Merge branch 'ethereum:master' into patch/typo

This commit is contained in:
Zoro 2024-06-13 21:17:52 +08:00 committed by GitHub
commit 8fd6d5bf7e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
45 changed files with 560 additions and 424 deletions

View file

@ -16,6 +16,7 @@ jobs:
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: 1.21.4 go-version: 1.21.4
cache: false
- name: Run tests - name: Run tests
run: go test -short ./... run: go test -short ./...
env: env:

View file

@ -23,6 +23,7 @@ linters:
- durationcheck - durationcheck
- exportloopref - exportloopref
- whitespace - whitespace
- revive # only certain checks enabled
### linters we tried and will not be using: ### linters we tried and will not be using:
### ###
@ -38,6 +39,15 @@ linters:
linters-settings: linters-settings:
gofmt: gofmt:
simplify: true simplify: true
revive:
enable-all-rules: false
# here we enable specific useful rules
# see https://golangci-lint.run/usage/linters/#revive for supported rules
rules:
- name: receiver-naming
severity: warning
disabled: false
exclude: [""]
issues: issues:
exclude-files: exclude-files:
@ -47,6 +57,9 @@ issues:
linters: linters:
- deadcode - deadcode
- staticcheck - staticcheck
- path: crypto/bn256/
linters:
- revive
- path: internal/build/pgp.go - path: internal/build/pgp.go
text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
- path: core/vm/contracts.go - path: core/vm/contracts.go

View file

@ -64,6 +64,9 @@ type Type struct {
var ( var (
// typeRegex parses the abi sub types // typeRegex parses the abi sub types
typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?") typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
// sliceSizeRegex grab the slice size
sliceSizeRegex = regexp.MustCompile("[0-9]+")
) )
// NewType creates a new reflection type of abi type given in t. // NewType creates a new reflection type of abi type given in t.
@ -91,8 +94,7 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
// grab the last cell and create a type from there // grab the last cell and create a type from there
sliced := t[i:] sliced := t[i:]
// grab the slice size with regexp // grab the slice size with regexp
re := regexp.MustCompile("[0-9]+") intz := sliceSizeRegex.FindAllString(sliced, -1)
intz := re.FindAllString(sliced, -1)
if len(intz) == 0 { if len(intz) == 0 {
// is a slice // is a slice

View file

@ -73,6 +73,14 @@ var (
DerivationSignatureHash = sha256.Sum256(common.Hash{}.Bytes()) DerivationSignatureHash = sha256.Sum256(common.Hash{}.Bytes())
) )
var (
// PinRegexp is the regular expression used to validate PIN codes.
pinRegexp = regexp.MustCompile(`^[0-9]{6,}$`)
// PukRegexp is the regular expression used to validate PUK codes.
pukRegexp = regexp.MustCompile(`^[0-9]{12,}$`)
)
// List of APDU command-related constants // List of APDU command-related constants
const ( const (
claISO7816 = 0 claISO7816 = 0
@ -380,7 +388,7 @@ func (w *Wallet) Open(passphrase string) error {
case passphrase == "": case passphrase == "":
return ErrPINUnblockNeeded return ErrPINUnblockNeeded
case status.PinRetryCount > 0: case status.PinRetryCount > 0:
if !regexp.MustCompile(`^[0-9]{6,}$`).MatchString(passphrase) { if !pinRegexp.MatchString(passphrase) {
w.log.Error("PIN needs to be at least 6 digits") w.log.Error("PIN needs to be at least 6 digits")
return ErrPINNeeded return ErrPINNeeded
} }
@ -388,7 +396,7 @@ func (w *Wallet) Open(passphrase string) error {
return err return err
} }
default: default:
if !regexp.MustCompile(`^[0-9]{12,}$`).MatchString(passphrase) { if !pukRegexp.MatchString(passphrase) {
w.log.Error("PUK needs to be at least 12 digits") w.log.Error("PUK needs to be at least 12 digits")
return ErrPINUnblockNeeded return ErrPINUnblockNeeded
} }

View file

@ -494,9 +494,6 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
for { for {
select { select {
case <-ctx.Done():
stream.Close()
case event, ok := <-stream.Events: case event, ok := <-stream.Events:
if !ok { if !ok {
log.Trace("Event stream closed") log.Trace("Event stream closed")

View file

@ -186,10 +186,14 @@ func (s *serverWithTimeout) eventCallback(event Event) {
// call will just do nothing // call will just do nothing
timer.Stop() timer.Stop()
delete(s.timeouts, id) delete(s.timeouts, id)
s.childEventCb(event) if s.childEventCb != nil {
s.childEventCb(event)
}
} }
default: default:
s.childEventCb(event) if s.childEventCb != nil {
s.childEventCb(event)
}
} }
} }
@ -211,25 +215,27 @@ func (s *serverWithTimeout) startTimeout(reqData RequestResponse) {
delete(s.timeouts, id) delete(s.timeouts, id)
childEventCb := s.childEventCb childEventCb := s.childEventCb
s.lock.Unlock() s.lock.Unlock()
childEventCb(Event{Type: EvFail, Data: reqData}) if childEventCb != nil {
childEventCb(Event{Type: EvFail, Data: reqData})
}
}) })
childEventCb := s.childEventCb childEventCb := s.childEventCb
s.lock.Unlock() s.lock.Unlock()
childEventCb(Event{Type: EvTimeout, Data: reqData}) if childEventCb != nil {
childEventCb(Event{Type: EvTimeout, Data: reqData})
}
}) })
} }
// unsubscribe stops all goroutines associated with the server. // unsubscribe stops all goroutines associated with the server.
func (s *serverWithTimeout) unsubscribe() { func (s *serverWithTimeout) unsubscribe() {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock()
for _, timer := range s.timeouts { for _, timer := range s.timeouts {
if timer != nil { if timer != nil {
timer.Stop() timer.Stop()
} }
} }
s.childEventCb = nil s.lock.Unlock()
s.parent.Unsubscribe() s.parent.Unsubscribe()
} }
@ -328,10 +334,10 @@ func (s *serverWithLimits) eventCallback(event Event) {
} }
childEventCb := s.childEventCb childEventCb := s.childEventCb
s.lock.Unlock() s.lock.Unlock()
if passEvent { if passEvent && childEventCb != nil {
childEventCb(event) childEventCb(event)
} }
if sendCanRequestAgain { if sendCanRequestAgain && childEventCb != nil {
childEventCb(Event{Type: EvCanRequestAgain}) childEventCb(Event{Type: EvCanRequestAgain})
} }
} }
@ -347,13 +353,12 @@ func (s *serverWithLimits) sendRequest(request Request) (reqId ID) {
// unsubscribe stops all goroutines associated with the server. // unsubscribe stops all goroutines associated with the server.
func (s *serverWithLimits) unsubscribe() { func (s *serverWithLimits) unsubscribe() {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock()
if s.delayTimer != nil { if s.delayTimer != nil {
s.delayTimer.Stop() s.delayTimer.Stop()
s.delayTimer = nil s.delayTimer = nil
} }
s.childEventCb = nil s.childEventCb = nil
s.lock.Unlock()
s.serverWithTimeout.unsubscribe() s.serverWithTimeout.unsubscribe()
} }
@ -383,7 +388,7 @@ func (s *serverWithLimits) canRequestNow() bool {
} }
childEventCb := s.childEventCb childEventCb := s.childEventCb
s.lock.Unlock() s.lock.Unlock()
if sendCanRequestAgain { if sendCanRequestAgain && childEventCb != nil {
childEventCb(Event{Type: EvCanRequestAgain}) childEventCb(Event{Type: EvCanRequestAgain})
} }
return canRequest return canRequest
@ -415,7 +420,7 @@ func (s *serverWithLimits) delay(delay time.Duration) {
} }
childEventCb := s.childEventCb childEventCb := s.childEventCb
s.lock.Unlock() s.lock.Unlock()
if sendCanRequestAgain { if sendCanRequestAgain && childEventCb != nil {
childEventCb(Event{Type: EvCanRequestAgain}) childEventCb(Event{Type: EvCanRequestAgain})
} }
}) })

View file

