Skip to content

Commit c6654c3

Browse files
authored
feat(sae): Store last accepted hash (#5544)
1 parent d8a8473 commit c6654c3

9 files changed

Lines changed: 28 additions & 14 deletions

File tree

graft/coreth/core/blockchain.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,7 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) {
843843
// Add the block to the canonical chain number scheme and mark as the head
844844
batch := bc.db.NewBatch()
845845
rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64())
846-
846+
rawdb.WriteHeadFastBlockHash(batch, block.Hash())
847847
rawdb.WriteHeadBlockHash(batch, block.Hash())
848848
rawdb.WriteHeadHeaderHash(batch, block.Hash())
849849

@@ -2192,6 +2192,7 @@ func (bc *BlockChain) ResetToStateSyncedBlock(block *types.Block) error {
21922192
}
21932193
rawdb.WriteHeadBlockHash(batch, block.Hash())
21942194
rawdb.WriteHeadHeaderHash(batch, block.Hash())
2195+
rawdb.WriteHeadFastBlockHash(batch, block.Hash())
21952196
customrawdb.WriteSnapshotBlockHash(batch, block.Hash())
21962197
rawdb.WriteSnapshotRoot(batch, block.Root())
21972198
if err := customrawdb.WriteSyncPerformed(batch, block.NumberU64()); err != nil {

graft/coreth/core/genesis.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
399399
rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64())
400400
rawdb.WriteHeadBlockHash(batch, block.Hash())
401401
rawdb.WriteHeadHeaderHash(batch, block.Hash())
402+
rawdb.WriteHeadFastBlockHash(batch, block.Hash())
402403
rawdb.WriteFinalizedBlockHash(batch, block.Hash())
403404
rawdb.WriteChainConfig(batch, block.Hash(), config)
404405
if err := batch.Write(); err != nil {

graft/subnet-evm/core/blockchain.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,7 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) {
860860
// Add the block to the canonical chain number scheme and mark as the head
861861
batch := bc.db.NewBatch()
862862
rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64())
863-
863+
rawdb.WriteHeadBlockHash(batch, block.Hash())
864864
rawdb.WriteHeadBlockHash(batch, block.Hash())
865865
rawdb.WriteHeadHeaderHash(batch, block.Hash())
866866

@@ -2231,6 +2231,7 @@ func (bc *BlockChain) ResetToStateSyncedBlock(block *types.Block) error {
22312231
}
22322232
rawdb.WriteHeadBlockHash(batch, block.Hash())
22332233
rawdb.WriteHeadHeaderHash(batch, block.Hash())
2234+
rawdb.WriteHeadFastBlockHash(batch, block.Hash())
22342235
customrawdb.WriteSnapshotBlockHash(batch, block.Hash())
22352236
rawdb.WriteSnapshotRoot(batch, block.Root())
22362237
if err := customrawdb.WriteSyncPerformed(batch, block.NumberU64()); err != nil {

graft/subnet-evm/core/genesis.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
428428
rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64())
429429
rawdb.WriteHeadBlockHash(batch, block.Hash())
430430
rawdb.WriteHeadHeaderHash(batch, block.Hash())
431+
rawdb.WriteHeadFastBlockHash(batch, block.Hash())
431432
rawdb.WriteFinalizedBlockHash(batch, block.Hash())
432433
customrawdb.WriteChainConfig(batch, block.Hash(), config, params.GetExtra(config).UpgradeConfig)
433434
if err := batch.Write(); err != nil {

vms/saevm/cchain/genesis.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ func writeGenesisBlock(db ethdb.Database, block *types.Block, config *ethparams.
240240
rawdb.WriteFinalizedBlockHash(b, hash)
241241
rawdb.WriteHeadBlockHash(b, hash)
242242
rawdb.WriteHeadHeaderHash(b, hash)
243+
rawdb.WriteHeadFastBlockHash(b, hash)
243244
rawdb.WriteChainConfig(b, hash, config)
244245
return b.Write()
245246
}

vms/saevm/docs/invariants.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ While it also has a notion of a "safe" block (with reduced probability of re-org
3131

3232
#### Mapping
3333

34-
| SAE | `rawdb` |
35-
| -------- | --------- |
36-
| Accepted | Canonical |
37-
| Executed | Head |
38-
| Settled | Finalized |
34+
| SAE | `rawdb` |
35+
| -------- | ------------------- |
36+
| Accepted | Canonical, HeadFast |
37+
| Executed | Head |
38+
| Settled | Finalized |
3939

4040
#### Rationale
4141

42-
* Accepted and canonical are effectively identical concepts, save for nuanced differences between the consensus mechanisms.
42+
* Accepted and canonical are effectively identical concepts, save for nuanced differences between the consensus mechanisms. `libevm`'s `HeadFast` denotes a recorded block whose state has not yet been executed; this aligns with SAE's definition of Accepted and is convenient for indexing the last-accepted block.
4343

4444
* From an API perspective, we treat "latest" (i.e. the chain head) as the last-executed block.
4545
Mirroring this on disk allows for simple integration with the upstream API implementations.

vms/saevm/sae/consensus.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func (vm *VM) AcceptBlock(ctx context.Context, b *blocks.Block) error {
5959
rawdb.WriteTxLookupEntriesByBlock(batch, b.EthBlock())
6060
// D(b ∈ A)
6161
rawdb.WriteCanonicalHash(batch, b.Hash(), b.NumberU64())
62+
rawdb.WriteHeadFastBlockHash(batch, b.Hash())
6263

6364
if err := batch.Write(); err != nil {
6465
return err

vms/saevm/sae/recovery.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"errors"
99
"fmt"
1010
"iter"
11-
"math"
1211
"sync/atomic"
1312

1413
"github.com/ava-labs/libevm/common"
@@ -96,15 +95,20 @@ func (rec *recovery) lastCommittedBlock() (_ *blocks.Block, retErr error) {
9695
}
9796

9897
func (rec *recovery) canonicalAfter(parent *blocks.Block) iter.Seq2[*blocks.Block, error] {
99-
nums, _ := rawdb.ReadAllCanonicalHashes(rec.db, parent.NumberU64()+1, math.MaxUint64, math.MaxInt)
100-
10198
return func(yield func(*blocks.Block, error) bool) {
102-
for _, num := range nums {
103-
b, err := rec.newCanonicalBlock(num, parent)
99+
lastAcceptedHash := rawdb.ReadHeadFastBlockHash(rec.db)
100+
if lastAcceptedHash == (common.Hash{}) {
101+
// SAE writes this hash on [VM.AcceptBlock], so the set of accepted,
102+
// asynchronous blocks MUST be empty.
103+
return
104+
}
105+
106+
for curr := parent; curr.Hash() != lastAcceptedHash; {
107+
b, err := rec.newCanonicalBlock(curr.Height()+1, curr)
104108
if !yield(b, err) || err != nil {
105109
return
106110
}
107-
parent = b
111+
curr = b
108112
}
109113
}
110114
}

vms/saevm/sae/recovery_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ func TestRecoverSimple(t *testing.T) {
137137
numBlocks int
138138
archival bool
139139
}{
140+
{
141+
name: "genesis",
142+
numBlocks: 0,
143+
},
140144
{
141145
name: "archival",
142146
numBlocks: 10,

0 commit comments

Comments
 (0)