From ce63bba361f9b76c326dfeb078872839a8aef06c Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 25 Jun 2025 16:49:09 +0800 Subject: [PATCH 01/14] eth, triedb/pathdb: permit write buffer allowance in PBSS archive mode (#32091) This pull request fixes a flaw in PBSS archive mode that significantly degrades performance when the mode is enabled. Originally, in hash mode, the dirty trie cache is completely disabled when archive mode is active, in order to disable the in-memory garbage collection mechanism. However, the internal logic in path mode differs significantly, and the dirty trie node cache is essential for maintaining chain insertion performance. Therefore, the cache is now retained in path mode. --- eth/backend.go | 2 +- triedb/pathdb/history_indexer.go | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 5561657ea8..4b08707d2f 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -140,7 +140,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { log.Warn("Sanitizing invalid miner gas price", "provided", config.Miner.GasPrice, "updated", ethconfig.Defaults.Miner.GasPrice) config.Miner.GasPrice = new(big.Int).Set(ethconfig.Defaults.Miner.GasPrice) } - if config.NoPruning && config.TrieDirtyCache > 0 { + if config.NoPruning && config.TrieDirtyCache > 0 && config.StateScheme == rawdb.HashScheme { if config.SnapshotCache > 0 { config.TrieCleanCache += config.TrieDirtyCache * 3 / 5 config.SnapshotCache += config.TrieDirtyCache * 2 / 5 diff --git a/triedb/pathdb/history_indexer.go b/triedb/pathdb/history_indexer.go index b09804ce9d..75bba5399a 100644 --- a/triedb/pathdb/history_indexer.go +++ b/triedb/pathdb/history_indexer.go @@ -128,9 +128,11 @@ func (b *batchIndexer) finish(force bool) error { return nil } var ( - batch = b.db.NewBatch() - batchMu sync.RWMutex - eg errgroup.Group + batch = b.db.NewBatch() + batchMu sync.RWMutex + storages int + start = time.Now() + eg errgroup.Group ) eg.SetLimit(runtime.NumCPU()) @@ -167,6 +169,7 @@ func (b *batchIndexer) finish(force bool) error { }) } for addrHash, slots := range b.storages { + storages += len(slots) for storageHash, idList := range slots { eg.Go(func() error { if !b.delete { @@ -216,6 +219,7 @@ func (b *batchIndexer) finish(force bool) error { if err := batch.Write(); err != nil { return err } + log.Debug("Committed batch indexer", "accounts", len(b.accounts), "storages", storages, "records", b.counter, "elapsed", common.PrettyDuration(time.Since(start))) b.counter = 0 b.accounts = make(map[common.Hash][]uint64) b.storages = make(map[common.Hash]map[common.Hash][]uint64) @@ -224,9 +228,10 @@ func (b *batchIndexer) finish(force bool) error { // indexSingle processes the state history with the specified ID for indexing. func indexSingle(historyID uint64, db ethdb.KeyValueStore, freezer ethdb.AncientReader) error { - defer func(start time.Time) { + start := time.Now() + defer func() { indexHistoryTimer.UpdateSince(start) - }(time.Now()) + }() metadata := loadIndexMetadata(db) if metadata == nil || metadata.Last+1 != historyID { @@ -247,15 +252,16 @@ func indexSingle(historyID uint64, db ethdb.KeyValueStore, freezer ethdb.Ancient if err := b.finish(true); err != nil { return err } - log.Debug("Indexed state history", "id", historyID) + log.Debug("Indexed state history", "id", historyID, "elapsed", common.PrettyDuration(time.Since(start))) return nil } // unindexSingle processes the state history with the specified ID for unindexing. func unindexSingle(historyID uint64, db ethdb.KeyValueStore, freezer ethdb.AncientReader) error { - defer func(start time.Time) { + start := time.Now() + defer func() { unindexHistoryTimer.UpdateSince(start) - }(time.Now()) + }() metadata := loadIndexMetadata(db) if metadata == nil || metadata.Last != historyID { @@ -276,7 +282,7 @@ func unindexSingle(historyID uint64, db ethdb.KeyValueStore, freezer ethdb.Ancie if err := b.finish(true); err != nil { return err } - log.Debug("Unindexed state history", "id", historyID) + log.Debug("Unindexed state history", "id", historyID, "elapsed", common.PrettyDuration(time.Since(start))) return nil } From a92f2b86e33e49ec23e67fa0e17eaabf99cc9645 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 25 Jun 2025 16:50:54 +0800 Subject: [PATCH 02/14] core, eth, triedb: serve historical states over RPC (#31161) This is the part-2 for archive node over path mode, which ultimately ships the functionality to serve the historical states --- core/blockchain_reader.go | 7 ++ core/state/database_history.go | 155 +++++++++++++++++++++++++++++++ eth/api_backend.go | 10 +- eth/state_accessor.go | 9 +- triedb/database.go | 9 ++ triedb/pathdb/history_indexer.go | 2 +- 6 files changed, 185 insertions(+), 7 deletions(-) create mode 100644 core/state/database_history.go diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 6a0cfd6704..046d96063d 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -370,6 +370,13 @@ func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) { return state.New(root, bc.statedb) } +// HistoricState returns a historic state specified by the given root. +// Live states are not available and won't be served, please use `State` +// or `StateAt` instead. +func (bc *BlockChain) HistoricState(root common.Hash) (*state.StateDB, error) { + return state.New(root, state.NewHistoricDatabase(bc.db, bc.triedb)) +} + // Config retrieves the chain's fork configuration. func (bc *BlockChain) Config() *params.ChainConfig { return bc.chainConfig } diff --git a/core/state/database_history.go b/core/state/database_history.go new file mode 100644 index 0000000000..314c56c470 --- /dev/null +++ b/core/state/database_history.go @@ -0,0 +1,155 @@ +// Copyright 2025 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 . + +package state + +import ( + "errors" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie/utils" + "github.com/ethereum/go-ethereum/triedb" + "github.com/ethereum/go-ethereum/triedb/pathdb" +) + +// historicReader wraps a historical state reader defined in path database, +// providing historic state serving over the path scheme. +// +// TODO(rjl493456442): historicReader is not thread-safe and does not fully +// comply with the StateReader interface requirements, needs to be fixed. +// Currently, it is only used in a non-concurrent context, so it is safe for now. +type historicReader struct { + reader *pathdb.HistoricalStateReader +} + +// newHistoricReader constructs a reader for historic state serving. +func newHistoricReader(r *pathdb.HistoricalStateReader) *historicReader { + return &historicReader{reader: r} +} + +// Account implements StateReader, retrieving the account specified by the address. +// +// An error will be returned if the associated snapshot is already stale or +// the requested account is not yet covered by the snapshot. +// +// The returned account might be nil if it's not existent. +func (r *historicReader) Account(addr common.Address) (*types.StateAccount, error) { + account, err := r.reader.Account(addr) + if err != nil { + return nil, err + } + if account == nil { + return nil, nil + } + acct := &types.StateAccount{ + Nonce: account.Nonce, + Balance: account.Balance, + CodeHash: account.CodeHash, + Root: common.BytesToHash(account.Root), + } + if len(acct.CodeHash) == 0 { + acct.CodeHash = types.EmptyCodeHash.Bytes() + } + if acct.Root == (common.Hash{}) { + acct.Root = types.EmptyRootHash + } + return acct, nil +} + +// Storage implements StateReader, retrieving the storage slot specified by the +// address and slot key. +// +// An error will be returned if the associated snapshot is already stale or +// the requested storage slot is not yet covered by the snapshot. +// +// The returned storage slot might be empty if it's not existent. +func (r *historicReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) { + blob, err := r.reader.Storage(addr, key) + if err != nil { + return common.Hash{}, err + } + if len(blob) == 0 { + return common.Hash{}, nil + } + _, content, _, err := rlp.Split(blob) + if err != nil { + return common.Hash{}, err + } + var slot common.Hash + slot.SetBytes(content) + return slot, nil +} + +// HistoricDB is the implementation of Database interface, with the ability to +// access historical state. +type HistoricDB struct { + disk ethdb.KeyValueStore + triedb *triedb.Database + codeCache *lru.SizeConstrainedCache[common.Hash, []byte] + codeSizeCache *lru.Cache[common.Hash, int] + pointCache *utils.PointCache +} + +// NewHistoricDatabase creates a historic state database. +func NewHistoricDatabase(disk ethdb.KeyValueStore, triedb *triedb.Database) *HistoricDB { + return &HistoricDB{ + disk: disk, + triedb: triedb, + codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), + codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), + pointCache: utils.NewPointCache(pointCacheSize), + } +} + +// Reader implements Database interface, returning a reader of the specific state. +func (db *HistoricDB) Reader(stateRoot common.Hash) (Reader, error) { + hr, err := db.triedb.HistoricReader(stateRoot) + if err != nil { + return nil, err + } + return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), newHistoricReader(hr)), nil +} + +// OpenTrie opens the main account trie. It's not supported by historic database. +func (db *HistoricDB) OpenTrie(root common.Hash) (Trie, error) { + return nil, errors.New("not implemented") +} + +// OpenStorageTrie opens the storage trie of an account. It's not supported by +// historic database. +func (db *HistoricDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error) { + return nil, errors.New("not implemented") +} + +// PointCache returns the cache holding points used in verkle tree key computation +func (db *HistoricDB) PointCache() *utils.PointCache { + return db.pointCache +} + +// TrieDB returns the underlying trie database for managing trie nodes. +func (db *HistoricDB) TrieDB() *triedb.Database { + return db.triedb +} + +// Snapshot returns the underlying state snapshot. +func (db *HistoricDB) Snapshot() *snapshot.Tree { + return nil +} diff --git a/eth/api_backend.go b/eth/api_backend.go index 8ec19308f9..99fd4c0aa0 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -238,7 +238,10 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B } stateDb, err := b.eth.BlockChain().StateAt(header.Root) if err != nil { - return nil, nil, err + stateDb, err = b.eth.BlockChain().HistoricState(header.Root) + if err != nil { + return nil, nil, err + } } return stateDb, header, nil } @@ -260,7 +263,10 @@ func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockN } stateDb, err := b.eth.BlockChain().StateAt(header.Root) if err != nil { - return nil, nil, err + stateDb, err = b.eth.BlockChain().HistoricState(header.Root) + if err != nil { + return nil, nil, err + } } return stateDb, header, nil } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 3c3e79a584..79c91043a3 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -182,10 +182,11 @@ func (eth *Ethereum) pathState(block *types.Block) (*state.StateDB, func(), erro if err == nil { return statedb, noopReleaser, nil } - // TODO historic state is not supported in path-based scheme. - // Fully archive node in pbss will be implemented by relying - // on state history, but needs more work on top. - return nil, nil, errors.New("historical state not available in path scheme yet") + statedb, err = eth.blockchain.HistoricState(block.Root()) + if err == nil { + return statedb, noopReleaser, nil + } + return nil, nil, errors.New("historical state is not available") } // stateAtBlock retrieves the state database associated with a certain block. diff --git a/triedb/database.go b/triedb/database.go index 03d07c1c1b..12b8856d32 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -129,6 +129,15 @@ func (db *Database) StateReader(blockRoot common.Hash) (database.StateReader, er return db.backend.StateReader(blockRoot) } +// HistoricReader constructs a reader for accessing the requested historic state. +func (db *Database) HistoricReader(root common.Hash) (*pathdb.HistoricalStateReader, error) { + pdb, ok := db.backend.(*pathdb.Database) + if !ok { + return nil, errors.New("not supported") + } + return pdb.HistoricReader(root) +} + // Update performs a state transition by committing dirty nodes contained in the // given set in order to update state from the specified parent to the specified // root. The held pre-images accumulated up to this point will be flushed in case diff --git a/triedb/pathdb/history_indexer.go b/triedb/pathdb/history_indexer.go index 75bba5399a..577eb86b78 100644 --- a/triedb/pathdb/history_indexer.go +++ b/triedb/pathdb/history_indexer.go @@ -504,7 +504,7 @@ func (i *indexIniter) index(done chan struct{}, interrupt *atomic.Int32, lastID ) // Override the ETA if larger than the largest until now eta := time.Duration(left/speed) * time.Millisecond - log.Info("Indexing state history", "processed", done, "left", left, "eta", common.PrettyDuration(eta)) + log.Info("Indexing state history", "processed", done, "left", left, "elapsed", common.PrettyDuration(time.Since(start)), "eta", common.PrettyDuration(eta)) } } // Check interruption signal and abort process if it's fired From 36bcc24fbe1b50f641564b5dfa730523a6b0bb94 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 26 Jun 2025 23:19:02 +0800 Subject: [PATCH 03/14] triedb/pathdb: fix journal resolution in pathdb (#32097) This pull request fixes a flaw in the PBSS state iterator, which could return empty account or storage data. In PBSS, multiple in-memory diff layers and a write buffer are maintained. These layers are persisted to the database and reloaded after node restarts. However, since the state data is encoded using RLP, the distinction between nil and an empty byte slice is lost during the encode/decode process. As a result, invalid state values such as `[]byte{}` can appear in PBSS and ultimately be returned by the state iterator. Checkout https://github.com/ethereum/go-ethereum/blob/master/triedb/pathdb/iterator_fast.go#L270 for more iterator details. It's a long-term existent issue and now be activated since the snapshot integration. The error `err="range contains deletion"` will occur when Geth tries to serve other peers with SNAP protocol request. --------- Co-authored-by: Felix Lange --- triedb/pathdb/iterator_test.go | 93 +++++++++++++++++++++++++++------- triedb/pathdb/states.go | 23 ++++++--- 2 files changed, 91 insertions(+), 25 deletions(-) diff --git a/triedb/pathdb/iterator_test.go b/triedb/pathdb/iterator_test.go index b24575cb47..adb534f47d 100644 --- a/triedb/pathdb/iterator_test.go +++ b/triedb/pathdb/iterator_test.go @@ -816,7 +816,8 @@ func testAccountIteratorDeletions(t *testing.T, newIterator func(db *Database, r config := &Config{ NoAsyncGeneration: true, } - db := New(rawdb.NewMemoryDatabase(), config, false) + memoryDB := rawdb.NewMemoryDatabase() + db := New(memoryDB, config, false) // Stack three diff layers on top with various overlaps db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), @@ -831,31 +832,55 @@ func testAccountIteratorDeletions(t *testing.T, newIterator func(db *Database, r db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0x33", "0x44", "0x55"), nil, nil, nil, false)) - // The output should be 11,33,44,55 - it := newIterator(db, common.HexToHash("0x04"), common.Hash{}) - // Do a quick check - verifyIterator(t, 4, it, verifyAccount) - it.Release() + verify := func() { + // The output should be 11,33,44,55 + it := newIterator(db, common.HexToHash("0x04"), common.Hash{}) + // Do a quick check + verifyIterator(t, 4, it, verifyAccount) + it.Release() - // And a more detailed verification that we indeed do not see '0x22' - it = newIterator(db, common.HexToHash("0x04"), common.Hash{}) - defer it.Release() - for it.Next() { - hash := it.Hash() - if it.Account() == nil { - t.Errorf("iterator returned nil-value for hash %x", hash) - } - if hash == deleted { - t.Errorf("expected deleted elem %x to not be returned by iterator", deleted) + // And a more detailed verification that we indeed do not see '0x22' + it = newIterator(db, common.HexToHash("0x04"), common.Hash{}) + defer it.Release() + for it.Next() { + hash := it.Hash() + if it.Account() == nil { + t.Errorf("iterator returned nil-value for hash %x", hash) + } + if hash == deleted { + t.Errorf("expected deleted elem %x to not be returned by iterator", deleted) + } } } + verify() + + if err := db.Journal(common.HexToHash("0x04")); err != nil { + t.Fatalf("Failed to journal the database, %v", err) + } + if err := db.Close(); err != nil { + t.Fatalf("Failed to close the database, %v", err) + } + db = New(memoryDB, config, false) + + verify() } func TestStorageIteratorDeletions(t *testing.T) { config := &Config{ NoAsyncGeneration: true, } - db := New(rawdb.NewMemoryDatabase(), config, false) + memoryDB := rawdb.NewMemoryDatabase() + db := New(memoryDB, config, false) + + restart := func(head common.Hash) { + if err := db.Journal(head); err != nil { + t.Fatalf("Failed to journal the database, %v", err) + } + if err := db.Close(); err != nil { + t.Fatalf("Failed to close the database, %v", err) + } + db = New(memoryDB, config, false) + } // Stack three diff layers on top with various overlaps db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), @@ -874,6 +899,19 @@ func TestStorageIteratorDeletions(t *testing.T) { verifyIterator(t, 3, it, verifyStorage) it.Release() + // Ensure the iteration result aligns after the database restart + restart(common.HexToHash("0x03")) + + // The output should be 02,04,05,06 + it, _ = db.StorageIterator(common.HexToHash("0x03"), common.HexToHash("0xaa"), common.Hash{}) + verifyIterator(t, 4, it, verifyStorage) + it.Release() + + // The output should be 04,05,06 + it, _ = db.StorageIterator(common.HexToHash("0x03"), common.HexToHash("0xaa"), common.HexToHash("0x03")) + verifyIterator(t, 3, it, verifyStorage) + it.Release() + // Destruct the whole storage accounts := map[common.Hash][]byte{ common.HexToHash("0xaa"): nil, @@ -885,6 +923,12 @@ func TestStorageIteratorDeletions(t *testing.T) { verifyIterator(t, 0, it, verifyStorage) it.Release() + // Ensure the iteration result aligns after the database restart + restart(common.HexToHash("0x04")) + it, _ = db.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{}) + verifyIterator(t, 0, it, verifyStorage) + it.Release() + // Re-insert the slots of the same account db.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), 4, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil), nil, nil, false)) @@ -894,6 +938,14 @@ func TestStorageIteratorDeletions(t *testing.T) { verifyIterator(t, 3, it, verifyStorage) it.Release() + // Ensure the iteration result aligns after the database restart + restart(common.HexToHash("0x05")) + + // The output should be 07,08,09 + it, _ = db.StorageIterator(common.HexToHash("0x05"), common.HexToHash("0xaa"), common.Hash{}) + verifyIterator(t, 3, it, verifyStorage) + it.Release() + // Destruct the whole storage but re-create the account in the same layer db.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), 5, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, [][]string{{"0x07", "0x08", "0x09"}}), nil, nil, false)) @@ -903,6 +955,13 @@ func TestStorageIteratorDeletions(t *testing.T) { it.Release() verifyIterator(t, 2, db.tree.get(common.HexToHash("0x06")).(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa"), common.Hash{}), verifyStorage) + + // Ensure the iteration result aligns after the database restart + restart(common.HexToHash("0x06")) + it, _ = db.StorageIterator(common.HexToHash("0x06"), common.HexToHash("0xaa"), common.Hash{}) + verifyIterator(t, 2, it, verifyStorage) // The output should be 11,12 + it.Release() + verifyIterator(t, 2, db.tree.get(common.HexToHash("0x06")).(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa"), common.Hash{}), verifyStorage) } // TestStaleIterator tests if the iterator could correctly terminate the iteration diff --git a/triedb/pathdb/states.go b/triedb/pathdb/states.go index 2a88d74f5f..bc638a569e 100644 --- a/triedb/pathdb/states.go +++ b/triedb/pathdb/states.go @@ -387,8 +387,8 @@ func (s *stateSet) decode(r *rlp.Stream) error { if err := r.Decode(&dec); err != nil { return fmt.Errorf("load diff accounts: %v", err) } - for i := 0; i < len(dec.AddrHashes); i++ { - accountSet[dec.AddrHashes[i]] = dec.Accounts[i] + for i := range dec.AddrHashes { + accountSet[dec.AddrHashes[i]] = empty2nil(dec.Accounts[i]) } s.accountData = accountSet @@ -407,8 +407,8 @@ func (s *stateSet) decode(r *rlp.Stream) error { } for _, entry := range storages { storageSet[entry.AddrHash] = make(map[common.Hash][]byte, len(entry.Keys)) - for i := 0; i < len(entry.Keys); i++ { - storageSet[entry.AddrHash][entry.Keys[i]] = entry.Vals[i] + for i := range entry.Keys { + storageSet[entry.AddrHash][entry.Keys[i]] = empty2nil(entry.Vals[i]) } } s.storageData = storageSet @@ -550,8 +550,8 @@ func (s *StateSetWithOrigin) decode(r *rlp.Stream) error { if err := r.Decode(&accounts); err != nil { return fmt.Errorf("load diff account origin set: %v", err) } - for i := 0; i < len(accounts.Accounts); i++ { - accountSet[accounts.Addresses[i]] = accounts.Accounts[i] + for i := range accounts.Accounts { + accountSet[accounts.Addresses[i]] = empty2nil(accounts.Accounts[i]) } s.accountOrigin = accountSet @@ -570,10 +570,17 @@ func (s *StateSetWithOrigin) decode(r *rlp.Stream) error { } for _, storage := range storages { storageSet[storage.Address] = make(map[common.Hash][]byte) - for i := 0; i < len(storage.Keys); i++ { - storageSet[storage.Address][storage.Keys[i]] = storage.Vals[i] + for i := range storage.Keys { + storageSet[storage.Address][storage.Keys[i]] = empty2nil(storage.Vals[i]) } } s.storageOrigin = storageSet return nil } + +func empty2nil(b []byte) []byte { + if len(b) == 0 { + return nil + } + return b +} From 0c90e4bda04a84929002dfb80a640026633e0542 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 26 Jun 2025 23:20:20 +0800 Subject: [PATCH 04/14] all: incorporate state history indexing status into eth_syncing response (#32099) This pull request tracks the state indexing progress in eth_syncing RPC response, i.e. we will return non-null syncing status until indexing has finished. --- core/blockchain_reader.go | 5 ++++ eth/api_backend.go | 4 +++ eth/downloader/api.go | 4 +++ ethclient/ethclient.go | 2 ++ graphql/graphql.go | 3 +++ interfaces.go | 5 +++- internal/ethapi/api.go | 1 + internal/jsre/deps/web3.js | 1 + triedb/database.go | 10 +++++++ triedb/pathdb/database.go | 9 +++++++ triedb/pathdb/history_indexer.go | 46 +++++++++++++++++++++++++++++++- 11 files changed, 88 insertions(+), 2 deletions(-) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 046d96063d..0734baab35 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -426,6 +426,11 @@ func (bc *BlockChain) TxIndexProgress() (TxIndexProgress, error) { return bc.txIndexer.txIndexProgress(), nil } +// StateIndexProgress returns the historical state indexing progress. +func (bc *BlockChain) StateIndexProgress() (uint64, error) { + return bc.triedb.IndexProgress() +} + // HistoryPruningCutoff returns the configured history pruning point. // Blocks before this might not be available in the database. func (bc *BlockChain) HistoryPruningCutoff() (uint64, common.Hash) { diff --git a/eth/api_backend.go b/eth/api_backend.go index 99fd4c0aa0..bd90f611f1 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -403,6 +403,10 @@ func (b *EthAPIBackend) SyncProgress(ctx context.Context) ethereum.SyncProgress prog.TxIndexFinishedBlocks = txProg.Indexed prog.TxIndexRemainingBlocks = txProg.Remaining } + remain, err := b.eth.blockchain.StateIndexProgress() + if err == nil { + prog.StateIndexRemaining = remain + } return prog } diff --git a/eth/downloader/api.go b/eth/downloader/api.go index ac175672a0..c98f9a2c3f 100644 --- a/eth/downloader/api.go +++ b/eth/downloader/api.go @@ -81,6 +81,10 @@ func (api *DownloaderAPI) eventLoop() { prog.TxIndexFinishedBlocks = txProg.Indexed prog.TxIndexRemainingBlocks = txProg.Remaining } + remain, err := api.chain.StateIndexProgress() + if err == nil { + prog.StateIndexRemaining = remain + } return prog } ) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 9d0e0d5b52..1195929f7d 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -789,6 +789,7 @@ type rpcProgress struct { HealingBytecode hexutil.Uint64 TxIndexFinishedBlocks hexutil.Uint64 TxIndexRemainingBlocks hexutil.Uint64 + StateIndexRemaining hexutil.Uint64 } func (p *rpcProgress) toSyncProgress() *ethereum.SyncProgress { @@ -815,5 +816,6 @@ func (p *rpcProgress) toSyncProgress() *ethereum.SyncProgress { HealingBytecode: uint64(p.HealingBytecode), TxIndexFinishedBlocks: uint64(p.TxIndexFinishedBlocks), TxIndexRemainingBlocks: uint64(p.TxIndexRemainingBlocks), + StateIndexRemaining: uint64(p.StateIndexRemaining), } } diff --git a/graphql/graphql.go b/graphql/graphql.go index e23e6fcb0e..6738cd913b 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -1510,6 +1510,9 @@ func (s *SyncState) TxIndexFinishedBlocks() hexutil.Uint64 { func (s *SyncState) TxIndexRemainingBlocks() hexutil.Uint64 { return hexutil.Uint64(s.progress.TxIndexRemainingBlocks) } +func (s *SyncState) StateIndexRemaining() hexutil.Uint64 { + return hexutil.Uint64(s.progress.StateIndexRemaining) +} // Syncing returns false in case the node is currently not syncing with the network. It can be up-to-date or has not // yet received the latest block headers from its peers. In case it is synchronizing: diff --git a/interfaces.go b/interfaces.go index 54a215d6e7..be5b970851 100644 --- a/interfaces.go +++ b/interfaces.go @@ -124,6 +124,9 @@ type SyncProgress struct { // "transaction indexing" fields TxIndexFinishedBlocks uint64 // Number of blocks whose transactions are already indexed TxIndexRemainingBlocks uint64 // Number of blocks whose transactions are not indexed yet + + // "historical state indexing" fields + StateIndexRemaining uint64 // Number of states remain unindexed } // Done returns the indicator if the initial sync is finished or not. @@ -131,7 +134,7 @@ func (prog SyncProgress) Done() bool { if prog.CurrentBlock < prog.HighestBlock { return false } - return prog.TxIndexRemainingBlocks == 0 + return prog.TxIndexRemainingBlocks == 0 && prog.StateIndexRemaining == 0 } // ChainSyncReader wraps access to the node's current sync status. If there's no diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index db0297ae5a..8f9442acee 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -170,6 +170,7 @@ func (api *EthereumAPI) Syncing(ctx context.Context) (interface{}, error) { "healingBytecode": hexutil.Uint64(progress.HealingBytecode), "txIndexFinishedBlocks": hexutil.Uint64(progress.TxIndexFinishedBlocks), "txIndexRemainingBlocks": hexutil.Uint64(progress.TxIndexRemainingBlocks), + "stateIndexRemaining": hexutil.Uint64(progress.StateIndexRemaining), }, nil } diff --git a/internal/jsre/deps/web3.js b/internal/jsre/deps/web3.js index 0aa738a2af..0071d7eb7d 100644 --- a/internal/jsre/deps/web3.js +++ b/internal/jsre/deps/web3.js @@ -3977,6 +3977,7 @@ var outputSyncingFormatter = function(result) { result.healingBytecode = utils.toDecimal(result.healingBytecode); result.txIndexFinishedBlocks = utils.toDecimal(result.txIndexFinishedBlocks); result.txIndexRemainingBlocks = utils.toDecimal(result.txIndexRemainingBlocks); + result.stateIndexRemaining = utils.toDecimal(result.stateIndexRemaining) return result; }; diff --git a/triedb/database.go b/triedb/database.go index 12b8856d32..e2f4334d6e 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -356,6 +356,16 @@ func (db *Database) StorageIterator(root common.Hash, account common.Hash, seek return pdb.StorageIterator(root, account, seek) } +// IndexProgress returns the indexing progress made so far. It provides the +// number of states that remain unindexed. +func (db *Database) IndexProgress() (uint64, error) { + pdb, ok := db.backend.(*pathdb.Database) + if !ok { + return 0, errors.New("not supported") + } + return pdb.IndexProgress() +} + // IsVerkle returns the indicator if the database is holding a verkle tree. func (db *Database) IsVerkle() bool { return db.config.IsVerkle diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 8932f3f7f8..7c8c327484 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -700,6 +700,15 @@ func (db *Database) HistoryRange() (uint64, uint64, error) { return historyRange(db.freezer) } +// IndexProgress returns the indexing progress made so far. It provides the +// number of states that remain unindexed. +func (db *Database) IndexProgress() (uint64, error) { + if db.indexer == nil { + return 0, nil + } + return db.indexer.progress() +} + // AccountIterator creates a new account iterator for the specified root hash and // seeks to a starting account hash. func (db *Database) AccountIterator(root common.Hash, seek common.Hash) (AccountIterator, error) { diff --git a/triedb/pathdb/history_indexer.go b/triedb/pathdb/history_indexer.go index 577eb86b78..6df74de61c 100644 --- a/triedb/pathdb/history_indexer.go +++ b/triedb/pathdb/history_indexer.go @@ -305,7 +305,12 @@ type indexIniter struct { interrupt chan *interruptSignal done chan struct{} closed chan struct{} - wg sync.WaitGroup + + // indexing progress + indexed atomic.Uint64 // the id of latest indexed state + last atomic.Uint64 // the id of the target state to be indexed + + wg sync.WaitGroup } func newIndexIniter(disk ethdb.KeyValueStore, freezer ethdb.AncientStore, lastID uint64) *indexIniter { @@ -316,6 +321,14 @@ func newIndexIniter(disk ethdb.KeyValueStore, freezer ethdb.AncientStore, lastID done: make(chan struct{}), closed: make(chan struct{}), } + // Load indexing progress + initer.last.Store(lastID) + metadata := loadIndexMetadata(disk) + if metadata != nil { + initer.indexed.Store(metadata.Last) + } + + // Launch background indexer initer.wg.Add(1) go initer.run(lastID) return initer @@ -342,6 +355,22 @@ func (i *indexIniter) inited() bool { } } +func (i *indexIniter) remain() uint64 { + select { + case <-i.closed: + return 0 + case <-i.done: + return 0 + default: + last, indexed := i.last.Load(), i.indexed.Load() + if last < indexed { + log.Error("Invalid state indexing range", "last", last, "indexed", indexed) + return 0 + } + return last - indexed + } +} + func (i *indexIniter) run(lastID uint64) { defer i.wg.Done() @@ -367,6 +396,8 @@ func (i *indexIniter) run(lastID uint64) { signal.result <- fmt.Errorf("invalid history id, last: %d, got: %d", lastID, signal.newLastID) continue } + i.last.Store(signal.newLastID) // update indexing range + // The index limit is extended by one, update the limit without // interrupting the current background process. if signal.newLastID == lastID+1 { @@ -507,6 +538,8 @@ func (i *indexIniter) index(done chan struct{}, interrupt *atomic.Int32, lastID log.Info("Indexing state history", "processed", done, "left", left, "elapsed", common.PrettyDuration(time.Since(start)), "eta", common.PrettyDuration(eta)) } } + i.indexed.Store(current - 1) // update indexing progress + // Check interruption signal and abort process if it's fired if interrupt != nil { if signal := interrupt.Load(); signal != 0 { @@ -617,3 +650,14 @@ func (i *historyIndexer) shorten(historyID uint64) error { return <-signal.result } } + +// progress returns the indexing progress made so far. It provides the number +// of states that remain unindexed. +func (i *historyIndexer) progress() (uint64, error) { + select { + case <-i.initer.closed: + return 0, errors.New("indexer is closed") + default: + return i.initer.remain(), nil + } +} From 57f8971b89b3ce3d31ec09d6a1e29151c90e7d19 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 26 Jun 2025 20:54:41 +0200 Subject: [PATCH 05/14] version: release go-ethereum v1.16.0 stable --- version/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/version/version.go b/version/version.go index 51cf410cda..a4c74ac103 100644 --- a/version/version.go +++ b/version/version.go @@ -17,8 +17,8 @@ package version const ( - Major = 1 // Major version component of the current release - Minor = 15 // Minor version component of the current release - Patch = 12 // Patch version component of the current release - Meta = "unstable" // Version metadata to append to the version string + Major = 1 // Major version component of the current release + Minor = 16 // Minor version component of the current release + Patch = 0 // Patch version component of the current release + Meta = "stable" // Version metadata to append to the version string ) From 3941fe0a5fe0db68fba03a509a9f38e7ba91778f Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 26 Jun 2025 20:58:52 +0200 Subject: [PATCH 06/14] version: begin v1.16.1 release cycle --- version/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/version/version.go b/version/version.go index a4c74ac103..750fa5a352 100644 --- a/version/version.go +++ b/version/version.go @@ -17,8 +17,8 @@ package version const ( - Major = 1 // Major version component of the current release - Minor = 16 // Minor version component of the current release - Patch = 0 // Patch version component of the current release - Meta = "stable" // Version metadata to append to the version string + Major = 1 // Major version component of the current release + Minor = 16 // Minor version component of the current release + Patch = 1 // Patch version component of the current release + Meta = "unstable" // Version metadata to append to the version string ) From 094db92d68f883284ba92708b67795eda6c40782 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 26 Jun 2025 21:29:59 +0200 Subject: [PATCH 07/14] .gitea: trigger PPA upload on tag --- .gitea/workflows/release-ppa.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/release-ppa.yml b/.gitea/workflows/release-ppa.yml index f164f85931..34b6be4b83 100644 --- a/.gitea/workflows/release-ppa.yml +++ b/.gitea/workflows/release-ppa.yml @@ -2,8 +2,8 @@ on: schedule: - cron: '0 16 * * *' push: - branches: - - "release/*" + tags: + - "v*" workflow_dispatch: jobs: From 668c3a7278af399c0e776e92f1c721b5158388f2 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 26 Jun 2025 22:02:50 +0200 Subject: [PATCH 08/14] .travis.yml: remove travis configuration --- .travis.yml | 86 ----------------------------------------------------- 1 file changed, 86 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 28d934c655..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,86 +0,0 @@ -language: go -go_import_path: github.com/ethereum/go-ethereum -sudo: false -jobs: - include: - # This builder create and push the Docker images for all architectures - - stage: build - if: type = push && tag ~= /^v[0-9]/ - os: linux - arch: amd64 - dist: focal - go: 1.24.x - env: - - docker - services: - - docker - git: - submodules: false # avoid cloning ethereum/tests - before_install: - - export DOCKER_CLI_EXPERIMENTAL=enabled - script: - - go run build/ci.go dockerx -platform "linux/amd64,linux/arm64,linux/riscv64" -hub ethereum/client-go -upload - - # This builder does the Ubuntu PPA nightly uploads - - stage: build - if: type = push && tag ~= /^v[0-9]/ - os: linux - dist: focal - go: 1.24.x - env: - - ubuntu-ppa - git: - submodules: false # avoid cloning ethereum/tests - before_install: - - sudo -E apt-get -yq --no-install-suggests --no-install-recommends install devscripts debhelper dput fakeroot - script: - - echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts - - go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder " - - # This builder does the Linux Azure uploads - - stage: build - if: type = push && tag ~= /^v[0-9]/ - os: linux - dist: focal - sudo: required - go: 1.24.x - env: - - azure-linux - git: - submodules: false # avoid cloning ethereum/tests - script: - # build amd64 - - go run build/ci.go install -dlgo - - go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - - # build 386 - - sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib - - git status --porcelain - - go run build/ci.go install -dlgo -arch 386 - - go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - - # Switch over GCC to cross compilation (breaks 386, hence why do it here only) - - sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-arm-linux-gnueabihf libc6-dev-armhf-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross - - sudo ln -s /usr/include/asm-generic /usr/include/asm - - - GOARM=5 go run build/ci.go install -dlgo -arch arm -cc arm-linux-gnueabi-gcc - - GOARM=5 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - - GOARM=6 go run build/ci.go install -dlgo -arch arm -cc arm-linux-gnueabi-gcc - - GOARM=6 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - - GOARM=7 go run build/ci.go install -dlgo -arch arm -cc arm-linux-gnueabihf-gcc - - GOARM=7 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - - go run build/ci.go install -dlgo -arch arm64 -cc aarch64-linux-gnu-gcc - - go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - - # This builder does the Azure archive purges to avoid accumulating junk - - stage: build - if: type = cron - os: linux - dist: focal - go: 1.24.x - env: - - azure-purge - git: - submodules: false # avoid cloning ethereum/tests - script: - - go run build/ci.go purge -store gethstore/builds -days 14 From 8e17b371fdf25fbd6caf9da54ede982488bff172 Mon Sep 17 00:00:00 2001 From: Delweng Date: Fri, 27 Jun 2025 15:18:05 +0800 Subject: [PATCH 09/14] all: replace override.prague with osaka (#32093) replace `--override.prague` with `--override.osaka` Signed-off-by: jsvisa --- cmd/geth/chaincmd.go | 8 ++++---- cmd/geth/config.go | 6 +++--- cmd/geth/main.go | 2 +- cmd/utils/flags.go | 6 +++--- core/genesis.go | 6 +++--- eth/backend.go | 4 ++-- eth/ethconfig/config.go | 4 ++-- eth/ethconfig/gen_config.go | 10 +++++----- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index fafdfe2f07..acd7b5c230 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -58,7 +58,7 @@ var ( ArgsUsage: "", Flags: slices.Concat([]cli.Flag{ utils.CachePreimagesFlag, - utils.OverridePrague, + utils.OverrideOsaka, utils.OverrideVerkle, }, utils.DatabaseFlags), Description: ` @@ -269,9 +269,9 @@ func initGenesis(ctx *cli.Context) error { defer stack.Close() var overrides core.ChainOverrides - if ctx.IsSet(utils.OverridePrague.Name) { - v := ctx.Uint64(utils.OverridePrague.Name) - overrides.OverridePrague = &v + if ctx.IsSet(utils.OverrideOsaka.Name) { + v := ctx.Uint64(utils.OverrideOsaka.Name) + overrides.OverrideOsaka = &v } if ctx.IsSet(utils.OverrideVerkle.Name) { v := ctx.Uint64(utils.OverrideVerkle.Name) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 3eb2b6dd37..fff1a67cef 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -223,9 +223,9 @@ func constructDevModeBanner(ctx *cli.Context, cfg gethConfig) string { // makeFullNode loads geth configuration and creates the Ethereum backend. func makeFullNode(ctx *cli.Context) *node.Node { stack, cfg := makeConfigNode(ctx) - if ctx.IsSet(utils.OverridePrague.Name) { - v := ctx.Uint64(utils.OverridePrague.Name) - cfg.Eth.OverridePrague = &v + if ctx.IsSet(utils.OverrideOsaka.Name) { + v := ctx.Uint64(utils.OverrideOsaka.Name) + cfg.Eth.OverrideOsaka = &v } if ctx.IsSet(utils.OverrideVerkle.Name) { v := ctx.Uint64(utils.OverrideVerkle.Name) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 289af90828..2da5c43216 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -62,7 +62,7 @@ var ( utils.NoUSBFlag, // deprecated utils.USBFlag, utils.SmartCardDaemonPathFlag, - utils.OverridePrague, + utils.OverrideOsaka, utils.OverrideVerkle, utils.EnablePersonal, // deprecated utils.TxPoolLocalsFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 3747e2c70b..ed594e40bd 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -243,9 +243,9 @@ var ( Value: 2048, Category: flags.EthCategory, } - OverridePrague = &cli.Uint64Flag{ - Name: "override.prague", - Usage: "Manually specify the Prague fork timestamp, overriding the bundled setting", + OverrideOsaka = &cli.Uint64Flag{ + Name: "override.osaka", + Usage: "Manually specify the Osaka fork timestamp, overriding the bundled setting", Category: flags.EthCategory, } OverrideVerkle = &cli.Uint64Flag{ diff --git a/core/genesis.go b/core/genesis.go index 080f8a3c5f..f1a620da57 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -258,7 +258,7 @@ func (e *GenesisMismatchError) Error() string { // ChainOverrides contains the changes to chain config. type ChainOverrides struct { - OverridePrague *uint64 + OverrideOsaka *uint64 OverrideVerkle *uint64 } @@ -267,8 +267,8 @@ func (o *ChainOverrides) apply(cfg *params.ChainConfig) error { if o == nil || cfg == nil { return nil } - if o.OverridePrague != nil { - cfg.PragueTime = o.OverridePrague + if o.OverrideOsaka != nil { + cfg.OsakaTime = o.OverrideOsaka } if o.OverrideVerkle != nil { cfg.VerkleTime = o.OverrideVerkle diff --git a/eth/backend.go b/eth/backend.go index 4b08707d2f..8f2b803c86 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -253,8 +253,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } // Override the chain config with provided settings. var overrides core.ChainOverrides - if config.OverridePrague != nil { - overrides.OverridePrague = config.OverridePrague + if config.OverrideOsaka != nil { + overrides.OverrideOsaka = config.OverrideOsaka } if config.OverrideVerkle != nil { overrides.OverrideVerkle = config.OverrideVerkle diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index b6029d4974..97d23744a0 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -158,8 +158,8 @@ type Config struct { // send-transaction variants. The unit is ether. RPCTxFeeCap float64 - // OverridePrague (TODO: remove after the fork) - OverridePrague *uint64 `toml:",omitempty"` + // OverrideOsaka (TODO: remove after the fork) + OverrideOsaka *uint64 `toml:",omitempty"` // OverrideVerkle (TODO: remove after the fork) OverrideVerkle *uint64 `toml:",omitempty"` diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 05f07178ac..0a188ba23c 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -54,7 +54,7 @@ func (c Config) MarshalTOML() (interface{}, error) { RPCGasCap uint64 RPCEVMTimeout time.Duration RPCTxFeeCap float64 - OverridePrague *uint64 `toml:",omitempty"` + OverrideOsaka *uint64 `toml:",omitempty"` OverrideVerkle *uint64 `toml:",omitempty"` } var enc Config @@ -95,7 +95,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCGasCap = c.RPCGasCap enc.RPCEVMTimeout = c.RPCEVMTimeout enc.RPCTxFeeCap = c.RPCTxFeeCap - enc.OverridePrague = c.OverridePrague + enc.OverrideOsaka = c.OverrideOsaka enc.OverrideVerkle = c.OverrideVerkle return &enc, nil } @@ -140,7 +140,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { RPCGasCap *uint64 RPCEVMTimeout *time.Duration RPCTxFeeCap *float64 - OverridePrague *uint64 `toml:",omitempty"` + OverrideOsaka *uint64 `toml:",omitempty"` OverrideVerkle *uint64 `toml:",omitempty"` } var dec Config @@ -258,8 +258,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.RPCTxFeeCap != nil { c.RPCTxFeeCap = *dec.RPCTxFeeCap } - if dec.OverridePrague != nil { - c.OverridePrague = dec.OverridePrague + if dec.OverrideOsaka != nil { + c.OverrideOsaka = dec.OverrideOsaka } if dec.OverrideVerkle != nil { c.OverrideVerkle = dec.OverrideVerkle From aa1de057201f510d8dc8135e083435148f997226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Irmak?= Date: Fri, 27 Jun 2025 10:27:52 +0300 Subject: [PATCH 10/14] node: do not double-wrap KV stores (#32089) For no apparent reason, KV stores were getting wrapped in `nofreezedb` first and then in `freezerdb`. --- node/database.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/database.go b/node/database.go index 44bea10307..274ccbfa7e 100644 --- a/node/database.go +++ b/node/database.go @@ -109,7 +109,7 @@ func newLevelDBDatabase(file string, cache int, handles int, namespace string, r return nil, err } log.Info("Using LevelDB as the backing database") - return rawdb.NewDatabase(db), nil + return db, nil } // newPebbleDBDatabase creates a persistent key-value database without a freezer @@ -119,5 +119,5 @@ func newPebbleDBDatabase(file string, cache int, handles int, namespace string, if err != nil { return nil, err } - return rawdb.NewDatabase(db), nil + return db, nil } From 663fa7b49603442ba897d79c77ad912ebf2950fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Duchesneau?= Date: Fri, 27 Jun 2025 18:56:20 -0400 Subject: [PATCH 11/14] eth: correct tracer initialization in BlockchainConfig (#32107) core.BlockChainConfig.VmConfig is not a pointer, so setting the Tracer on the `vmConfig` object after it was passed to options does *not* apply it to options.VmConfig This fixes the issue by setting the value directly inside the `options` object and removing the confusing `vmConfig` variable to prevent further mistakes. --- eth/backend.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 8f2b803c86..f7105ab79c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -221,9 +221,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } } var ( - vmConfig = vm.Config{ - EnablePreimageRecording: config.EnablePreimageRecording, - } options = &core.BlockChainConfig{ TrieCleanLimit: config.TrieCleanCache, NoPrefetch: config.NoPrefetch, @@ -236,7 +233,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { StateScheme: scheme, ChainHistoryMode: config.HistoryMode, TxLookupLimit: int64(min(config.TransactionHistory, math.MaxInt64)), - VmConfig: vmConfig, + VmConfig: vm.Config{ + EnablePreimageRecording: config.EnablePreimageRecording, + }, } ) @@ -249,7 +248,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, fmt.Errorf("failed to create tracer %s: %v", config.VMTrace, err) } - vmConfig.Tracer = t + options.VmConfig.Tracer = t } // Override the chain config with provided settings. var overrides core.ChainOverrides From 158118f6d8565c1f1368e27513d6fa1496754230 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 30 Jun 2025 09:53:52 +0200 Subject: [PATCH 12/14] .gitea: switch release builds to static linking (#32118) This is to avoid compatibility issues with mismatched glibc versions between the builder and deployment target. Fixes #32102 --- .gitea/workflows/release.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 04e724ccf4..25dfe359c8 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -25,7 +25,7 @@ jobs: - name: Build (amd64) run: | - go run build/ci.go install -arch amd64 -dlgo + go run build/ci.go install -static -arch amd64 -dlgo - name: Create/upload archive (amd64) run: | @@ -37,11 +37,11 @@ jobs: - name: Build (386) run: | - go run build/ci.go install -arch 386 -dlgo + go run build/ci.go install -static -arch 386 -dlgo - name: Create/upload archive (386) run: | - go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds + go run build/ci.go archive -static -arch 386 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds rm -f build/bin/* env: LINUX_SIGNING_KEY: ${{ secrets.LINUX_SIGNING_KEY }} @@ -67,7 +67,7 @@ jobs: - name: Build (arm64) run: | - go run build/ci.go install -dlgo -arch arm64 -cc aarch64-linux-gnu-gcc + go run build/ci.go install -static -dlgo -arch arm64 -cc aarch64-linux-gnu-gcc - name: Create/upload archive (arm64) run: | @@ -79,7 +79,7 @@ jobs: - name: Run build (arm5) run: | - go run build/ci.go install -dlgo -arch arm -cc arm-linux-gnueabi-gcc + go run build/ci.go install -static -dlgo -arch arm -cc arm-linux-gnueabi-gcc env: GOARM: "5" @@ -93,7 +93,7 @@ jobs: - name: Run build (arm6) run: | - go run build/ci.go install -dlgo -arch arm -cc arm-linux-gnueabi-gcc + go run build/ci.go install -static -dlgo -arch arm -cc arm-linux-gnueabi-gcc env: GOARM: "6" @@ -108,7 +108,7 @@ jobs: - name: Run build (arm7) run: | - go run build/ci.go install -dlgo -arch arm -cc arm-linux-gnueabi-gcc + go run build/ci.go install -static -dlgo -arch arm -cc arm-linux-gnueabi-gcc env: GOARM: "7" From 9eed26d1b0be440c208b805b9d71296da7a50f51 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 30 Jun 2025 10:17:59 +0200 Subject: [PATCH 13/14] .gitea: fix 386 upload --- .gitea/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 25dfe359c8..f4a539b0b0 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -41,7 +41,7 @@ jobs: - name: Create/upload archive (386) run: | - go run build/ci.go archive -static -arch 386 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds + go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds rm -f build/bin/* env: LINUX_SIGNING_KEY: ${{ secrets.LINUX_SIGNING_KEY }} From 87d7c2aa125cba93e1d5b7e8eb3b3eb1327b51ba Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 30 Jun 2025 17:24:52 +0200 Subject: [PATCH 14/14] .gitea: disable cron schedule --- .gitea/workflows/release-azure-cleanup.yml | 9 +++++++-- .gitea/workflows/release-ppa.yml | 10 ++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/release-azure-cleanup.yml b/.gitea/workflows/release-azure-cleanup.yml index 4a20828d2e..0b04581e9b 100644 --- a/.gitea/workflows/release-azure-cleanup.yml +++ b/.gitea/workflows/release-azure-cleanup.yml @@ -1,8 +1,13 @@ on: - schedule: - - cron: '0 15 * * *' workflow_dispatch: + ### Note we cannot use cron-triggered builds right now, Gitea seems to have + ### a few bugs in that area. So this workflow is scheduled using an external + ### triggering mechanism and workflow_dispatch. + # + # schedule: + # - cron: '0 15 * * *' + jobs: azure-cleanup: runs-on: ubuntu-latest diff --git a/.gitea/workflows/release-ppa.yml b/.gitea/workflows/release-ppa.yml index 34b6be4b83..129badac16 100644 --- a/.gitea/workflows/release-ppa.yml +++ b/.gitea/workflows/release-ppa.yml @@ -1,11 +1,17 @@ on: - schedule: - - cron: '0 16 * * *' push: tags: - "v*" workflow_dispatch: + ### Note we cannot use cron-triggered builds right now, Gitea seems to have + ### a few bugs in that area. So this workflow is scheduled using an external + ### triggering mechanism and workflow_dispatch. + # + # schedule: + # - cron: '0 16 * * *' + + jobs: ppa: name: PPA Upload