-
Notifications
You must be signed in to change notification settings - Fork 242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Domain block production for domains v2 #1567
Changes from all commits
52c49b3
c6535e4
9a09c21
2f3c921
ff5023b
0929f44
33f7b7c
36fc466
1c835c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,8 +25,32 @@ const BAD_RECEIPT_MISMATCH_INFO: &[u8] = b"bad_receipt_mismatch_info"; | |
const BAD_RECEIPT_NUMBERS: &[u8] = b"bad_receipt_numbers"; | ||
|
||
/// domain_block_hash => primary_block_hash | ||
/// | ||
/// Updated only when there is a new domain block produced | ||
const PRIMARY_HASH: &[u8] = b"primary_hash"; | ||
|
||
/// domain_block_hash => latest_primary_block_hash | ||
/// | ||
/// It's important to note that a primary block could possibly contain no bundles for a specific domain, | ||
/// leading to the situation where multiple primary blocks could correspond to the same domain block. | ||
/// | ||
/// PrimaryBlock10 --> DomainBlock5 | ||
/// PrimaryBlock11 --> DomainBlock5 | ||
/// PrimaryBlock12 --> DomainBlock5 | ||
/// | ||
/// This mapping is designed to track the most recent primary block that derives the domain block | ||
/// identified by `domain_block_hash`, e.g., Hash(DomainBlock5) => Hash(PrimaryBlock12). | ||
const LATEST_PRIMARY_HASH: &[u8] = b"latest_primary_hash"; | ||
|
||
/// primary_block_hash => best_domain_block_hash | ||
/// | ||
/// This mapping tracks the mapping of a primary block and the corresponding domain block derived | ||
/// until this primary block: | ||
/// - Hash(PrimaryBlock10) => Hash(DomainBlock5) | ||
/// - Hash(PrimaryBlock11) => Hash(DomainBlock5) | ||
/// - Hash(PrimaryBlock12) => Hash(DomainBlock5) | ||
const BEST_DOMAIN_HASH: &[u8] = b"best_domain_hash"; | ||
|
||
/// Prune the execution receipts when they reach this number. | ||
const PRUNING_DEPTH: BlockNumber = 1000; | ||
|
||
|
@@ -66,6 +90,7 @@ where | |
{ | ||
let block_number = execution_receipt.primary_number; | ||
let primary_hash = execution_receipt.primary_hash; | ||
let domain_hash = execution_receipt.domain_hash; | ||
|
||
let block_number_key = (EXECUTION_RECEIPT_BLOCK_NUMBER, block_number).encode(); | ||
let mut hashes_at_block_number = | ||
|
@@ -109,6 +134,11 @@ where | |
execution_receipt_key(primary_hash).as_slice(), | ||
execution_receipt.encode().as_slice(), | ||
), | ||
// TODO: prune the stale mappings. | ||
( | ||
(PRIMARY_HASH, domain_hash).encode().as_slice(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need this storage? Primary hash should be part of the domain block and can be fetch from the runtime no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is mainly for
Is it? do you mean the ER in the consensus chain runtime? |
||
primary_hash.encode().as_slice(), | ||
), | ||
( | ||
block_number_key.as_slice(), | ||
hashes_at_block_number.encode().as_slice(), | ||
|
@@ -125,6 +155,26 @@ where | |
) | ||
} | ||
|
||
/// Load the execution receipt for given domain block hash. | ||
pub(super) fn load_execution_receipt_by_domain_hash<Backend, Hash, Number, PHash>( | ||
backend: &Backend, | ||
domain_hash: Hash, | ||
) -> ClientResult<Option<ExecutionReceipt<Number, PHash, Hash>>> | ||
where | ||
Backend: AuxStore, | ||
Hash: Encode + Decode, | ||
Number: Decode, | ||
PHash: Encode + Decode, | ||
{ | ||
match primary_hash_for::<Backend, Hash, PHash>(backend, domain_hash)? { | ||
Some(primary_block_hash) => load_decode( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This redirection is unnecessary here if the domain_hash is mapped to ER |
||
backend, | ||
execution_receipt_key(primary_block_hash).as_slice(), | ||
), | ||
None => Ok(None), | ||
} | ||
} | ||
|
||
/// Load the execution receipt for given primary block hash. | ||
pub(super) fn load_execution_receipt<Backend, Hash, Number, PHash>( | ||
backend: &Backend, | ||
|
@@ -142,27 +192,65 @@ where | |
) | ||
} | ||
|
||
pub(super) fn track_domain_hash_to_primary_hash<Backend, Hash, PHash>( | ||
pub(super) fn track_domain_hash_and_primary_hash<Backend, Hash, PHash>( | ||
backend: &Backend, | ||
domain_hash: Hash, | ||
primary_hash: PHash, | ||
best_domain_hash: Hash, | ||
latest_primary_hash: PHash, | ||
) -> ClientResult<()> | ||
where | ||
Backend: AuxStore, | ||
Hash: Encode, | ||
Hash: Clone + Encode, | ||
PHash: Encode, | ||
{ | ||
// TODO: prune the stale mappings. | ||
|
||
backend.insert_aux( | ||
&[( | ||
(PRIMARY_HASH, domain_hash).encode().as_slice(), | ||
primary_hash.encode().as_slice(), | ||
)], | ||
&[ | ||
( | ||
(LATEST_PRIMARY_HASH, best_domain_hash.clone()) | ||
.encode() | ||
.as_slice(), | ||
latest_primary_hash.encode().as_slice(), | ||
), | ||
( | ||
(BEST_DOMAIN_HASH, latest_primary_hash).encode().as_slice(), | ||
best_domain_hash.encode().as_slice(), | ||
), | ||
], | ||
vec![], | ||
) | ||
} | ||
|
||
pub(super) fn best_domain_hash_for<Backend, Hash, PHash>( | ||
backend: &Backend, | ||
primary_hash: &PHash, | ||
) -> ClientResult<Option<Hash>> | ||
where | ||
Backend: AuxStore, | ||
Hash: Decode, | ||
PHash: Encode, | ||
{ | ||
load_decode( | ||
backend, | ||
(BEST_DOMAIN_HASH, primary_hash).encode().as_slice(), | ||
) | ||
} | ||
|
||
pub(super) fn latest_primary_hash_for<Backend, Hash, PHash>( | ||
backend: &Backend, | ||
domain_hash: &Hash, | ||
) -> ClientResult<Option<PHash>> | ||
where | ||
Backend: AuxStore, | ||
Hash: Encode, | ||
PHash: Decode, | ||
{ | ||
load_decode( | ||
backend, | ||
(LATEST_PRIMARY_HASH, domain_hash).encode().as_slice(), | ||
) | ||
} | ||
|
||
pub(super) fn primary_hash_for<Backend, Hash, PHash>( | ||
backend: &Backend, | ||
domain_hash: Hash, | ||
|
@@ -411,6 +499,7 @@ mod tests { | |
ExecutionReceipt { | ||
primary_number, | ||
primary_hash: H256::random(), | ||
domain_number: primary_number, | ||
domain_hash: H256::random(), | ||
trace: Default::default(), | ||
trace_root: Default::default(), | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to change. ER should be stored against domain block hash and processed primary block hash should map domain block hash.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use the domain block hash as the key before but there is some issue, PTAL #1254
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The advantage of using primary block hash as the key has seemingly been diminished by v2 as now each primary block hash is mapped to an optional ER as well, let's reassess these two options. @NingLin-P Perhaps you could make a brief doc for them on the use cases so that we don't have to look into the code? I can do it as well if you prefer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm willing to do that, but I think there is not really a trade-off we need to make, using
domain_hash
will just bring back the issue #1254 because:When processing the consensus block, the operator checks the ER contains inside is the same as the one it produces locally, if not then use the local ER to construct and submit a fraud proof.
When using
domain_hash
as key we are unable to find and load the local ER if the incoming ER is different from the local one because theincoming_ER.domain_hash
is also different, thusload_local_ER(incoming_ER.domain_hash)
will always result inNone
then we are unable to construct the fraud proof properly.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same problem is back, but there might be another solution given the context has been changed a lot, I'm not entirely sure, hence want to make it assessed again under the v2 design.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have revisited the v2 fraud proof, which only mentioned the operator should "detecting any discrepancies" but didn't give more detail.
But IMO, the requirement is still the same under v2 design, namely get the local ER that driving from the same consensus block as the incoming ER thus seems inevitable to use the consensus block hash as the key for ER.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant to have a brief intro for the scenarios here so that we can come to a conclusion naturally and even help the readers who are not familiar with the context.
So, the problem here is how to track the receipt on the operator's side so that it can be retrieved later.
Use cases
Retrieve the receipt for bundle production
Retrieve the receipt of a specific domain block in order to compare the local trace and the other trace for fraud proof.
domain_block_hash
in the v2 ExecutionReceipt structure.Actually, even if we include
domain_block_hash
in the receipt, it’s unusable in case the bad receipt, because it’s never verified and any trace mismatch will cause a different domain block hash since the state must be different,bad_receipt.domain_block_hash
never exists on the honest operator’s end.Options
domain_block_hash
as the key (domain_block_hash ⇒ ER)consensus_block_hash
as the key (consensus_block_hash ⇒ ER)To conclude, the receipt needs to be keyed by
consensus_block_hash
.