go-ethereum/eth/protocols/snap/syncer.go
Jonny Rhea 17aab1ac9a
Some checks are pending
/ Linux Build (push) Waiting to run
/ Linux Build (arm) (push) Waiting to run
/ Keeper Build (push) Waiting to run
/ Windows Build (push) Waiting to run
/ Docker Image (push) Waiting to run
core, eth/protocols/snap, eth/downloader: snap/2 sync logic (#34626)
Adds snap/2 (EIP-8189), a block-access-list (BAL) based state sync, and
wires it to run side by side with snap/1. It's opt-in (for now) behind a
new --snap.v2 flag and chosen at startup.

https://eips.ethereum.org/EIPS/eip-8189

---------

Co-authored-by: Toni Wahrstätter <info@toniwahrstaetter.com>
Co-authored-by: Gary Rong <garyrong0905@gmail.com>
2026-06-11 14:45:07 +08:00

147 lines
5.9 KiB
Go

// Copyright 2026 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package snap
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
)
// Progress is the set of snap-syncer progress that eth/downloader surfaces in
// ethereum.SyncProgress. The two syncer versions report it via different types
// (syncProgress / syncProgressV2). The adapters normalize to this.
type Progress struct {
AccountSynced uint64
AccountBytes common.StorageSize
BytecodeSynced uint64
BytecodeBytes common.StorageSize
StorageSynced uint64
StorageBytes common.StorageSize
// Healing-phase status. Reported by snap/1 only.
TrienodeHealSynced uint64
TrienodeHealBytes common.StorageSize
BytecodeHealSynced uint64
BytecodeHealBytes common.StorageSize
HealingTrienodes uint64
HealingBytecode uint64
}
// Syncer is the uniform view over the snap/1 (*syncer) and snap/2 (*syncerV2)
// state syncers, consumed by eth/downloader. Peers are passed as SyncPeerV2,
// which is a superset of SyncPeer, so a single peer value works for both
// underlying syncers.
type Syncer interface {
Sync(pivot *types.Header, cancel chan struct{}) error
Progress() Progress
Register(peer SyncPeerV2) error
Unregister(id string) error
OnAccounts(peer SyncPeerV2, id uint64, hashes []common.Hash, accounts [][]byte, proof [][]byte) error
OnStorage(peer SyncPeerV2, id uint64, hashes [][]common.Hash, slots [][][]byte, proof [][]byte) error
OnByteCodes(peer SyncPeerV2, id uint64, bytecodes [][]byte) error
OnTrieNodes(peer SyncPeerV2, id uint64, trienodes [][]byte) error
OnAccessLists(peer SyncPeerV2, id uint64, lists rlp.RawList[rlp.RawValue]) error
// Version is the snap protocol version this syncer implements.
Version() uint
}
// NewV1Syncer returns a Syncer backed by the snap/1 state syncer.
func NewV1Syncer(db ethdb.Database, scheme string) Syncer {
return syncerV1Adapter{newSyncer(db, scheme)}
}
// NewV2Syncer returns a Syncer backed by the snap/2 state syncer.
func NewV2Syncer(db ethdb.Database, scheme string) Syncer {
return syncerV2Adapter{newSyncerV2(db, scheme)}
}
// syncerV1Adapter adapts the snap/1 *syncer to Syncer.
type syncerV1Adapter struct{ *syncer }
func (s syncerV1Adapter) Sync(pivot *types.Header, cancel chan struct{}) error {
return s.syncer.Sync(pivot.Root, cancel)
}
func (s syncerV1Adapter) Progress() Progress {
progress, pending := s.syncer.Progress()
return Progress{
AccountSynced: progress.AccountSynced,
AccountBytes: progress.AccountBytes,
BytecodeSynced: progress.BytecodeSynced,
BytecodeBytes: progress.BytecodeBytes,
StorageSynced: progress.StorageSynced,
StorageBytes: progress.StorageBytes,
TrienodeHealSynced: progress.TrienodeHealSynced,
TrienodeHealBytes: progress.TrienodeHealBytes,
BytecodeHealSynced: progress.BytecodeHealSynced,
BytecodeHealBytes: progress.BytecodeHealBytes,
HealingTrienodes: pending.TrienodeHeal,
HealingBytecode: pending.BytecodeHeal,
}
}
// The snap/1 syncer's methods take SyncPeer. SyncPeerV2 is a superset, so the
// incoming peer satisfies them directly. Explicit forwarders are needed because
// the parameter types differ.
func (s syncerV1Adapter) Register(peer SyncPeerV2) error { return s.syncer.Register(peer) }
func (s syncerV1Adapter) OnAccounts(peer SyncPeerV2, id uint64, hashes []common.Hash, accounts [][]byte, proof [][]byte) error {
return s.syncer.OnAccounts(peer, id, hashes, accounts, proof)
}
func (s syncerV1Adapter) OnStorage(peer SyncPeerV2, id uint64, hashes [][]common.Hash, slots [][][]byte, proof [][]byte) error {
return s.syncer.OnStorage(peer, id, hashes, slots, proof)
}
func (s syncerV1Adapter) OnByteCodes(peer SyncPeerV2, id uint64, bytecodes [][]byte) error {
return s.syncer.OnByteCodes(peer, id, bytecodes)
}
func (s syncerV1Adapter) OnTrieNodes(peer SyncPeerV2, id uint64, trienodes [][]byte) error {
return s.syncer.OnTrieNodes(peer, id, trienodes)
}
// OnAccessLists is a no-op for snap/1, which never requests BALs.
func (syncerV1Adapter) OnAccessLists(SyncPeerV2, uint64, rlp.RawList[rlp.RawValue]) error {
return nil
}
// Version is SNAP1
func (syncerV1Adapter) Version() uint { return SNAP1 }
// syncerV2Adapter adapts the snap/2 *syncerV2 to Syncer. Its peer-facing methods
// already take SyncPeerV2 and its Sync already takes a header, so only Progress
// (different return type) and OnTrieNodes (absent) need wrapping.
type syncerV2Adapter struct{ *syncerV2 }
func (s syncerV2Adapter) Progress() Progress {
progress := s.syncerV2.Progress()
return Progress{
AccountSynced: progress.AccountSynced,
AccountBytes: progress.AccountBytes,
BytecodeSynced: progress.BytecodeSynced,
BytecodeBytes: progress.BytecodeBytes,
StorageSynced: progress.StorageSynced,
StorageBytes: progress.StorageBytes,
}
}
// OnTrieNodes is a no-op for snap/2, which heals via BALs rather than trie nodes.
// Stale responses from snap/1 peers are silently ignored.
func (syncerV2Adapter) OnTrieNodes(SyncPeerV2, uint64, [][]byte) error { return nil }
// Version is SNAP2; snap/2 needs SNAP2 peers to serve the BAL requests it issues.
func (syncerV2Adapter) Version() uint { return SNAP2 }