@ -51,6 +51,7 @@ func TestServerEvents(t *testing.T) {
expEvent(EvFail) expEvent(EvFail)
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}}) rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}})
expEvent(nil) expEvent(nil)
srv.unsubscribe()
} }
func TestServerParallel(t *testing.T) { func TestServerParallel(t *testing.T) {
@ -129,9 +130,7 @@ func TestServerEventRateLimit(t *testing.T) {
srv := NewServer(rs, clock) srv := NewServer(rs, clock)
var eventCount int var eventCount int
srv.subscribe(func(event Event) { srv.subscribe(func(event Event) {
if !event.IsRequestEvent() { eventCount++
eventCount++
}
}) })
expEvents := func(send, expAllowed int) { expEvents := func(send, expAllowed int) {
eventCount = 0 eventCount = 0
@ -147,6 +146,30 @@ func TestServerEventRateLimit(t *testing.T) {
expEvents(5, 1) expEvents(5, 1)
clock.Run(maxServerEventRate * maxServerEventBuffer * 2) clock.Run(maxServerEventRate * maxServerEventBuffer * 2)
expEvents(maxServerEventBuffer+5, maxServerEventBuffer) expEvents(maxServerEventBuffer+5, maxServerEventBuffer)
srv.unsubscribe()
}
func TestServerUnsubscribe(t *testing.T) {
rs := &testRequestServer{}
clock := &mclock.Simulated{}
srv := NewServer(rs, clock)
var eventCount int
srv.subscribe(func(event Event) {
eventCount++
})
eventCb := rs.eventCb
eventCb(Event{Type: testEventType})
if eventCount != 1 {
t.Errorf("Server event callback not called before unsubscribe")
}
srv.unsubscribe()
if rs.eventCb != nil {
t.Errorf("Server event callback not removed after unsubscribe")
}
eventCb(Event{Type: testEventType})
if eventCount != 1 {
t.Errorf("Server event callback called after unsubscribe")
}
} }
type testRequestServer struct { type testRequestServer struct {
@ -156,4 +179,4 @@ type testRequestServer struct {
func (rs *testRequestServer) Name() string { return "" } func (rs *testRequestServer) Name() string { return "" }
func (rs *testRequestServer) Subscribe(eventCb func(Event)) { rs.eventCb = eventCb } func (rs *testRequestServer) Subscribe(eventCb func(Event)) { rs.eventCb = eventCb }
func (rs *testRequestServer) SendRequest(ID, Request) {} func (rs *testRequestServer) SendRequest(ID, Request) {}
func (rs *testRequestServer) Unsubscribe() {} func (rs *testRequestServer) Unsubscribe() { rs.eventCb = nil }

View file

@ -173,24 +173,24 @@ type TestCommitteeChain struct {
init bool init bool
} }
func (t *TestCommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error { func (tc *TestCommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error {
t.fsp, t.nsp, t.init = bootstrap.Header.SyncPeriod(), bootstrap.Header.SyncPeriod()+2, true tc.fsp, tc.nsp, tc.init = bootstrap.Header.SyncPeriod(), bootstrap.Header.SyncPeriod()+2, true
return nil return nil
} }
func (t *TestCommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error { func (tc *TestCommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error {
period := update.AttestedHeader.Header.SyncPeriod() period := update.AttestedHeader.Header.SyncPeriod()
if period < t.fsp || period > t.nsp || !t.init { if period < tc.fsp || period > tc.nsp || !tc.init {
return light.ErrInvalidPeriod return light.ErrInvalidPeriod
} }
if period == t.nsp { if period == tc.nsp {
t.nsp++ tc.nsp++
} }
return nil return nil
} }
func (t *TestCommitteeChain) NextSyncPeriod() (uint64, bool) { func (tc *TestCommitteeChain) NextSyncPeriod() (uint64, bool) {
return t.nsp, t.init return tc.nsp, tc.init
} }
func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) { func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) {
@ -199,8 +199,8 @@ func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) {
} }
} }
func (t *TestCommitteeChain) SetNextSyncPeriod(nsp uint64) { func (tc *TestCommitteeChain) SetNextSyncPeriod(nsp uint64) {
t.init, t.nsp = true, nsp tc.init, tc.nsp = true, nsp
} }
func (tc *TestCommitteeChain) ExpNextSyncPeriod(t *testing.T, expNsp uint64) { func (tc *TestCommitteeChain) ExpNextSyncPeriod(t *testing.T, expNsp uint64) {

View file

@ -109,7 +109,7 @@ func rlpxPing(ctx *cli.Context) error {
} }
return fmt.Errorf("received disconnect message: %v", msg[0]) return fmt.Errorf("received disconnect message: %v", msg[0])
default: default:
return fmt.Errorf("invalid message code %d, expected handshake (code zero)", code) return fmt.Errorf("invalid message code %d, expected handshake (code zero) or disconnect (code one)", code)
} }
return nil return nil
} }

View file

@ -156,6 +156,7 @@ var (
utils.BeaconGenesisRootFlag, utils.BeaconGenesisRootFlag,
utils.BeaconGenesisTimeFlag, utils.BeaconGenesisTimeFlag,
utils.BeaconCheckpointFlag, utils.BeaconCheckpointFlag,
utils.CollectWitnessFlag,
}, utils.NetworkFlags, utils.DatabaseFlags) }, utils.NetworkFlags, utils.DatabaseFlags)
rpcFlags = []cli.Flag{ rpcFlags = []cli.Flag{

View file

@ -604,6 +604,11 @@ var (
Usage: "Disables db compaction after import", Usage: "Disables db compaction after import",
Category: flags.LoggingCategory, Category: flags.LoggingCategory,
} }
CollectWitnessFlag = &cli.BoolFlag{
Name: "collectwitness",
Usage: "Enable state witness generation during block execution. Work in progress flag, don't use.",
Category: flags.MiscCategory,
}
// MISC settings // MISC settings
SyncTargetFlag = &cli.StringFlag{ SyncTargetFlag = &cli.StringFlag{
@ -1760,6 +1765,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
// TODO(fjl): force-enable this in --dev mode // TODO(fjl): force-enable this in --dev mode
cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name) cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name)
} }
if ctx.IsSet(CollectWitnessFlag.Name) {
cfg.EnableWitnessCollection = ctx.Bool(CollectWitnessFlag.Name)
}
if ctx.IsSet(RPCGlobalGasCapFlag.Name) { if ctx.IsSet(RPCGlobalGasCapFlag.Name) {
cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name) cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name)
@ -2190,7 +2198,10 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) { if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) {
cache.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100 cache.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100
} }
vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)} vmcfg := vm.Config{
EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name),
EnableWitnessCollection: ctx.Bool(CollectWitnessFlag.Name),
}
if ctx.IsSet(VMTraceFlag.Name) { if ctx.IsSet(VMTraceFlag.Name) {
if name := ctx.String(VMTraceFlag.Name); name != "" { if name := ctx.String(VMTraceFlag.Name); name != "" {
var config json.RawMessage var config json.RawMessage

View file

@ -1809,7 +1809,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// while processing transactions. Before Byzantium the prefetcher is mostly // while processing transactions. Before Byzantium the prefetcher is mostly
// useless due to the intermediate root hashing after each transaction. // useless due to the intermediate root hashing after each transaction.
if bc.chainConfig.IsByzantium(block.Number()) { if bc.chainConfig.IsByzantium(block.Number()) {
statedb.StartPrefetcher("chain") statedb.StartPrefetcher("chain", !bc.vmConfig.EnableWitnessCollection)
} }
activeState = statedb activeState = statedb

View file

@ -60,11 +60,11 @@ func newAccessList() *accessList {
} }
// Copy creates an independent copy of an accessList. // Copy creates an independent copy of an accessList.
func (a *accessList) Copy() *accessList { func (al *accessList) Copy() *accessList {
cp := newAccessList() cp := newAccessList()
cp.addresses = maps.Clone(a.addresses) cp.addresses = maps.Clone(al.addresses)
cp.slots = make([]map[common.Hash]struct{}, len(a.slots)) cp.slots = make([]map[common.Hash]struct{}, len(al.slots))
for i, slotMap := range a.slots { for i, slotMap := range al.slots {
cp.slots[i] = maps.Clone(slotMap) cp.slots[i] = maps.Clone(slotMap)
} }
return cp return cp

View file

@ -123,7 +123,7 @@ type Trie interface {
// The returned nodeset can be nil if the trie is clean(nothing to commit). // The returned nodeset can be nil if the trie is clean(nothing to commit).
// Once the trie is committed, it's not usable anymore. A new trie must // Once the trie is committed, it's not usable anymore. A new trie must
// be created with new root and updated trie database for following usage // be created with new root and updated trie database for following usage
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet)
// NodeIterator returns an iterator that returns nodes of the trie. Iteration // NodeIterator returns an iterator that returns nodes of the trie. Iteration
// starts at the key after the given start key. And error will be returned // starts at the key after the given start key. And error will be returned

View file

@ -360,10 +360,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi
for i, key := range result.keys { for i, key := range result.keys {
snapTrie.Update(key, result.vals[i]) snapTrie.Update(key, result.vals[i])
} }
root, nodes, err := snapTrie.Commit(false) root, nodes := snapTrie.Commit(false)
if err != nil {
return false, nil, err
}
if nodes != nil { if nodes != nil {
tdb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) tdb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
tdb.Commit(root, false) tdb.Commit(root, false)

View file

@ -210,7 +210,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st
if !commit { if !commit {
return stTrie.Hash() return stTrie.Hash()
} }
root, nodes, _ := stTrie.Commit(false) root, nodes := stTrie.Commit(false)
if nodes != nil { if nodes != nil {
t.nodes.Merge(nodes) t.nodes.Merge(nodes)
} }
@ -218,7 +218,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st
} }
func (t *testHelper) Commit() common.Hash { func (t *testHelper) Commit() common.Hash {
root, nodes, _ := t.accTrie.Commit(true) root, nodes := t.accTrie.Commit(true)
if nodes != nil { if nodes != nil {
t.nodes.Merge(nodes) t.nodes.Merge(nodes)
} }

View file

@ -815,7 +815,7 @@ func TestStorageIteratorDeletions(t *testing.T) {
verifyIterator(t, 2, snaps.Snapshot(common.HexToHash("0x06")).(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa")), verifyStorage) verifyIterator(t, 2, snaps.Snapshot(common.HexToHash("0x06")).(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa")), verifyStorage)
} }
// BenchmarkAccountIteratorTraversal is a bit a bit notorious -- all layers contain the // BenchmarkAccountIteratorTraversal is a bit notorious -- all layers contain the
// exact same 200 accounts. That means that we need to process 2000 items, but // exact same 200 accounts. That means that we need to process 2000 items, but
// only spit out 200 values eventually. // only spit out 200 values eventually.
// //

View file

@ -230,6 +230,14 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
} }
value.SetBytes(val) value.SetBytes(val)
} }
// Independent of where we loaded the data from, add it to the prefetcher.
// Whilst this would be a bit weird if snapshots are disabled, but we still
// want the trie nodes to end up in the prefetcher too, so just push through.
if s.db.prefetcher != nil && s.data.Root != types.EmptyRootHash {
if err = s.db.prefetcher.prefetch(s.addrHash, s.origin.Root, s.address, [][]byte{key[:]}, true); err != nil {
log.Error("Failed to prefetch storage slot", "addr", s.address, "key", key, "err", err)
}
}
s.originStorage[key] = value s.originStorage[key] = value
return value return value
} }
@ -293,7 +301,7 @@ func (s *stateObject) finalise() {
s.pendingStorage[key] = value s.pendingStorage[key] = value
} }
if s.db.prefetcher != nil && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { if s.db.prefetcher != nil && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash {
if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch); err != nil { if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch, false); err != nil {
log.Error("Failed to prefetch slots", "addr", s.address, "slots", len(slotsToPrefetch), "err", err) log.Error("Failed to prefetch slots", "addr", s.address, "slots", len(slotsToPrefetch), "err", err)
} }
} }
@ -462,10 +470,7 @@ func (s *stateObject) commit() (*accountUpdate, *trienode.NodeSet, error) {
s.origin = s.data.Copy() s.origin = s.data.Copy()
return op, nil, nil return op, nil, nil
} }
root, nodes, err := s.trie.Commit(false) root, nodes := s.trie.Commit(false)
if err != nil {
return nil, nil, err
}
s.data.Root = root s.data.Root = root
s.origin = s.data.Copy() s.origin = s.data.Copy()
return op, nodes, nil return op, nodes, nil

