Merge branch 'ethereum:master' into gethintegration

This commit is contained in:
Chen Kai 2025-04-26 12:40:04 +08:00 committed by GitHub
commit 8fa6e26562
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 116 additions and 30 deletions

View file

@ -41,7 +41,8 @@ var (
AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}). AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}).
AddFork("BELLATRIX", 144896, []byte{2, 0, 0, 0}). AddFork("BELLATRIX", 144896, []byte{2, 0, 0, 0}).
AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}). AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}).
AddFork("DENEB", 269568, []byte{4, 0, 0, 0}) AddFork("DENEB", 269568, []byte{4, 0, 0, 0}).
AddFork("ELECTRA", 364032, []byte{5, 0, 0, 0})
SepoliaLightConfig = (&ChainConfig{ SepoliaLightConfig = (&ChainConfig{
GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"), GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"),

View file

@ -87,10 +87,16 @@ type FilterMaps struct {
// Matcher backend can read them under indexLock read lock. // Matcher backend can read them under indexLock read lock.
indexLock sync.RWMutex indexLock sync.RWMutex
indexedRange filterMapsRange indexedRange filterMapsRange
cleanedEpochsBefore uint32 // all unindexed data cleaned before this point
indexedView *ChainView // always consistent with the log index indexedView *ChainView // always consistent with the log index
hasTempRange bool hasTempRange bool
// cleanedEpochsBefore indicates that all unindexed data before this point
// has been cleaned.
//
// This field is only accessed and modified within tryUnindexTail, so no
// explicit locking is required.
cleanedEpochsBefore uint32
// also accessed by indexer and matcher backend but no locking needed. // also accessed by indexer and matcher backend but no locking needed.
filterMapCache *lru.Cache[uint32, filterMap] filterMapCache *lru.Cache[uint32, filterMap]
lastBlockCache *lru.Cache[uint32, lastBlockOfMap] lastBlockCache *lru.Cache[uint32, lastBlockOfMap]
@ -248,6 +254,7 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, f
}, },
// deleting last unindexed epoch might have been interrupted by shutdown // deleting last unindexed epoch might have been interrupted by shutdown
cleanedEpochsBefore: max(rs.MapsFirst>>params.logMapsPerEpoch, 1) - 1, cleanedEpochsBefore: max(rs.MapsFirst>>params.logMapsPerEpoch, 1) - 1,
historyCutoff: historyCutoff, historyCutoff: historyCutoff,
finalBlock: finalBlock, finalBlock: finalBlock,
matcherSyncCh: make(chan *FilterMapsMatcherBackend), matcherSyncCh: make(chan *FilterMapsMatcherBackend),
@ -444,6 +451,7 @@ func (f *FilterMaps) safeDeleteWithLogs(deleteFn func(db ethdb.KeyValueStore, ha
// setRange updates the indexed chain view and covered range and also adds the // setRange updates the indexed chain view and covered range and also adds the
// changes to the given batch. // changes to the given batch.
//
// Note that this function assumes that the index write lock is being held. // Note that this function assumes that the index write lock is being held.
func (f *FilterMaps) setRange(batch ethdb.KeyValueWriter, newView *ChainView, newRange filterMapsRange, isTempRange bool) { func (f *FilterMaps) setRange(batch ethdb.KeyValueWriter, newView *ChainView, newRange filterMapsRange, isTempRange bool) {
f.indexedView = newView f.indexedView = newView
@ -477,6 +485,7 @@ func (f *FilterMaps) setRange(batch ethdb.KeyValueWriter, newView *ChainView, ne
// Note that this function assumes that the log index structure is consistent // Note that this function assumes that the log index structure is consistent
// with the canonical chain at the point where the given log value index points. // with the canonical chain at the point where the given log value index points.
// If this is not the case then an invalid result or an error may be returned. // If this is not the case then an invalid result or an error may be returned.
//
// Note that this function assumes that the indexer read lock is being held when // Note that this function assumes that the indexer read lock is being held when
// called from outside the indexerLoop goroutine. // called from outside the indexerLoop goroutine.
func (f *FilterMaps) getLogByLvIndex(lvIndex uint64) (*types.Log, error) { func (f *FilterMaps) getLogByLvIndex(lvIndex uint64) (*types.Log, error) {
@ -655,6 +664,7 @@ func (f *FilterMaps) mapRowIndex(mapIndex, rowIndex uint32) uint64 {
// getBlockLvPointer returns the starting log value index where the log values // getBlockLvPointer returns the starting log value index where the log values
// generated by the given block are located. If blockNumber is beyond the current // generated by the given block are located. If blockNumber is beyond the current
// head then the first unoccupied log value index is returned. // head then the first unoccupied log value index is returned.
//
// Note that this function assumes that the indexer read lock is being held when // Note that this function assumes that the indexer read lock is being held when
// called from outside the indexerLoop goroutine. // called from outside the indexerLoop goroutine.
func (f *FilterMaps) getBlockLvPointer(blockNumber uint64) (uint64, error) { func (f *FilterMaps) getBlockLvPointer(blockNumber uint64) (uint64, error) {
@ -762,7 +772,7 @@ func (f *FilterMaps) deleteTailEpoch(epoch uint32) (bool, error) {
return false, errors.New("invalid tail epoch number") return false, errors.New("invalid tail epoch number")
} }
// remove index data // remove index data
if err := f.safeDeleteWithLogs(func(db ethdb.KeyValueStore, hashScheme bool, stopCb func(bool) bool) error { deleteFn := func(db ethdb.KeyValueStore, hashScheme bool, stopCb func(bool) bool) error {
first := f.mapRowIndex(firstMap, 0) first := f.mapRowIndex(firstMap, 0)
count := f.mapRowIndex(firstMap+f.mapsPerEpoch, 0) - first count := f.mapRowIndex(firstMap+f.mapsPerEpoch, 0) - first
if err := rawdb.DeleteFilterMapRows(f.db, common.NewRange(first, count), hashScheme, stopCb); err != nil { if err := rawdb.DeleteFilterMapRows(f.db, common.NewRange(first, count), hashScheme, stopCb); err != nil {
@ -786,10 +796,13 @@ func (f *FilterMaps) deleteTailEpoch(epoch uint32) (bool, error) {
f.lvPointerCache.Remove(blockNumber) f.lvPointerCache.Remove(blockNumber)
} }
return nil return nil
}, fmt.Sprintf("Deleting tail epoch #%d", epoch), func() bool { }
action := fmt.Sprintf("Deleting tail epoch #%d", epoch)
stopFn := func() bool {
f.processEvents() f.processEvents()
return f.stop || !f.targetHeadIndexed() return f.stop || !f.targetHeadIndexed()
}); err == nil { }
if err := f.safeDeleteWithLogs(deleteFn, action, stopFn); err == nil {
// everything removed; mark as cleaned and report success // everything removed; mark as cleaned and report success
if f.cleanedEpochsBefore == epoch { if f.cleanedEpochsBefore == epoch {
f.cleanedEpochsBefore = epoch + 1 f.cleanedEpochsBefore = epoch + 1
@ -808,6 +821,9 @@ func (f *FilterMaps) deleteTailEpoch(epoch uint32) (bool, error) {
} }
// exportCheckpoints exports epoch checkpoints in the format used by checkpoints.go. // exportCheckpoints exports epoch checkpoints in the format used by checkpoints.go.
//
// Note: acquiring the indexLock read lock is unnecessary here, as this function
// is always called within the indexLoop.
func (f *FilterMaps) exportCheckpoints() { func (f *FilterMaps) exportCheckpoints() {
finalLvPtr, err := f.getBlockLvPointer(f.finalBlock + 1) finalLvPtr, err := f.getBlockLvPointer(f.finalBlock + 1)
if err != nil { if err != nil {

View file

@ -43,6 +43,8 @@ func (f *FilterMaps) indexerLoop() {
log.Info("Started log indexer") log.Info("Started log indexer")
for !f.stop { for !f.stop {
// Note: acquiring the indexLock read lock is unnecessary here,
// as the `indexedRange` is accessed within the indexerLoop.
if !f.indexedRange.initialized { if !f.indexedRange.initialized {
if f.targetView.HeadNumber() == 0 { if f.targetView.HeadNumber() == 0 {
// initialize when chain head is available // initialize when chain head is available
@ -105,7 +107,7 @@ type targetUpdate struct {
historyCutoff, finalBlock uint64 historyCutoff, finalBlock uint64
} }
// SetTargetView sets a new target chain view for the indexer to render. // SetTarget sets a new target chain view for the indexer to render.
// Note that SetTargetView never blocks. // Note that SetTargetView never blocks.
func (f *FilterMaps) SetTarget(targetView *ChainView, historyCutoff, finalBlock uint64) { func (f *FilterMaps) SetTarget(targetView *ChainView, historyCutoff, finalBlock uint64) {
if targetView == nil { if targetView == nil {
@ -178,6 +180,8 @@ func (f *FilterMaps) processSingleEvent(blocking bool) bool {
if f.stop { if f.stop {
return false return false
} }
// Note: acquiring the indexLock read lock is unnecessary here,
// as this function is always called within the indexLoop.
if !f.hasTempRange { if !f.hasTempRange {
for _, mb := range f.matcherSyncRequests { for _, mb := range f.matcherSyncRequests {
mb.synced() mb.synced()

View file

@ -111,17 +111,17 @@ func (fm *FilterMapsMatcherBackend) GetLogByLvIndex(ctx context.Context, lvIndex
// synced signals to the matcher that has triggered a synchronisation that it // synced signals to the matcher that has triggered a synchronisation that it
// has been finished and the log index is consistent with the chain head passed // has been finished and the log index is consistent with the chain head passed
// as a parameter. // as a parameter.
//
// Note that if the log index head was far behind the chain head then it might not // Note that if the log index head was far behind the chain head then it might not
// be synced up to the given head in a single step. Still, the latest chain head // be synced up to the given head in a single step. Still, the latest chain head
// should be passed as a parameter and the existing log index should be consistent // should be passed as a parameter and the existing log index should be consistent
// with that chain. // with that chain.
//
// Note: acquiring the indexLock read lock is unnecessary here, as this function
// is always called within the indexLoop.
func (fm *FilterMapsMatcherBackend) synced() { func (fm *FilterMapsMatcherBackend) synced() {
fm.f.indexLock.RLock()
fm.f.matchersLock.Lock() fm.f.matchersLock.Lock()
defer func() { defer fm.f.matchersLock.Unlock()
fm.f.matchersLock.Unlock()
fm.f.indexLock.RUnlock()
}()
indexedBlocks := fm.f.indexedRange.blocks indexedBlocks := fm.f.indexedRange.blocks
if !fm.f.indexedRange.headIndexed && !indexedBlocks.IsEmpty() { if !fm.f.indexedRange.headIndexed && !indexedBlocks.IsEmpty() {
@ -154,6 +154,8 @@ func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange
case <-ctx.Done(): case <-ctx.Done():
return SyncRange{}, ctx.Err() return SyncRange{}, ctx.Err()
case <-fm.f.disabledCh: case <-fm.f.disabledCh:
// Note: acquiring the indexLock read lock is unnecessary here,
// as the indexer has already been terminated.
return SyncRange{IndexedView: fm.f.indexedView}, nil return SyncRange{IndexedView: fm.f.indexedView}, nil
} }
select { select {
@ -162,6 +164,8 @@ func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange
case <-ctx.Done(): case <-ctx.Done():
return SyncRange{}, ctx.Err() return SyncRange{}, ctx.Err()
case <-fm.f.disabledCh: case <-fm.f.disabledCh:
// Note: acquiring the indexLock read lock is unnecessary here,
// as the indexer has already been terminated.
return SyncRange{IndexedView: fm.f.indexedView}, nil return SyncRange{IndexedView: fm.f.indexedView}, nil
} }
} }
@ -170,7 +174,9 @@ func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange
// valid range with the current indexed range. This function should be called // valid range with the current indexed range. This function should be called
// whenever a part of the log index has been removed, before adding new blocks // whenever a part of the log index has been removed, before adding new blocks
// to it. // to it.
// Note that this function assumes that the index read lock is being held. //
// Note: acquiring the indexLock read lock is unnecessary here, as this function
// is always called within the indexLoop.
func (f *FilterMaps) updateMatchersValidRange() { func (f *FilterMaps) updateMatchersValidRange() {
f.matchersLock.Lock() f.matchersLock.Lock()
defer f.matchersLock.Unlock() defer f.matchersLock.Unlock()

View file

@ -255,7 +255,8 @@ func TestStateProcessorErrors(t *testing.T) {
}, },
want: "could not apply tx 0 [0xc18d10f4c809dbdfa1a074c3300de9bc4b7f16a20f0ec667f6f67312b71b956a]: EIP-7702 transaction with empty auth list (sender 0x71562b71999873DB5b286dF957af199Ec94617F7)", want: "could not apply tx 0 [0xc18d10f4c809dbdfa1a074c3300de9bc4b7f16a20f0ec667f6f67312b71b956a]: EIP-7702 transaction with empty auth list (sender 0x71562b71999873DB5b286dF957af199Ec94617F7)",
}, },
// ErrSetCodeTxCreate cannot be tested: it is impossible to create a SetCode-tx with nil `to`. // ErrSetCodeTxCreate cannot be tested here: it is impossible to create a SetCode-tx with nil `to`.
// The EstimateGas API tests test this case.
} { } {
block := GenerateBadBlock(gspec.ToBlock(), beacon.New(ethash.NewFaker()), tt.txs, gspec.Config, false) block := GenerateBadBlock(gspec.ToBlock(), beacon.New(ethash.NewFaker()), tt.txs, gspec.Config, false)
_, err := blockchain.InsertChain(types.Blocks{block}) _, err := blockchain.InsertChain(types.Blocks{block})

View file

@ -754,6 +754,9 @@ func toCallArg(msg ethereum.CallMsg) interface{} {
if msg.BlobHashes != nil { if msg.BlobHashes != nil {
arg["blobVersionedHashes"] = msg.BlobHashes arg["blobVersionedHashes"] = msg.BlobHashes
} }
if msg.AuthorizationList != nil {
arg["authorizationList"] = msg.AuthorizationList
}
return arg return arg
} }

View file

@ -251,6 +251,9 @@ func toCallArg(msg ethereum.CallMsg) interface{} {
if msg.BlobHashes != nil { if msg.BlobHashes != nil {
arg["blobVersionedHashes"] = msg.BlobHashes arg["blobVersionedHashes"] = msg.BlobHashes
} }
if msg.AuthorizationList != nil {
arg["authorizationList"] = msg.AuthorizationList
}
return arg return arg
} }

View file

@ -156,6 +156,9 @@ type CallMsg struct {
// For BlobTxType // For BlobTxType
BlobGasFeeCap *big.Int BlobGasFeeCap *big.Int
BlobHashes []common.Hash BlobHashes []common.Hash
// For SetCodeTxType
AuthorizationList []types.SetCodeAuthorization
} }
// A ContractCaller provides contract calls, essentially transactions that are executed by // A ContractCaller provides contract calls, essentially transactions that are executed by

View file

@ -668,6 +668,11 @@ func TestEstimateGas(t *testing.T) {
b.SetPoS() b.SetPoS()
})) }))
setCodeAuthorization, _ := types.SignSetCode(accounts[0].key, types.SetCodeAuthorization{
Address: accounts[0].addr,
Nonce: uint64(genBlocks + 1),
})
var testSuite = []struct { var testSuite = []struct {
blockNumber rpc.BlockNumber blockNumber rpc.BlockNumber
call TransactionArgs call TransactionArgs
@ -846,6 +851,50 @@ func TestEstimateGas(t *testing.T) {
}, },
want: 21000, want: 21000,
}, },
// Should be able to estimate SetCodeTx.
{
blockNumber: rpc.LatestBlockNumber,
call: TransactionArgs{
From: &accounts[0].addr,
To: &accounts[1].addr,
Value: (*hexutil.Big)(big.NewInt(0)),
AuthorizationList: []types.SetCodeAuthorization{setCodeAuthorization},
},
want: 46000,
},
// Should retrieve the code of 0xef0001 || accounts[0].addr and return an invalid opcode error.
{
blockNumber: rpc.LatestBlockNumber,
call: TransactionArgs{
From: &accounts[0].addr,
To: &accounts[0].addr,
Value: (*hexutil.Big)(big.NewInt(0)),
AuthorizationList: []types.SetCodeAuthorization{setCodeAuthorization},
},
expectErr: errors.New("invalid opcode: opcode 0xef not defined"),
},
// SetCodeTx with empty authorization list should fail.
{
blockNumber: rpc.LatestBlockNumber,
call: TransactionArgs{
From: &accounts[0].addr,
To: &common.Address{},
Value: (*hexutil.Big)(big.NewInt(0)),
AuthorizationList: []types.SetCodeAuthorization{},
},
expectErr: core.ErrEmptyAuthList,
},
// SetCodeTx with nil `to` should fail.
{
blockNumber: rpc.LatestBlockNumber,
call: TransactionArgs{
From: &accounts[0].addr,
To: nil,
Value: (*hexutil.Big)(big.NewInt(0)),
AuthorizationList: []types.SetCodeAuthorization{setCodeAuthorization},
},
expectErr: core.ErrSetCodeTxCreate,
},
} }
for i, tc := range testSuite { for i, tc := range testSuite {
result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)
@ -855,7 +904,7 @@ func TestEstimateGas(t *testing.T) {
continue continue
} }
if !errors.Is(err, tc.expectErr) { if !errors.Is(err, tc.expectErr) {
if !reflect.DeepEqual(err, tc.expectErr) { if err.Error() != tc.expectErr.Error() {
t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err)
} }
} }

View file

@ -52,7 +52,7 @@ type Config struct {
// DefaultConfig contains default settings for miner. // DefaultConfig contains default settings for miner.
var DefaultConfig = Config{ var DefaultConfig = Config{
GasCeil: 30_000_000, GasCeil: 36_000_000,
GasPrice: big.NewInt(params.GWei / 1000), GasPrice: big.NewInt(params.GWei / 1000),
// The default recommit time is chosen as two seconds since // The default recommit time is chosen as two seconds since

View file

@ -19,6 +19,6 @@ package version
const ( const (
Major = 1 // Major version component of the current release Major = 1 // Major version component of the current release
Minor = 15 // Minor version component of the current release Minor = 15 // Minor version component of the current release
Patch = 10 // Patch version component of the current release Patch = 11 // Patch version component of the current release
Meta = "unstable" // Version metadata to append to the version string Meta = "unstable" // Version metadata to append to the version string
) )