Skip to content

Commit 3bf744f

Browse files
authored
[r3.5] execution/stagedsync: AuRa genesis bypass for parallel-exec emptyRemoval (#21931)
Cherry-pick of #21930 to release/3.5. Fixes #21712.
1 parent 6ece8fa commit 3bf744f

2 files changed

Lines changed: 83 additions & 1 deletion

File tree

execution/stagedsync/calc_state_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,3 +546,83 @@ func lookupKeyUpdate(t *testing.T, updates *commitment.Updates, plainKey string)
546546
require.NotNil(t, found, "no Update emitted for plainKey %x", plainKey)
547547
return found
548548
}
549+
550+
// TestNormalizeWriteSet_GenesisBypassRetainsEmptyAccount pins that emptyRemoval=false
551+
// retains an empty account as a full UPDATE rather than emitting SelfDestructPath.
552+
func TestNormalizeWriteSet_GenesisBypassRetainsEmptyAccount(t *testing.T) {
553+
zeroAddr := accounts.InternAddress([20]byte{})
554+
555+
ver := state.Version{TxIndex: 0, Incarnation: 0}
556+
rawWrites := state.VersionedWrites{
557+
&state.VersionedWrite{Address: zeroAddr, Path: state.BalancePath, Val: uint256.Int{}, Version: ver},
558+
&state.VersionedWrite{Address: zeroAddr, Path: state.NoncePath, Val: uint64(0), Version: ver},
559+
&state.VersionedWrite{Address: zeroAddr, Path: state.CodeHashPath, Val: accounts.EmptyCodeHash, Version: ver},
560+
}
561+
vm := state.NewVersionMap(nil)
562+
for _, w := range rawWrites {
563+
vm.Write(w.Address, w.Path, accounts.NilKey, ver, w.Val, true)
564+
}
565+
566+
normalized := normalizeWriteSet(rawWrites, vm, 0, 0, nil, nil, false)
567+
568+
for _, w := range normalized {
569+
assert.NotEqual(t, state.SelfDestructPath, w.Path,
570+
"emptyRemoval=false must suppress SelfDestructPath emission for empty accounts")
571+
}
572+
573+
cs := newTestCalcState()
574+
cs.ApplyWrites(normalized)
575+
acc, ok := cs.accounts[zeroAddr]
576+
require.True(t, ok)
577+
assert.False(t, acc.Deleted)
578+
579+
updates := newTestUpdates()
580+
cs.FlushToUpdates(updates)
581+
keyVal := zeroAddr.Value()
582+
got := lookupKeyUpdate(t, updates, string(keyVal[:]))
583+
assert.Equal(t,
584+
commitment.BalanceUpdate|commitment.NonceUpdate|commitment.CodeUpdate,
585+
got.Flags,
586+
"empty account at genesis must emit full UPDATE, matching serial's TrieContext.Account")
587+
}
588+
589+
// TestNormalizeWriteSet_PostGenesisEmptyAccountTriggersEIP161 pins that emptyRemoval=true
590+
// emits SelfDestructPath for an empty account and flushes as DeleteUpdate.
591+
func TestNormalizeWriteSet_PostGenesisEmptyAccountTriggersEIP161(t *testing.T) {
592+
addr := accounts.InternAddress([20]byte{0xab, 0xcd})
593+
594+
ver := state.Version{TxIndex: 0, Incarnation: 0}
595+
rawWrites := state.VersionedWrites{
596+
&state.VersionedWrite{Address: addr, Path: state.BalancePath, Val: uint256.Int{}, Version: ver},
597+
&state.VersionedWrite{Address: addr, Path: state.NoncePath, Val: uint64(0), Version: ver},
598+
&state.VersionedWrite{Address: addr, Path: state.CodeHashPath, Val: accounts.EmptyCodeHash, Version: ver},
599+
}
600+
vm := state.NewVersionMap(nil)
601+
for _, w := range rawWrites {
602+
vm.Write(w.Address, w.Path, accounts.NilKey, ver, w.Val, true)
603+
}
604+
605+
normalized := normalizeWriteSet(rawWrites, vm, 0, 0, nil, nil, true)
606+
607+
sdSeen := false
608+
for _, w := range normalized {
609+
if w.Path == state.SelfDestructPath && w.Address == addr {
610+
v, _ := w.Val.(bool)
611+
sdSeen = sdSeen || v
612+
}
613+
}
614+
require.True(t, sdSeen, "emptyRemoval=true must emit SelfDestructPath=true for empty account")
615+
616+
cs := newTestCalcState()
617+
cs.ApplyWrites(normalized)
618+
acc, ok := cs.accounts[addr]
619+
require.True(t, ok)
620+
assert.True(t, acc.Deleted)
621+
622+
updates := newTestUpdates()
623+
cs.FlushToUpdates(updates)
624+
keyVal := addr.Value()
625+
got := lookupKeyUpdate(t, updates, string(keyVal[:]))
626+
assert.Equal(t, commitment.DeleteUpdate, got.Flags,
627+
"empty account with emptyRemoval=true must emit DeleteUpdate (EIP-161)")
628+
}

execution/stagedsync/exec3_parallel.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2597,7 +2597,9 @@ func (be *blockExecutor) nextResult(ctx context.Context, pe *parallelExecutor, r
25972597
}
25982598
return keys
25992599
}
2600-
txResult.writes = normalizeWriteSet(rawWrites, be.versionMap, txVersion.TxIndex, resultIncarnation, stateReader, domainStorageKeys, pe.cfg.chainConfig.IsSpuriousDragon(be.blockNum))
2600+
// Mirror txtask.go's genesis rules-clobber so empty allocs (AuRa ZeroAddress) survive.
2601+
emptyRemoval := be.blockNum != 0 && pe.cfg.chainConfig.IsSpuriousDragon(be.blockNum)
2602+
txResult.writes = normalizeWriteSet(rawWrites, be.versionMap, txVersion.TxIndex, resultIncarnation, stateReader, domainStorageKeys, emptyRemoval)
26012603
}
26022604

26032605
// Snapshot the finalized result before pushing — prevents

0 commit comments

Comments
 (0)