View file

@ -200,14 +200,14 @@ func (s *StateDB) SetLogger(l *tracing.Hooks) {
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
// state trie concurrently while the state is mutated so that when we reach the // state trie concurrently while the state is mutated so that when we reach the
// commit phase, most of the needed data is already hot. // commit phase, most of the needed data is already hot.
func (s *StateDB) StartPrefetcher(namespace string) { func (s *StateDB) StartPrefetcher(namespace string, noreads bool) {
if s.prefetcher != nil { if s.prefetcher != nil {
s.prefetcher.terminate(false) s.prefetcher.terminate(false)
s.prefetcher.report() s.prefetcher.report()
s.prefetcher = nil s.prefetcher = nil
} }
if s.snap != nil { if s.snap != nil {
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace) s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, noreads)
// With the switch to the Proof-of-Stake consensus algorithm, block production // With the switch to the Proof-of-Stake consensus algorithm, block production
// rewards are now handled at the consensus layer. Consequently, a block may // rewards are now handled at the consensus layer. Consequently, a block may
@ -218,7 +218,7 @@ func (s *StateDB) StartPrefetcher(namespace string) {
// To prevent this, the account trie is always scheduled for prefetching once // To prevent this, the account trie is always scheduled for prefetching once
// the prefetcher is constructed. For more details, see: // the prefetcher is constructed. For more details, see:
// https://github.com/ethereum/go-ethereum/issues/29880 // https://github.com/ethereum/go-ethereum/issues/29880
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil); err != nil { if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil, false); err != nil {
log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err) log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err)
} }
} }
@ -616,6 +616,14 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
return nil return nil
} }
} }
// Independent of where we loaded the data from, add it to the prefetcher.
// Whilst this would be a bit weird if snapshots are disabled, but we still
// want the trie nodes to end up in the prefetcher too, so just push through.
if s.prefetcher != nil {
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, [][]byte{addr[:]}, true); err != nil {
log.Error("Failed to prefetch account", "addr", addr, "err", err)
}
}
// Insert into the live set // Insert into the live set
obj := newObject(s, addr, data) obj := newObject(s, addr, data)
s.setStateObject(obj) s.setStateObject(obj)
@ -792,7 +800,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure
} }
if s.prefetcher != nil && len(addressesToPrefetch) > 0 { if s.prefetcher != nil && len(addressesToPrefetch) > 0 {
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch); err != nil { if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch, false); err != nil {
log.Error("Failed to prefetch addresses", "addresses", len(addressesToPrefetch), "err", err) log.Error("Failed to prefetch addresses", "addresses", len(addressesToPrefetch), "err", err)
} }
} }
@ -1171,10 +1179,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) {
// code didn't anticipate for. // code didn't anticipate for.
workers.Go(func() error { workers.Go(func() error {
// Write the account trie changes, measuring the amount of wasted time // Write the account trie changes, measuring the amount of wasted time
newroot, set, err := s.trie.Commit(true) newroot, set := s.trie.Commit(true)
if err != nil {
return err
}
root = newroot root = newroot
if err := merge(set); err != nil { if err := merge(set); err != nil {

View file

@ -44,31 +44,49 @@ type triePrefetcher struct {
root common.Hash // Root hash of the account trie for metrics root common.Hash // Root hash of the account trie for metrics
fetchers map[string]*subfetcher // Subfetchers for each trie fetchers map[string]*subfetcher // Subfetchers for each trie
term chan struct{} // Channel to signal interruption term chan struct{} // Channel to signal interruption
noreads bool // Whether to ignore state-read-only prefetch requests
deliveryMissMeter metrics.Meter deliveryMissMeter metrics.Meter
accountLoadMeter metrics.Meter
accountDupMeter metrics.Meter accountLoadReadMeter metrics.Meter
accountWasteMeter metrics.Meter accountLoadWriteMeter metrics.Meter
storageLoadMeter metrics.Meter accountDupReadMeter metrics.Meter
storageDupMeter metrics.Meter accountDupWriteMeter metrics.Meter
storageWasteMeter metrics.Meter accountDupCrossMeter metrics.Meter
accountWasteMeter metrics.Meter
storageLoadReadMeter metrics.Meter
storageLoadWriteMeter metrics.Meter
storageDupReadMeter metrics.Meter
storageDupWriteMeter metrics.Meter
storageDupCrossMeter metrics.Meter
storageWasteMeter metrics.Meter
} }
func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePrefetcher { func newTriePrefetcher(db Database, root common.Hash, namespace string, noreads bool) *triePrefetcher {
prefix := triePrefetchMetricsPrefix + namespace prefix := triePrefetchMetricsPrefix + namespace
return &triePrefetcher{ return &triePrefetcher{
db: db, db: db,
root: root, root: root,
fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map
term: make(chan struct{}), term: make(chan struct{}),
noreads: noreads,
deliveryMissMeter: metrics.GetOrRegisterMeter(prefix+"/deliverymiss", nil), deliveryMissMeter: metrics.GetOrRegisterMeter(prefix+"/deliverymiss", nil),
accountLoadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load", nil),
accountDupMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup", nil), accountLoadReadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load/read", nil),
accountWasteMeter: metrics.GetOrRegisterMeter(prefix+"/account/waste", nil), accountLoadWriteMeter: metrics.GetOrRegisterMeter(prefix+"/account/load/write", nil),
storageLoadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load", nil), accountDupReadMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/read", nil),
storageDupMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup", nil), accountDupWriteMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/write", nil),
storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil), accountDupCrossMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/cross", nil),
accountWasteMeter: metrics.GetOrRegisterMeter(prefix+"/account/waste", nil),
storageLoadReadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load/read", nil),
storageLoadWriteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load/write", nil),
storageDupReadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/read", nil),
storageDupWriteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/write", nil),
storageDupCrossMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/cross", nil),
storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil),
} }
} }
@ -98,19 +116,31 @@ func (p *triePrefetcher) report() {
fetcher.wait() // ensure the fetcher's idle before poking in its internals fetcher.wait() // ensure the fetcher's idle before poking in its internals
if fetcher.root == p.root { if fetcher.root == p.root {
p.accountLoadMeter.Mark(int64(len(fetcher.seen))) p.accountLoadReadMeter.Mark(int64(len(fetcher.seenRead)))
p.accountDupMeter.Mark(int64(fetcher.dups)) p.accountLoadWriteMeter.Mark(int64(len(fetcher.seenWrite)))
p.accountDupReadMeter.Mark(int64(fetcher.dupsRead))
p.accountDupWriteMeter.Mark(int64(fetcher.dupsWrite))
p.accountDupCrossMeter.Mark(int64(fetcher.dupsCross))
for _, key := range fetcher.used { for _, key := range fetcher.used {
delete(fetcher.seen, string(key)) delete(fetcher.seenRead, string(key))
delete(fetcher.seenWrite, string(key))
} }
p.accountWasteMeter.Mark(int64(len(fetcher.seen))) p.accountWasteMeter.Mark(int64(len(fetcher.seenRead) + len(fetcher.seenWrite)))
} else { } else {
p.storageLoadMeter.Mark(int64(len(fetcher.seen))) p.storageLoadReadMeter.Mark(int64(len(fetcher.seenRead)))
p.storageDupMeter.Mark(int64(fetcher.dups)) p.storageLoadWriteMeter.Mark(int64(len(fetcher.seenWrite)))
p.storageDupReadMeter.Mark(int64(fetcher.dupsRead))
p.storageDupWriteMeter.Mark(int64(fetcher.dupsWrite))
p.storageDupCrossMeter.Mark(int64(fetcher.dupsCross))
for _, key := range fetcher.used { for _, key := range fetcher.used {
delete(fetcher.seen, string(key)) delete(fetcher.seenRead, string(key))
delete(fetcher.seenWrite, string(key))
} }
p.storageWasteMeter.Mark(int64(len(fetcher.seen))) p.storageWasteMeter.Mark(int64(len(fetcher.seenRead) + len(fetcher.seenWrite)))
} }
} }
} }
@ -126,7 +156,11 @@ func (p *triePrefetcher) report() {
// upon the same contract, the parameters invoking this method may be // upon the same contract, the parameters invoking this method may be
// repeated. // repeated.
// 2. Finalize of the main account trie. This happens only once per block. // 2. Finalize of the main account trie. This happens only once per block.
func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) error { func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte, read bool) error {
// If the state item is only being read, but reads are disabled, return
if read && p.noreads {
return nil
}
// Ensure the subfetcher is still alive // Ensure the subfetcher is still alive
select { select {
case <-p.term: case <-p.term:
@ -139,7 +173,7 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr comm
fetcher = newSubfetcher(p.db, p.root, owner, root, addr) fetcher = newSubfetcher(p.db, p.root, owner, root, addr)
p.fetchers[id] = fetcher p.fetchers[id] = fetcher
} }
return fetcher.schedule(keys) return fetcher.schedule(keys, read)
} }
// trie returns the trie matching the root hash, blocking until the fetcher of // trie returns the trie matching the root hash, blocking until the fetcher of
@ -186,38 +220,51 @@ type subfetcher struct {
addr common.Address // Address of the account that the trie belongs to addr common.Address // Address of the account that the trie belongs to
trie Trie // Trie being populated with nodes trie Trie // Trie being populated with nodes
tasks [][]byte // Items queued up for retrieval tasks []*subfetcherTask // Items queued up for retrieval
lock sync.Mutex // Lock protecting the task queue lock sync.Mutex // Lock protecting the task queue
wake chan struct{} // Wake channel if a new task is scheduled wake chan struct{} // Wake channel if a new task is scheduled
stop chan struct{} // Channel to interrupt processing stop chan struct{} // Channel to interrupt processing
term chan struct{} // Channel to signal interruption term chan struct{} // Channel to signal interruption
seen map[string]struct{} // Tracks the entries already loaded seenRead map[string]struct{} // Tracks the entries already loaded via read operations
dups int // Number of duplicate preload tasks seenWrite map[string]struct{} // Tracks the entries already loaded via write operations
used [][]byte // Tracks the entries used in the end
dupsRead int // Number of duplicate preload tasks via reads only
dupsWrite int // Number of duplicate preload tasks via writes only
dupsCross int // Number of duplicate preload tasks via read-write-crosses
used [][]byte // Tracks the entries used in the end
}
// subfetcherTask is a trie path to prefetch, tagged with whether it originates
// from a read or a write request.
type subfetcherTask struct {
read bool
key []byte
} }
// newSubfetcher creates a goroutine to prefetch state items belonging to a // newSubfetcher creates a goroutine to prefetch state items belonging to a
// particular root hash. // particular root hash.
func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash, addr common.Address) *subfetcher { func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash, addr common.Address) *subfetcher {
sf := &subfetcher{ sf := &subfetcher{
db: db, db: db,
state: state, state: state,
owner: owner, owner: owner,
root: root, root: root,
addr: addr, addr: addr,
wake: make(chan struct{}, 1), wake: make(chan struct{}, 1),
stop: make(chan struct{}), stop: make(chan struct{}),
term: make(chan struct{}), term: make(chan struct{}),
seen: make(map[string]struct{}), seenRead: make(map[string]struct{}),
seenWrite: make(map[string]struct{}),
} }
go sf.loop() go sf.loop()
return sf return sf
} }
// schedule adds a batch of trie keys to the queue to prefetch. // schedule adds a batch of trie keys to the queue to prefetch.
func (sf *subfetcher) schedule(keys [][]byte) error { func (sf *subfetcher) schedule(keys [][]byte, read bool) error {
// Ensure the subfetcher is still alive // Ensure the subfetcher is still alive
select { select {
case <-sf.term: case <-sf.term:
@ -226,7 +273,10 @@ func (sf *subfetcher) schedule(keys [][]byte) error {
} }
// Append the tasks to the current queue // Append the tasks to the current queue
sf.lock.Lock() sf.lock.Lock()
sf.tasks = append(sf.tasks, keys...) for _, key := range keys {
key := key // closure for the append below
sf.tasks = append(sf.tasks, &subfetcherTask{read: read, key: key})
}
sf.lock.Unlock() sf.lock.Unlock()
// Notify the background thread to execute scheduled tasks // Notify the background thread to execute scheduled tasks
@ -303,16 +353,36 @@ func (sf *subfetcher) loop() {
sf.lock.Unlock() sf.lock.Unlock()
for _, task := range tasks { for _, task := range tasks {
if _, ok := sf.seen[string(task)]; ok { key := string(task.key)
sf.dups++ if task.read {
continue if _, ok := sf.seenRead[key]; ok {
} sf.dupsRead++
if len(task) == common.AddressLength { continue
sf.trie.GetAccount(common.BytesToAddress(task)) }
if _, ok := sf.seenWrite[key]; ok {
sf.dupsCross++
continue
}
} else { } else {
sf.trie.GetStorage(sf.addr, task) if _, ok := sf.seenRead[key]; ok {
sf.dupsCross++
continue
}
if _, ok := sf.seenWrite[key]; ok {
sf.dupsWrite++
continue
}
}
if len(task.key) == common.AddressLength {
sf.trie.GetAccount(common.BytesToAddress(task.key))
} else {
sf.trie.GetStorage(sf.addr, task.key)
}
if task.read {
sf.seenRead[key] = struct{}{}
} else {
sf.seenWrite[key] = struct{}{}
} }
sf.seen[string(task)] = struct{}{}
} }
case <-sf.stop: case <-sf.stop:

View file

@ -47,15 +47,15 @@ func filledStateDB() *StateDB {
func TestUseAfterTerminate(t *testing.T) { func TestUseAfterTerminate(t *testing.T) {
db := filledStateDB() db := filledStateDB()
prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") prefetcher := newTriePrefetcher(db.db, db.originalRoot, "", true)
skey := common.HexToHash("aaa") skey := common.HexToHash("aaa")
if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err != nil { if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}, false); err != nil {
t.Errorf("Prefetch failed before terminate: %v", err) t.Errorf("Prefetch failed before terminate: %v", err)
} }
prefetcher.terminate(false) prefetcher.terminate(false)
if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err == nil { if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}, false); err == nil {
t.Errorf("Prefetch succeeded after terminate: %v", err) t.Errorf("Prefetch succeeded after terminate: %v", err)
} }
if tr := prefetcher.trie(common.Hash{}, db.originalRoot); tr == nil { if tr := prefetcher.trie(common.Hash{}, db.originalRoot); tr == nil {

View file

@ -143,7 +143,7 @@ func (bc *testBlockChain) CurrentFinalBlock() *types.Header {
} }
} }
func (bt *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
return nil return nil
} }

View file

@ -459,11 +459,11 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
// homestead rules. // homestead rules.
type HomesteadSigner struct{ FrontierSigner } type HomesteadSigner struct{ FrontierSigner }
func (s HomesteadSigner) ChainID() *big.Int { func (hs HomesteadSigner) ChainID() *big.Int {
return nil return nil
} }
func (s HomesteadSigner) Equal(s2 Signer) bool { func (hs HomesteadSigner) Equal(s2 Signer) bool {
_, ok := s2.(HomesteadSigner) _, ok := s2.(HomesteadSigner)
return ok return ok
} }
@ -486,11 +486,11 @@ func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
// frontier rules. // frontier rules.
type FrontierSigner struct{} type FrontierSigner struct{}
func (s FrontierSigner) ChainID() *big.Int { func (fs FrontierSigner) ChainID() *big.Int {
return nil return nil
} }
func (s FrontierSigner) Equal(s2 Signer) bool { func (fs FrontierSigner) Equal(s2 Signer) bool {
_, ok := s2.(FrontierSigner) _, ok := s2.(FrontierSigner)
return ok return ok
} }

View file

@ -33,6 +33,7 @@ type Config struct {
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
ExtraEips []int // Additional EIPS that are to be enabled ExtraEips []int // Additional EIPS that are to be enabled
EnableWitnessCollection bool // true if witness collection is enabled
} }
// ScopeContext contains the things that are per-call, such as stack and memory, // ScopeContext contains the things that are per-call, such as stack and memory,

