Skip to content

Commit e03b41e

Browse files
Merge pull request #2486 from skalenetwork/fix-mismatch
Fix mismatch in receipts
2 parents f6a3a4a + 0648bee commit e03b41e

3 files changed

Lines changed: 42 additions & 23 deletions

File tree

.github/workflows/test.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ jobs:
8585
sudo update-alternatives --install /usr/bin/gcov-tool gcov-tool /usr/bin/gcov-tool-11 11
8686
gcc --version
8787
88+
- name: Free disk space
89+
run: |
90+
sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc
91+
df -h
92+
8893
- name: Build dependencies
8994
run: |
9095
cd deps

libethereum/Block.cpp

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -999,8 +999,14 @@ u256 Block::enact( VerifiedBlockRef const& _block, BlockChain const& _bc ) {
999999
throw;
10001000
}
10011001

1002-
// EIP-2718: use typed receipt encoding for non-Legacy transactions.
1003-
if ( EIP1559TransactionsPatch::isEnabledInWorkingBlock() &&
1002+
// The EIP-1559
1003+
// transaction format is accepted before Berlin, but the typed-receipt
1004+
// encoding must only change at the coordinated Berlin fork so blocks
1005+
// produced before it keep their original receiptsRoot.
1006+
// The parent block timestamp is used (not the global committed-block
1007+
// timestamp) so the encoding is deterministic per block, including when
1008+
// a block is re-enacted out of order.
1009+
if ( BerlinForkPatch::isEnabledWhen( previousInfo().timestamp() ) &&
10041010
m_receipts.back().txType() > 0 ) {
10051011
receipts.push_back( m_receipts.back().typedRlp() );
10061012
} else {
@@ -1420,10 +1426,15 @@ void Block::commitToSeal(
14201426
RLPStream k;
14211427
k << i;
14221428

1423-
// Since EIP-1559 API is enabled before Berlin fork,
1424-
// this part of EIP-2718 logic is activated depending on EIP1559TransactionsPatch
1429+
// EIP-2718 typed-receipt encoding is gated on BerlinForkPatch:
1430+
// the EIP-1559 transaction format is accepted
1431+
// before Berlin, but the receipt encoding must only change at the
1432+
// coordinated Berlin fork so pre-Berlin blocks keep their receiptsRoot.
1433+
// The parent block timestamp is used (not the global committed-block
1434+
// timestamp) so the encoding is deterministic per block and matches enact().
14251435
bytes receiptBytes;
1426-
if ( EIP1559TransactionsPatch::isEnabledInWorkingBlock() && receipt( i ).txType() > 0 ) {
1436+
if ( BerlinForkPatch::isEnabledWhen( previousInfo().timestamp() ) &&
1437+
receipt( i ).txType() > 0 ) {
14271438
receiptBytes = receipt( i ).typedRlp();
14281439
} else {
14291440
RLPStream receiptrlp;
@@ -1433,9 +1444,11 @@ void Block::commitToSeal(
14331444
receiptsMap.insert( std::make_pair( k.out(), receiptBytes ) );
14341445

14351446
dev::bytes txOutput = m_transactions[i].toBytes();
1436-
// Same as receiptBytes creation:
1437-
// this part of EIP-2718 logic is activated depending on EIP1559TransactionsPatch
1438-
if ( EIP1559TransactionsPatch::isEnabledInWorkingBlock() &&
1447+
// EIP-2718: typed transactions go into the transactions trie wrapped as an
1448+
// RLP byte string. Unlike the receipt encoding above, this is gated on
1449+
// EIP1559TransactionsPatch because typed transactions are accepted
1450+
// before Berlin.
1451+
if ( EIP1559TransactionsPatch::isEnabledWhen( previousInfo().timestamp() ) &&
14391452
m_transactions[i].txType() != dev::eth::TransactionType::Legacy ) {
14401453
RLPStream s;
14411454
s.append( txOutput );

test/api-tests/hardfork-compat/test_hardfork_compat.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
- a factory whose constructor runs CREATE and CREATE2
1212
3. Launch the 5.2.0 sync node (syncNode=true, archiveMode=true)
1313
4. Wait for the sync node to catch up to the primary head
14-
5. Compare the per-block stateRoot of every block (the primary assertion)
15-
6. Compare per-block hashes as a diagnostic cross-check
14+
5. Compare the per-block stateRoot of every block
15+
6. Compare per-block hashes (covers receiptsRoot/transactionsRoot)
16+
Both comparisons are hard assertions: any mismatch fails the test.
1617
1718
Tests run in file order (sequential): the workload must complete before the
1819
sync node is launched and the comparison runs.
@@ -280,20 +281,20 @@ def test_sync_catchup_and_state_root_comparison(
280281
compare_bn = min(w3_primary.eth.block_number, w3_sync.eth.block_number)
281282
logger.info("Comparing stateRoot for blocks 0..%d (5.1.0 vs 5.2.0)", compare_bn)
282283

284+
# Run both comparisons before asserting so a failure reports the full
285+
# picture (stateRoot and hash mismatches) in one go. The block hash
286+
# embeds receiptsRoot/transactionsRoot, so it must fail the test just
287+
# like a stateRoot mismatch -- not be logged as a diagnostic.
283288
root_mismatches = compare_state_roots(w3_primary, w3_sync, compare_bn)
284-
assert len(root_mismatches) == 0, (
285-
f"stateRoot mismatches between 5.1.0 and 5.2.0 at blocks: {root_mismatches}"
286-
)
287-
logger.info("All %d block stateRoots match between 5.1.0 and 5.2.0", compare_bn + 1)
288-
289289
hash_mismatches = compare_block_hashes(w3_primary, w3_sync, compare_bn)
290-
if hash_mismatches:
291-
logger.warning(
292-
"Block hash mismatches between 5.1.0 and 5.2.0 at blocks %s; "
293-
"stateRoot matched, so this is diagnostic only",
294-
hash_mismatches,
295-
)
296-
else:
297-
logger.info("All %d block hashes match between 5.1.0 and 5.2.0", compare_bn + 1)
290+
291+
assert not root_mismatches and not hash_mismatches, (
292+
f"5.1.0 vs 5.2.0 divergence: stateRoot mismatches at blocks "
293+
f"{root_mismatches}, block hash mismatches at blocks {hash_mismatches}"
294+
)
295+
logger.info(
296+
"All %d block stateRoots and hashes match between 5.1.0 and 5.2.0",
297+
compare_bn + 1,
298+
)
298299
finally:
299300
_stop_node(proc, log_fd, "SYNC(5.2.0)")

0 commit comments

Comments
 (0)