View file

@ -184,6 +184,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
var ( var (
vmConfig = vm.Config{ vmConfig = vm.Config{
EnablePreimageRecording: config.EnablePreimageRecording, EnablePreimageRecording: config.EnablePreimageRecording,
EnableWitnessCollection: config.EnableWitnessCollection,
} }
cacheConfig = &core.CacheConfig{ cacheConfig = &core.CacheConfig{
TrieCleanLimit: config.TrieCleanCache, TrieCleanLimit: config.TrieCleanCache,

View file

@ -141,6 +141,9 @@ type Config struct {
// Enables tracking of SHA3 preimages in the VM // Enables tracking of SHA3 preimages in the VM
EnablePreimageRecording bool EnablePreimageRecording bool
// Enables prefetching trie nodes for read operations too
EnableWitnessCollection bool `toml:"-"`
// Enables VM tracing // Enables VM tracing
VMTrace string VMTrace string
VMTraceJsonConfig string VMTraceJsonConfig string

View file

@ -50,6 +50,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
BlobPool blobpool.Config BlobPool blobpool.Config
GPO gasprice.Config GPO gasprice.Config
EnablePreimageRecording bool EnablePreimageRecording bool
EnableWitnessCollection bool `toml:"-"`
VMTrace string VMTrace string
VMTraceJsonConfig string VMTraceJsonConfig string
DocRoot string `toml:"-"` DocRoot string `toml:"-"`
@ -93,6 +94,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.BlobPool = c.BlobPool enc.BlobPool = c.BlobPool
enc.GPO = c.GPO enc.GPO = c.GPO
enc.EnablePreimageRecording = c.EnablePreimageRecording enc.EnablePreimageRecording = c.EnablePreimageRecording
enc.EnableWitnessCollection = c.EnableWitnessCollection
enc.VMTrace = c.VMTrace enc.VMTrace = c.VMTrace
enc.VMTraceJsonConfig = c.VMTraceJsonConfig enc.VMTraceJsonConfig = c.VMTraceJsonConfig
enc.DocRoot = c.DocRoot enc.DocRoot = c.DocRoot
@ -140,6 +142,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
BlobPool *blobpool.Config BlobPool *blobpool.Config
GPO *gasprice.Config GPO *gasprice.Config
EnablePreimageRecording *bool EnablePreimageRecording *bool
EnableWitnessCollection *bool `toml:"-"`
VMTrace *string VMTrace *string
VMTraceJsonConfig *string VMTraceJsonConfig *string
DocRoot *string `toml:"-"` DocRoot *string `toml:"-"`
@ -252,6 +255,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
if dec.EnablePreimageRecording != nil { if dec.EnablePreimageRecording != nil {
c.EnablePreimageRecording = *dec.EnablePreimageRecording c.EnablePreimageRecording = *dec.EnablePreimageRecording
} }
if dec.EnableWitnessCollection != nil {
c.EnableWitnessCollection = *dec.EnableWitnessCollection
}
if dec.VMTrace != nil { if dec.VMTrace != nil {
c.VMTrace = *dec.VMTrace c.VMTrace = *dec.VMTrace
} }

View file

@ -1525,7 +1525,7 @@ func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv)
// Commit the state changes into db and re-create the trie // Commit the state changes into db and re-create the trie
// for accessing later. // for accessing later.
root, nodes, _ := accTrie.Commit(false) root, nodes := accTrie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
accTrie, _ = trie.New(trie.StateTrieID(root), db) accTrie, _ = trie.New(trie.StateTrieID(root), db)
@ -1587,7 +1587,7 @@ func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) {
// Commit the state changes into db and re-create the trie // Commit the state changes into db and re-create the trie
// for accessing later. // for accessing later.
root, nodes, _ := accTrie.Commit(false) root, nodes := accTrie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
accTrie, _ = trie.New(trie.StateTrieID(root), db) accTrie, _ = trie.New(trie.StateTrieID(root), db)
@ -1633,7 +1633,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots
slices.SortFunc(entries, (*kv).cmp) slices.SortFunc(entries, (*kv).cmp)
// Commit account trie // Commit account trie
root, set, _ := accTrie.Commit(true) root, set := accTrie.Commit(true)
nodes.Merge(set) nodes.Merge(set)
// Commit gathered dirty nodes into database // Commit gathered dirty nodes into database
@ -1700,7 +1700,7 @@ func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, bounda
slices.SortFunc(entries, (*kv).cmp) slices.SortFunc(entries, (*kv).cmp)
// Commit account trie // Commit account trie
root, set, _ := accTrie.Commit(true) root, set := accTrie.Commit(true)
nodes.Merge(set) nodes.Merge(set)
// Commit gathered dirty nodes into database // Commit gathered dirty nodes into database
@ -1742,7 +1742,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *triedb.Datab
entries = append(entries, elem) entries = append(entries, elem)
} }
slices.SortFunc(entries, (*kv).cmp) slices.SortFunc(entries, (*kv).cmp)
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
return root, nodes, entries return root, nodes, entries
} }
@ -1793,7 +1793,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *triedb.Database) (com
entries = append(entries, elem) entries = append(entries, elem)
} }
slices.SortFunc(entries, (*kv).cmp) slices.SortFunc(entries, (*kv).cmp)
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
return root, nodes, entries return root, nodes, entries
} }
@ -1825,7 +1825,7 @@ func makeUnevenStorageTrie(owner common.Hash, slots int, db *triedb.Database) (c
} }
} }
slices.SortFunc(entries, (*kv).cmp) slices.SortFunc(entries, (*kv).cmp)
root, nodes, _ := tr.Commit(false) root, nodes := tr.Commit(false)
return root, nodes, entries return root, nodes, entries
} }

File diff suppressed because it is too large Load diff

View file

@ -101,10 +101,10 @@ func (h *TerminalHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
} }
// ResetFieldPadding zeroes the field-padding for all attribute pairs. // ResetFieldPadding zeroes the field-padding for all attribute pairs.
func (t *TerminalHandler) ResetFieldPadding() { func (h *TerminalHandler) ResetFieldPadding() {
t.mu.Lock() h.mu.Lock()
t.fieldPadding = make(map[string]int) h.fieldPadding = make(map[string]int)
t.mu.Unlock() h.mu.Unlock()
} }
type leveler struct{ minLevel slog.Level } type leveler struct{ minLevel slog.Level }

View file

@ -123,20 +123,25 @@ The API is initialised with a particular node adapter and has the following
endpoints: endpoints:
``` ```
GET / Get network information OPTIONS / Response 200 with "Access-Control-Allow-Headers"" header set to "Content-Type""
POST /start Start all nodes in the network GET / Get network information
POST /stop Stop all nodes in the network POST /start Start all nodes in the network
GET /events Stream network events POST /stop Stop all nodes in the network
GET /snapshot Take a network snapshot POST /mocker/start Start the mocker node simulation
POST /snapshot Load a network snapshot POST /mocker/stop Stop the mocker node simulation
POST /nodes Create a node GET /mocker Get a list of available mockers
GET /nodes Get all nodes in the network POST /reset Reset all properties of a network to initial (empty) state
GET /nodes/:nodeid Get node information GET /events Stream network events
POST /nodes/:nodeid/start Start a node GET /snapshot Take a network snapshot
POST /nodes/:nodeid/stop Stop a node POST /snapshot Load a network snapshot
POST /nodes/:nodeid/conn/:peerid Connect two nodes POST /nodes Create a node
DELETE /nodes/:nodeid/conn/:peerid Disconnect two nodes GET /nodes Get all nodes in the network
GET /nodes/:nodeid/rpc Make RPC requests to a node via WebSocket GET /nodes/:nodeid Get node information
POST /nodes/:nodeid/start Start a node
POST /nodes/:nodeid/stop Stop a node
POST /nodes/:nodeid/conn/:peerid Connect two nodes
DELETE /nodes/:nodeid/conn/:peerid Disconnect two nodes
GET /nodes/:nodeid/rpc Make RPC requests to a node via WebSocket
``` ```
For convenience, `nodeid` in the URL can be the name of a node rather than its For convenience, `nodeid` in the URL can be the name of a node rather than its

View file

@ -67,9 +67,9 @@ func (vs *ValidationMessages) Info(msg string) {
} }
// GetWarnings returns an error with all messages of type WARN of above, or nil if no warnings were present // GetWarnings returns an error with all messages of type WARN of above, or nil if no warnings were present
func (v *ValidationMessages) GetWarnings() error { func (vs *ValidationMessages) GetWarnings() error {
var messages []string var messages []string
for _, msg := range v.Messages { for _, msg := range vs.Messages {
if msg.Typ == WARN || msg.Typ == CRIT { if msg.Typ == WARN || msg.Typ == CRIT {
messages = append(messages, msg.Message) messages = append(messages, msg.Message)
} }

View file

@ -52,9 +52,9 @@ func NewUIServerAPI(extapi *SignerAPI) *UIServerAPI {
// the full Account object and not only Address. // the full Account object and not only Address.
// Example call // Example call
// {"jsonrpc":"2.0","method":"clef_listAccounts","params":[], "id":4} // {"jsonrpc":"2.0","method":"clef_listAccounts","params":[], "id":4}
func (s *UIServerAPI) ListAccounts(ctx context.Context) ([]accounts.Account, error) { func (api *UIServerAPI) ListAccounts(ctx context.Context) ([]accounts.Account, error) {
var accs []accounts.Account var accs []accounts.Account
for _, wallet := range s.am.Wallets() { for _, wallet := range api.am.Wallets() {
accs = append(accs, wallet.Accounts()...) accs = append(accs, wallet.Accounts()...)
} }
return accs, nil return accs, nil
@ -72,9 +72,9 @@ type rawWallet struct {
// ListWallets will return a list of wallets that clef manages // ListWallets will return a list of wallets that clef manages
// Example call // Example call
// {"jsonrpc":"2.0","method":"clef_listWallets","params":[], "id":5} // {"jsonrpc":"2.0","method":"clef_listWallets","params":[], "id":5}
func (s *UIServerAPI) ListWallets() []rawWallet { func (api *UIServerAPI) ListWallets() []rawWallet {
wallets := make([]rawWallet, 0) // return [] instead of nil if empty wallets := make([]rawWallet, 0) // return [] instead of nil if empty
for _, wallet := range s.am.Wallets() { for _, wallet := range api.am.Wallets() {
status, failure := wallet.Status() status, failure := wallet.Status()
raw := rawWallet{ raw := rawWallet{
@ -94,8 +94,8 @@ func (s *UIServerAPI) ListWallets() []rawWallet {
// it for later reuse. // it for later reuse.
// Example call // Example call
// {"jsonrpc":"2.0","method":"clef_deriveAccount","params":["ledger://","m/44'/60'/0'", false], "id":6} // {"jsonrpc":"2.0","method":"clef_deriveAccount","params":["ledger://","m/44'/60'/0'", false], "id":6}
func (s *UIServerAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { func (api *UIServerAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) {
wallet, err := s.am.Wallet(url) wallet, err := api.am.Wallet(url)
if err != nil { if err != nil {
return accounts.Account{}, err return accounts.Account{}, err
} }
@ -122,7 +122,7 @@ func fetchKeystore(am *accounts.Manager) *keystore.KeyStore {
// encrypting it with the passphrase. // encrypting it with the passphrase.
// Example call (should fail on password too short) // Example call (should fail on password too short)
// {"jsonrpc":"2.0","method":"clef_importRawKey","params":["1111111111111111111111111111111111111111111111111111111111111111","test"], "id":6} // {"jsonrpc":"2.0","method":"clef_importRawKey","params":["1111111111111111111111111111111111111111111111111111111111111111","test"], "id":6}
func (s *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Account, error) { func (api *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Account, error) {
key, err := crypto.HexToECDSA(privkey) key, err := crypto.HexToECDSA(privkey)
if err != nil { if err != nil {
return accounts.Account{}, err return accounts.Account{}, err
@ -131,7 +131,7 @@ func (s *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Ac
return accounts.Account{}, fmt.Errorf("password requirements not met: %v", err) return accounts.Account{}, fmt.Errorf("password requirements not met: %v", err)
} }
// No error // No error
return fetchKeystore(s.am).ImportECDSA(key, password) return fetchKeystore(api.am).ImportECDSA(key, password)
} }
// OpenWallet initiates a hardware wallet opening procedure, establishing a USB // OpenWallet initiates a hardware wallet opening procedure, establishing a USB
@ -140,8 +140,8 @@ func (s *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Ac
// Trezor PIN matrix challenge). // Trezor PIN matrix challenge).
// Example // Example
// {"jsonrpc":"2.0","method":"clef_openWallet","params":["ledger://",""], "id":6} // {"jsonrpc":"2.0","method":"clef_openWallet","params":["ledger://",""], "id":6}
func (s *UIServerAPI) OpenWallet(url string, passphrase *string) error { func (api *UIServerAPI) OpenWallet(url string, passphrase *string) error {
wallet, err := s.am.Wallet(url) wallet, err := api.am.Wallet(url)
if err != nil { if err != nil {
return err return err
} }
@ -155,24 +155,24 @@ func (s *UIServerAPI) OpenWallet(url string, passphrase *string) error {
// ChainId returns the chainid in use for Eip-155 replay protection // ChainId returns the chainid in use for Eip-155 replay protection
// Example call // Example call
// {"jsonrpc":"2.0","method":"clef_chainId","params":[], "id":8} // {"jsonrpc":"2.0","method":"clef_chainId","params":[], "id":8}
func (s *UIServerAPI) ChainId() math.HexOrDecimal64 { func (api *UIServerAPI) ChainId() math.HexOrDecimal64 {
return (math.HexOrDecimal64)(s.extApi.chainID.Uint64()) return (math.HexOrDecimal64)(api.extApi.chainID.Uint64())
} }
// SetChainId sets the chain id to use when signing transactions. // SetChainId sets the chain id to use when signing transactions.
// Example call to set Ropsten: // Example call to set Ropsten:
// {"jsonrpc":"2.0","method":"clef_setChainId","params":["3"], "id":8} // {"jsonrpc":"2.0","method":"clef_setChainId","params":["3"], "id":8}
func (s *UIServerAPI) SetChainId(id math.HexOrDecimal64) math.HexOrDecimal64 { func (api *UIServerAPI) SetChainId(id math.HexOrDecimal64) math.HexOrDecimal64 {
s.extApi.chainID = new(big.Int).SetUint64(uint64(id)) api.extApi.chainID = new(big.Int).SetUint64(uint64(id))
return s.ChainId() return api.ChainId()
} }
// Export returns encrypted private key associated with the given address in web3 keystore format. // Export returns encrypted private key associated with the given address in web3 keystore format.
// Example // Example
// {"jsonrpc":"2.0","method":"clef_export","params":["0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a"], "id":4} // {"jsonrpc":"2.0","method":"clef_export","params":["0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a"], "id":4}
func (s *UIServerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) { func (api *UIServerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) {
// Look up the wallet containing the requested signer // Look up the wallet containing the requested signer
wallet, err := s.am.Find(accounts.Account{Address: addr}) wallet, err := api.am.Find(accounts.Account{Address: addr})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -59,7 +59,7 @@ func TestIterator(t *testing.T) {
all[val.k] = val.v all[val.k] = val.v
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -257,7 +257,7 @@ func TestDifferenceIterator(t *testing.T) {
for _, val := range testdata1 { for _, val := range testdata1 {
triea.MustUpdate([]byte(val.k), []byte(val.v)) triea.MustUpdate([]byte(val.k), []byte(val.v))
} }
rootA, nodesA, _ := triea.Commit(false) rootA, nodesA := triea.Commit(false)
dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA))
triea, _ = New(TrieID(rootA), dba) triea, _ = New(TrieID(rootA), dba)
@ -266,7 +266,7 @@ func TestDifferenceIterator(t *testing.T) {
for _, val := range testdata2 { for _, val := range testdata2 {
trieb.MustUpdate([]byte(val.k), []byte(val.v)) trieb.MustUpdate([]byte(val.k), []byte(val.v))
} }
rootB, nodesB, _ := trieb.Commit(false) rootB, nodesB := trieb.Commit(false)
dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB))
trieb, _ = New(TrieID(rootB), dbb) trieb, _ = New(TrieID(rootB), dbb)
@ -299,7 +299,7 @@ func TestUnionIterator(t *testing.T) {
for _, val := range testdata1 { for _, val := range testdata1 {
triea.MustUpdate([]byte(val.k), []byte(val.v)) triea.MustUpdate([]byte(val.k), []byte(val.v))
} }
rootA, nodesA, _ := triea.Commit(false) rootA, nodesA := triea.Commit(false)
dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA))
triea, _ = New(TrieID(rootA), dba) triea, _ = New(TrieID(rootA), dba)
@ -308,7 +308,7 @@ func TestUnionIterator(t *testing.T) {
for _, val := range testdata2 { for _, val := range testdata2 {
trieb.MustUpdate([]byte(val.k), []byte(val.v)) trieb.MustUpdate([]byte(val.k), []byte(val.v))
} }
rootB, nodesB, _ := trieb.Commit(false) rootB, nodesB := trieb.Commit(false)
dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB))
trieb, _ = New(TrieID(rootB), dbb) trieb, _ = New(TrieID(rootB), dbb)
@ -371,7 +371,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool, scheme string) {
for _, val := range testdata1 { for _, val := range testdata1 {
tr.MustUpdate([]byte(val.k), []byte(val.v)) tr.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes, _ := tr.Commit(false) root, nodes := tr.Commit(false)
tdb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) tdb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
if !memonly { if !memonly {
tdb.Commit(root) tdb.Commit(root)
@ -481,7 +481,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme strin
for _, val := range testdata1 { for _, val := range testdata1 {
ctr.MustUpdate([]byte(val.k), []byte(val.v)) ctr.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes, _ := ctr.Commit(false) root, nodes := ctr.Commit(false)
for path, n := range nodes.Nodes { for path, n := range nodes.Nodes {
if n.Hash == barNodeHash { if n.Hash == barNodeHash {
barNodePath = []byte(path) barNodePath = []byte(path)
@ -561,7 +561,7 @@ func testIteratorNodeBlob(t *testing.T, scheme string) {
all[val.k] = val.v all[val.k] = val.v
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
triedb.Commit(root) triedb.Commit(root)

View file

@ -221,7 +221,7 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte {
// All cached preimages will be also flushed if preimages recording is enabled. // All cached preimages will be also flushed if preimages recording is enabled.
// Once the trie is committed, it's not usable anymore. A new trie must // Once the trie is committed, it's not usable anymore. A new trie must
// be created with new root and updated trie database for following usage // be created with new root and updated trie database for following usage
func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) {
// Write all the pre-images to the actual disk database // Write all the pre-images to the actual disk database
if len(t.getSecKeyCache()) > 0 { if len(t.getSecKeyCache()) > 0 {
preimages := make(map[common.Hash][]byte) preimages := make(map[common.Hash][]byte)

View file

@ -60,7 +60,7 @@ func makeTestStateTrie() (*testDb, *StateTrie, map[string][]byte) {
trie.MustUpdate(key, val) trie.MustUpdate(key, val)
} }
} }
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil { if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil {
panic(fmt.Errorf("failed to commit db %v", err)) panic(fmt.Errorf("failed to commit db %v", err))
} }

View file

@ -79,10 +79,7 @@ func fuzz(data []byte, debugging bool) {
return return
} }
// Flush trie -> database // Flush trie -> database
rootA, nodes, err := trieA.Commit(false) rootA, nodes := trieA.Commit(false)
if err != nil {
panic(err)
}
if nodes != nil { if nodes != nil {
dbA.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) dbA.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
} }

View file

@ -58,7 +58,7 @@ func makeTestTrie(scheme string) (ethdb.Database, *testDb, *StateTrie, map[strin
trie.MustUpdate(key, val) trie.MustUpdate(key, val)
} }
} }
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil { if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil {
panic(fmt.Errorf("failed to commit db %v", err)) panic(fmt.Errorf("failed to commit db %v", err))
} }
@ -771,7 +771,7 @@ func testSyncMovingTarget(t *testing.T, scheme string) {
srcTrie.MustUpdate(key, val) srcTrie.MustUpdate(key, val)
diff[string(key)] = val diff[string(key)] = val
} }
root, nodes, _ := srcTrie.Commit(false) root, nodes := srcTrie.Commit(false)
if err := srcDb.Update(root, preRoot, trienode.NewWithNodeSet(nodes)); err != nil { if err := srcDb.Update(root, preRoot, trienode.NewWithNodeSet(nodes)); err != nil {
panic(err) panic(err)
} }
@ -796,7 +796,7 @@ func testSyncMovingTarget(t *testing.T, scheme string) {
srcTrie.MustUpdate([]byte(k), val) srcTrie.MustUpdate([]byte(k), val)
reverted[k] = val reverted[k] = val
} }
root, nodes, _ = srcTrie.Commit(false) root, nodes = srcTrie.Commit(false)
if err := srcDb.Update(root, preRoot, trienode.NewWithNodeSet(nodes)); err != nil { if err := srcDb.Update(root, preRoot, trienode.NewWithNodeSet(nodes)); err != nil {
panic(err) panic(err)
} }
@ -847,7 +847,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) {
writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateA) writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateA)
writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateA) writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateA)
rootA, nodesA, _ := srcTrie.Commit(false) rootA, nodesA := srcTrie.Commit(false)
if err := srcTrieDB.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)); err != nil { if err := srcTrieDB.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)); err != nil {
panic(err) panic(err)
} }
@ -866,7 +866,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) {
deleteFn([]byte{0x13, 0x44}, srcTrie, stateB) deleteFn([]byte{0x13, 0x44}, srcTrie, stateB)
writeFn([]byte{0x01, 0x24}, nil, srcTrie, stateB) writeFn([]byte{0x01, 0x24}, nil, srcTrie, stateB)
rootB, nodesB, _ := srcTrie.Commit(false) rootB, nodesB := srcTrie.Commit(false)
if err := srcTrieDB.Update(rootB, rootA, trienode.NewWithNodeSet(nodesB)); err != nil { if err := srcTrieDB.Update(rootB, rootA, trienode.NewWithNodeSet(nodesB)); err != nil {
panic(err) panic(err)
} }
@ -884,7 +884,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) {
writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateC) writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateC)
writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateC) writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateC)
rootC, nodesC, _ := srcTrie.Commit(false) rootC, nodesC := srcTrie.Commit(false)
if err := srcTrieDB.Update(rootC, rootB, trienode.NewWithNodeSet(nodesC)); err != nil { if err := srcTrieDB.Update(rootC, rootB, trienode.NewWithNodeSet(nodesC)); err != nil {
panic(err) panic(err)
} }
@ -946,7 +946,7 @@ func testSyncAbort(t *testing.T, scheme string) {
} }
writeFn(key, val, srcTrie, stateA) writeFn(key, val, srcTrie, stateA)
rootA, nodesA, _ := srcTrie.Commit(false) rootA, nodesA := srcTrie.Commit(false)
if err := srcTrieDB.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)); err != nil { if err := srcTrieDB.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)); err != nil {
panic(err) panic(err)
} }
@ -963,7 +963,7 @@ func testSyncAbort(t *testing.T, scheme string) {
srcTrie, _ = New(TrieID(rootA), srcTrieDB) srcTrie, _ = New(TrieID(rootA), srcTrieDB)
deleteFn(key, srcTrie, stateB) deleteFn(key, srcTrie, stateB)
rootB, nodesB, _ := srcTrie.Commit(false) rootB, nodesB := srcTrie.Commit(false)
if err := srcTrieDB.Update(rootB, rootA, trienode.NewWithNodeSet(nodesB)); err != nil { if err := srcTrieDB.Update(rootB, rootA, trienode.NewWithNodeSet(nodesB)); err != nil {
panic(err) panic(err)
} }
@ -990,7 +990,7 @@ func testSyncAbort(t *testing.T, scheme string) {
srcTrie, _ = New(TrieID(rootB), srcTrieDB) srcTrie, _ = New(TrieID(rootB), srcTrieDB)
writeFn(key, val, srcTrie, stateC) writeFn(key, val, srcTrie, stateC)
rootC, nodesC, _ := srcTrie.Commit(false) rootC, nodesC := srcTrie.Commit(false)
if err := srcTrieDB.Update(rootC, rootB, trienode.NewWithNodeSet(nodesC)); err != nil { if err := srcTrieDB.Update(rootC, rootB, trienode.NewWithNodeSet(nodesC)); err != nil {
panic(err) panic(err)
} }

View file

@ -70,7 +70,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) {
} }
insertSet := copySet(trie.tracer.inserts) // copy before commit insertSet := copySet(trie.tracer.inserts) // copy before commit
deleteSet := copySet(trie.tracer.deletes) // copy before commit deleteSet := copySet(trie.tracer.deletes) // copy before commit
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
seen := setKeys(iterNodes(db, root)) seen := setKeys(iterNodes(db, root))
@ -137,7 +137,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
for _, val := range vals { for _, val := range vals {
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -152,7 +152,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
for _, val := range vals { for _, val := range vals {
trie.MustUpdate([]byte(val.k), randBytes(32)) trie.MustUpdate([]byte(val.k), randBytes(32))
} }
root, nodes, _ = trie.Commit(false) root, nodes = trie.Commit(false)
db.Update(root, parent, trienode.NewWithNodeSet(nodes)) db.Update(root, parent, trienode.NewWithNodeSet(nodes))
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -170,7 +170,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
keys = append(keys, string(key)) keys = append(keys, string(key))
trie.MustUpdate(key, randBytes(32)) trie.MustUpdate(key, randBytes(32))
} }
root, nodes, _ = trie.Commit(false) root, nodes = trie.Commit(false)
db.Update(root, parent, trienode.NewWithNodeSet(nodes)) db.Update(root, parent, trienode.NewWithNodeSet(nodes))
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -185,7 +185,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
for _, key := range keys { for _, key := range keys {
trie.MustUpdate([]byte(key), nil) trie.MustUpdate([]byte(key), nil)
} }
root, nodes, _ = trie.Commit(false) root, nodes = trie.Commit(false)
db.Update(root, parent, trienode.NewWithNodeSet(nodes)) db.Update(root, parent, trienode.NewWithNodeSet(nodes))
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -200,7 +200,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
for _, val := range vals { for _, val := range vals {
trie.MustUpdate([]byte(val.k), nil) trie.MustUpdate([]byte(val.k), nil)
} }
root, nodes, _ = trie.Commit(false) root, nodes = trie.Commit(false)
db.Update(root, parent, trienode.NewWithNodeSet(nodes)) db.Update(root, parent, trienode.NewWithNodeSet(nodes))
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -219,7 +219,7 @@ func TestAccessListLeak(t *testing.T) {
for _, val := range standard { for _, val := range standard {
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
var cases = []struct { var cases = []struct {
@ -269,7 +269,7 @@ func TestTinyTree(t *testing.T) {
for _, val := range tiny { for _, val := range tiny {
trie.MustUpdate([]byte(val.k), randBytes(32)) trie.MustUpdate([]byte(val.k), randBytes(32))
} }
root, set, _ := trie.Commit(false) root, set := trie.Commit(false)
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(set)) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(set))
parent := root parent := root
@ -278,7 +278,7 @@ func TestTinyTree(t *testing.T) {
for _, val := range tiny { for _, val := range tiny {
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, set, _ = trie.Commit(false) root, set = trie.Commit(false)
db.Update(root, parent, trienode.NewWithNodeSet(set)) db.Update(root, parent, trienode.NewWithNodeSet(set))
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)

View file

@ -608,7 +608,7 @@ func (t *Trie) Hash() common.Hash {
// The returned nodeset can be nil if the trie is clean (nothing to commit). // The returned nodeset can be nil if the trie is clean (nothing to commit).
// Once the trie is committed, it's not usable anymore. A new trie must // Once the trie is committed, it's not usable anymore. A new trie must
// be created with new root and updated trie database for following usage // be created with new root and updated trie database for following usage
func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) {
defer t.tracer.reset() defer t.tracer.reset()
defer func() { defer func() {
t.committed = true t.committed = true
@ -620,13 +620,13 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
if t.root == nil { if t.root == nil {
paths := t.tracer.deletedNodes() paths := t.tracer.deletedNodes()
if len(paths) == 0 { if len(paths) == 0 {
return types.EmptyRootHash, nil, nil // case (a) return types.EmptyRootHash, nil // case (a)
} }
nodes := trienode.NewNodeSet(t.owner) nodes := trienode.NewNodeSet(t.owner)
for _, path := range paths { for _, path := range paths {
nodes.AddNode([]byte(path), trienode.NewDeleted()) nodes.AddNode([]byte(path), trienode.NewDeleted())
} }
return types.EmptyRootHash, nodes, nil // case (b) return types.EmptyRootHash, nodes // case (b)
} }
// Derive the hash for all dirty nodes first. We hold the assumption // Derive the hash for all dirty nodes first. We hold the assumption
// in the following procedure that all nodes are hashed. // in the following procedure that all nodes are hashed.
@ -638,14 +638,14 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
// Replace the root node with the origin hash in order to // Replace the root node with the origin hash in order to
// ensure all resolved nodes are dropped after the commit. // ensure all resolved nodes are dropped after the commit.
t.root = hashedNode t.root = hashedNode
return rootHash, nil, nil return rootHash, nil
} }
nodes := trienode.NewNodeSet(t.owner) nodes := trienode.NewNodeSet(t.owner)
for _, path := range t.tracer.deletedNodes() { for _, path := range t.tracer.deletedNodes() {
nodes.AddNode([]byte(path), trienode.NewDeleted()) nodes.AddNode([]byte(path), trienode.NewDeleted())
} }
t.root = newCommitter(nodes, t.tracer, collectLeaf).Commit(t.root) t.root = newCommitter(nodes, t.tracer, collectLeaf).Commit(t.root)
return rootHash, nodes, nil return rootHash, nodes
} }
// hashRoot calculates the root hash of the given trie // hashRoot calculates the root hash of the given trie

View file

@ -95,7 +95,7 @@ func testMissingNode(t *testing.T, memonly bool, scheme string) {
trie := NewEmpty(triedb) trie := NewEmpty(triedb)
updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
if !memonly { if !memonly {
@ -184,7 +184,7 @@ func TestInsert(t *testing.T) {
updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")
root, _, _ = trie.Commit(false) root, _ = trie.Commit(false)
if root != exp { if root != exp {
t.Errorf("case 2: exp %x got %x", exp, root) t.Errorf("case 2: exp %x got %x", exp, root)
} }
@ -209,7 +209,7 @@ func TestGet(t *testing.T) {
if i == 1 { if i == 1 {
return return
} }
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
} }
@ -282,7 +282,7 @@ func TestReplication(t *testing.T) {
for _, val := range vals { for _, val := range vals {
updateString(trie, val.k, val.v) updateString(trie, val.k, val.v)
} }
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
// create a new trie on top of the database and check that lookups work. // create a new trie on top of the database and check that lookups work.
@ -295,7 +295,7 @@ func TestReplication(t *testing.T) {
t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v)
} }
} }
hash, nodes, _ := trie2.Commit(false) hash, nodes := trie2.Commit(false)
if hash != root { if hash != root {
t.Errorf("root failure. expected %x got %x", root, hash) t.Errorf("root failure. expected %x got %x", root, hash)
} }
@ -531,7 +531,7 @@ func runRandTest(rt randTest) error {
case opHash: case opHash:
tr.Hash() tr.Hash()
case opCommit: case opCommit:
root, nodes, _ := tr.Commit(true) root, nodes := tr.Commit(true)
if nodes != nil { if nodes != nil {
triedb.Update(root, origin, trienode.NewWithNodeSet(nodes)) triedb.Update(root, origin, trienode.NewWithNodeSet(nodes))
} }
@ -768,7 +768,7 @@ func TestCommitAfterHash(t *testing.T) {
if exp != root { if exp != root {
t.Errorf("got %x, exp %x", root, exp) t.Errorf("got %x, exp %x", root, exp)
} }
root, _, _ = trie.Commit(false) root, _ = trie.Commit(false)
if exp != root { if exp != root {
t.Errorf("got %x, exp %x", root, exp) t.Errorf("got %x, exp %x", root, exp)
} }
@ -894,7 +894,7 @@ func TestCommitSequence(t *testing.T) {
trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i])
} }
// Flush trie -> database // Flush trie -> database
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
// Flush memdb -> disk (sponge) // Flush memdb -> disk (sponge)
db.Commit(root) db.Commit(root)
@ -935,7 +935,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) {
trie.MustUpdate(key, val) trie.MustUpdate(key, val)
} }
// Flush trie -> database // Flush trie -> database
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
// Flush memdb -> disk (sponge) // Flush memdb -> disk (sponge)
db.Commit(root) db.Commit(root)
@ -984,7 +984,7 @@ func TestCommitSequenceStackTrie(t *testing.T) {
stTrie.Update(key, val) stTrie.Update(key, val)
} }
// Flush trie -> database // Flush trie -> database
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
// Flush memdb -> disk (sponge) // Flush memdb -> disk (sponge)
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
db.Commit(root) db.Commit(root)
@ -1042,7 +1042,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) {
stTrie.Update(key, []byte{0x1}) stTrie.Update(key, []byte{0x1})
// Flush trie -> database // Flush trie -> database
root, nodes, _ := trie.Commit(false) root, nodes := trie.Commit(false)
// Flush memdb -> disk (sponge) // Flush memdb -> disk (sponge)
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
db.Commit(root) db.Commit(root)

View file

@ -42,7 +42,7 @@ type Trie interface {
// Commit the trie and returns a set of dirty nodes generated along with // Commit the trie and returns a set of dirty nodes generated along with
// the new root hash. // the new root hash.
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet)
} }
// TrieLoader wraps functions to load tries. // TrieLoader wraps functions to load tries.
@ -125,10 +125,7 @@ func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Addre
return nil, fmt.Errorf("failed to revert state, err: %w", err) return nil, fmt.Errorf("failed to revert state, err: %w", err)
} }
} }
root, result, err := tr.Commit(false) root, result := tr.Commit(false)
if err != nil {
return nil, err
}
if root != prevRoot { if root != prevRoot {
return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root) return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root)
} }
@ -180,10 +177,7 @@ func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error {
return err return err
} }
} }
root, result, err := st.Commit(false) root, result := st.Commit(false)
if err != nil {
return err
}
if root != prev.Root { if root != prev.Root {
return errors.New("failed to reset storage trie") return errors.New("failed to reset storage trie")
} }
@ -234,10 +228,7 @@ func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error {
return err return err
} }
} }
root, result, err := st.Commit(false) root, result := st.Commit(false)
if err != nil {
return err
}
if root != types.EmptyRootHash { if root != types.EmptyRootHash {
return errors.New("failed to clear storage trie") return errors.New("failed to clear storage trie")
} }

View file

@ -217,22 +217,21 @@ func (t *VerkleTrie) Hash() common.Hash {
} }
// Commit writes all nodes to the tree's memory database. // Commit writes all nodes to the tree's memory database.
func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet, error) { func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet) {
root, ok := t.root.(*verkle.InternalNode) root := t.root.(*verkle.InternalNode)
if !ok {
return common.Hash{}, nil, errors.New("unexpected root node type")
}
nodes, err := root.BatchSerialize() nodes, err := root.BatchSerialize()
if err != nil { if err != nil {
return common.Hash{}, nil, fmt.Errorf("serializing tree nodes: %s", err) // Error return from this function indicates error in the code logic
// of BatchSerialize, and we fail catastrophically if this is the case.
panic(fmt.Errorf("BatchSerialize failed: %v", err))
} }
nodeset := trienode.NewNodeSet(common.Hash{}) nodeset := trienode.NewNodeSet(common.Hash{})
for _, node := range nodes { for _, node := range nodes {
// hash parameter is not used in pathdb // Hash parameter is not used in pathdb
nodeset.AddNode(node.Path, trienode.New(common.Hash{}, node.SerializedBytes)) nodeset.AddNode(node.Path, trienode.New(common.Hash{}, node.SerializedBytes))
} }
// Serialize root commitment form // Serialize root commitment form
return t.Hash(), nodeset, nil return t.Hash(), nodeset
} }
// NodeIterator implements state.Trie, returning an iterator that returns // NodeIterator implements state.Trie, returning an iterator that returns

View file

@ -46,11 +46,7 @@ func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[comm
h.Update(key.Bytes(), val) h.Update(key.Bytes(), val)
} }
} }
root, nodes, err := h.Commit(false) return h.Commit(false)
if err != nil {
panic(fmt.Errorf("failed to commit hasher, err: %w", err))
}
return root, nodes
} }
func generateAccount(storageRoot common.Hash) types.StateAccount { func generateAccount(storageRoot common.Hash) types.StateAccount {

View file

@ -80,7 +80,7 @@ func (h *testHasher) Delete(key []byte) error {
// Commit computes the new hash of the states and returns the set with all // Commit computes the new hash of the states and returns the set with all
// state changes. // state changes.
func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) {
var ( var (
nodes = make(map[common.Hash][]byte) nodes = make(map[common.Hash][]byte)
set = trienode.NewNodeSet(h.owner) set = trienode.NewNodeSet(h.owner)
@ -111,7 +111,7 @@ func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, e
if root == types.EmptyRootHash && h.root != types.EmptyRootHash { if root == types.EmptyRootHash && h.root != types.EmptyRootHash {
set.AddNode(nil, trienode.NewDeleted()) set.AddNode(nil, trienode.NewDeleted())
} }
return root, set, nil return root, set
} }
// hash performs the hash computation upon the provided states. // hash performs the hash computation upon the provided states.