Merge pull request #50 from berachain/update-main

Update upstream master
This commit is contained in:
Cal Bera 2025-08-07 10:53:12 -07:00 committed by GitHub
commit 2e040fc486
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 543 additions and 187 deletions

View file

@ -32,7 +32,7 @@ type Value [32]byte
// Values represent a series of merkle tree leaves/nodes. // Values represent a series of merkle tree leaves/nodes.
type Values []Value type Values []Value
var valueT = reflect.TypeOf(Value{}) var valueT = reflect.TypeFor[Value]()
// UnmarshalJSON parses a merkle value in hex syntax. // UnmarshalJSON parses a merkle value in hex syntax.
func (m *Value) UnmarshalJSON(input []byte) error { func (m *Value) UnmarshalJSON(input []byte) error {

View file

@ -28,11 +28,11 @@ import (
) )
var ( var (
bytesT = reflect.TypeOf(Bytes(nil)) bytesT = reflect.TypeFor[Bytes]()
bigT = reflect.TypeOf((*Big)(nil)) bigT = reflect.TypeFor[*Big]()
uintT = reflect.TypeOf(Uint(0)) uintT = reflect.TypeFor[Uint]()
uint64T = reflect.TypeOf(Uint64(0)) uint64T = reflect.TypeFor[Uint64]()
u256T = reflect.TypeOf((*uint256.Int)(nil)) u256T = reflect.TypeFor[*uint256.Int]()
) )
// Bytes marshals/unmarshals as a JSON string with 0x prefix. // Bytes marshals/unmarshals as a JSON string with 0x prefix.

View file

@ -471,7 +471,7 @@ func isString(input []byte) bool {
// UnmarshalJSON parses a hash in hex syntax. // UnmarshalJSON parses a hash in hex syntax.
func (d *Decimal) UnmarshalJSON(input []byte) error { func (d *Decimal) UnmarshalJSON(input []byte) error {
if !isString(input) { if !isString(input) {
return &json.UnmarshalTypeError{Value: "non-string", Type: reflect.TypeOf(uint64(0))} return &json.UnmarshalTypeError{Value: "non-string", Type: reflect.TypeFor[uint64]()}
} }
if i, err := strconv.ParseUint(string(input[1:len(input)-1]), 10, 64); err == nil { if i, err := strconv.ParseUint(string(input[1:len(input)-1]), 10, 64); err == nil {
*d = Decimal(i) *d = Decimal(i)

View file

@ -551,8 +551,10 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
return block, b.receipts return block, b.receipts
} }
sdb := state.NewDatabase(trdb, nil)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
statedb, err := state.New(parent.Root(), state.NewDatabase(trdb, nil)) statedb, err := state.New(parent.Root(), sdb)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View file

@ -124,19 +124,12 @@ func (cv *ChainView) RawReceipts(number uint64) types.Receipts {
// SharedRange returns the block range shared by two chain views. // SharedRange returns the block range shared by two chain views.
func (cv *ChainView) SharedRange(cv2 *ChainView) common.Range[uint64] { func (cv *ChainView) SharedRange(cv2 *ChainView) common.Range[uint64] {
cv.lock.Lock() if cv == nil || cv2 == nil {
defer cv.lock.Unlock()
if cv == nil || cv2 == nil || !cv.extendNonCanonical() || !cv2.extendNonCanonical() {
return common.Range[uint64]{} return common.Range[uint64]{}
} }
var sharedLen uint64 sharedLen := min(cv.headNumber, cv2.headNumber) + 1
for n := min(cv.headNumber+1-uint64(len(cv.hashes)), cv2.headNumber+1-uint64(len(cv2.hashes))); n <= cv.headNumber && n <= cv2.headNumber; n++ { for sharedLen > 0 && cv.BlockId(sharedLen-1) != cv2.BlockId(sharedLen-1) {
h1, h2 := cv.blockHash(n), cv2.blockHash(n) sharedLen--
if h1 != h2 || h1 == (common.Hash{}) {
break
}
sharedLen = n + 1
} }
return common.NewRange(0, sharedLen) return common.NewRange(0, sharedLen)
} }

View file

@ -241,9 +241,8 @@ func checksumToBytes(hash uint32) [4]byte {
// them, one for the block number based forks and the second for the timestamps. // them, one for the block number based forks and the second for the timestamps.
func gatherForks(config *params.ChainConfig, genesis uint64) ([]uint64, []uint64) { func gatherForks(config *params.ChainConfig, genesis uint64) ([]uint64, []uint64) {
// Gather all the fork block numbers via reflection // Gather all the fork block numbers via reflection
kind := reflect.TypeOf(params.ChainConfig{}) kind := reflect.TypeFor[params.ChainConfig]()
conf := reflect.ValueOf(config).Elem() conf := reflect.ValueOf(config).Elem()
x := uint64(0)
var ( var (
forksByBlock []uint64 forksByBlock []uint64
forksByTime []uint64 forksByTime []uint64
@ -258,12 +257,12 @@ func gatherForks(config *params.ChainConfig, genesis uint64) ([]uint64, []uint64
} }
// Extract the fork rule block number or timestamp and aggregate it // Extract the fork rule block number or timestamp and aggregate it
if field.Type == reflect.TypeOf(&x) { if field.Type == reflect.TypeFor[*uint64]() {
if rule := conf.Field(i).Interface().(*uint64); rule != nil { if rule := conf.Field(i).Interface().(*uint64); rule != nil {
forksByTime = append(forksByTime, *rule) forksByTime = append(forksByTime, *rule)
} }
} }
if field.Type == reflect.TypeOf(new(big.Int)) { if field.Type == reflect.TypeFor[*big.Int]() {
if rule := conf.Field(i).Interface().(*big.Int); rule != nil { if rule := conf.Field(i).Interface().(*big.Int); rule != nil {
forksByBlock = append(forksByBlock, rule.Uint64()) forksByBlock = append(forksByBlock, rule.Uint64())
} }

View file

@ -0,0 +1,105 @@
// 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 <http://www.gnu.org/licenses/>.
package overlay
import (
"bytes"
"encoding/gob"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
)
// TransitionState is a structure that holds the progress markers of the
// translation process.
type TransitionState struct {
CurrentAccountAddress *common.Address // addresss of the last translated account
CurrentSlotHash common.Hash // hash of the last translated storage slot
CurrentPreimageOffset int64 // next byte to read from the preimage file
Started, Ended bool
// Mark whether the storage for an account has been processed. This is useful if the
// maximum number of leaves of the conversion is reached before the whole storage is
// processed.
StorageProcessed bool
BaseRoot common.Hash // hash of the last read-only MPT base tree
}
// InTransition returns true if the translation process is in progress.
func (ts *TransitionState) InTransition() bool {
return ts != nil && ts.Started && !ts.Ended
}
// Transitioned returns true if the translation process has been completed.
func (ts *TransitionState) Transitioned() bool {
return ts != nil && ts.Ended
}
// Copy returns a deep copy of the TransitionState object.
func (ts *TransitionState) Copy() *TransitionState {
ret := &TransitionState{
Started: ts.Started,
Ended: ts.Ended,
CurrentSlotHash: ts.CurrentSlotHash,
CurrentPreimageOffset: ts.CurrentPreimageOffset,
StorageProcessed: ts.StorageProcessed,
}
if ts.CurrentAccountAddress != nil {
addr := *ts.CurrentAccountAddress
ret.CurrentAccountAddress = &addr
}
return ret
}
// LoadTransitionState retrieves the Verkle transition state associated with
// the given state root hash from the database.
func LoadTransitionState(db ethdb.KeyValueReader, root common.Hash, isVerkle bool) *TransitionState {
var ts *TransitionState
data, _ := rawdb.ReadVerkleTransitionState(db, root)
// if a state could be read from the db, attempt to decode it
if len(data) > 0 {
var (
newts TransitionState
buf = bytes.NewBuffer(data[:])
dec = gob.NewDecoder(buf)
)
// Decode transition state
err := dec.Decode(&newts)
if err != nil {
log.Error("failed to decode transition state", "err", err)
return nil
}
ts = &newts
}
// Fallback that should only happen before the transition
if ts == nil {
// Initialize the first transition state, with the "ended"
// field set to true if the database was created
// as a verkle database.
log.Debug("no transition state found, starting fresh", "is verkle", db)
// Start with a fresh state
ts = &TransitionState{Ended: isVerkle}
}
return ts
}

View file

@ -0,0 +1,30 @@
// 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 <http://www.gnu.org/licenses/>.
package rawdb
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
)
func ReadVerkleTransitionState(db ethdb.KeyValueReader, hash common.Hash) ([]byte, error) {
return db.Get(transitionStateKey(hash))
}
func WriteVerkleTransitionState(db ethdb.KeyValueWriter, hash common.Hash, state []byte) error {
return db.Put(transitionStateKey(hash), state)
}

View file

@ -604,7 +604,7 @@ var knownMetadataKeys = [][]byte{
snapshotGeneratorKey, snapshotRecoveryKey, txIndexTailKey, fastTxLookupLimitKey, snapshotGeneratorKey, snapshotRecoveryKey, txIndexTailKey, fastTxLookupLimitKey,
uncleanShutdownKey, badBlockKey, transitionStatusKey, skeletonSyncStatusKey, uncleanShutdownKey, badBlockKey, transitionStatusKey, skeletonSyncStatusKey,
persistentStateIDKey, trieJournalKey, snapshotSyncStatusKey, snapSyncStatusFlagKey, persistentStateIDKey, trieJournalKey, snapshotSyncStatusKey, snapSyncStatusFlagKey,
filterMapsRangeKey, headStateHistoryIndexKey, filterMapsRangeKey, headStateHistoryIndexKey, VerkleTransitionStatePrefix,
} }
// printChainMetadata prints out chain metadata to stderr. // printChainMetadata prints out chain metadata to stderr.

View file

@ -158,6 +158,9 @@ var (
preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil)
preimageHitsCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) preimageHitsCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil)
preimageMissCounter = metrics.NewRegisteredCounter("db/preimage/miss", nil) preimageMissCounter = metrics.NewRegisteredCounter("db/preimage/miss", nil)
// Verkle transition information
VerkleTransitionStatePrefix = []byte("verkle-transition-state-")
) )
// LegacyTxLookupEntry is the legacy TxLookupEntry definition with some unnecessary // LegacyTxLookupEntry is the legacy TxLookupEntry definition with some unnecessary
@ -397,3 +400,8 @@ func storageHistoryIndexBlockKey(addressHash common.Hash, storageHash common.Has
binary.BigEndian.PutUint32(buf[:], blockID) binary.BigEndian.PutUint32(buf[:], blockID)
return append(append(append(StateHistoryStorageBlockPrefix, addressHash.Bytes()...), storageHash.Bytes()...), buf[:]...) return append(append(append(StateHistoryStorageBlockPrefix, addressHash.Bytes()...), storageHash.Bytes()...), buf[:]...)
} }
// transitionStateKey = transitionStatusKey + hash
func transitionStateKey(hash common.Hash) []byte {
return append(VerkleTransitionStatePrefix, hash.Bytes()...)
}

View file

@ -21,6 +21,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/common/lru"
"github.com/ethereum/go-ethereum/core/overlay"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
@ -151,17 +152,21 @@ type CachingDB struct {
codeCache *lru.SizeConstrainedCache[common.Hash, []byte] codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
codeSizeCache *lru.Cache[common.Hash, int] codeSizeCache *lru.Cache[common.Hash, int]
pointCache *utils.PointCache pointCache *utils.PointCache
// Transition-specific fields
TransitionStatePerRoot *lru.Cache[common.Hash, *overlay.TransitionState]
} }
// NewDatabase creates a state database with the provided data sources. // NewDatabase creates a state database with the provided data sources.
func NewDatabase(triedb *triedb.Database, snap *snapshot.Tree) *CachingDB { func NewDatabase(triedb *triedb.Database, snap *snapshot.Tree) *CachingDB {
return &CachingDB{ return &CachingDB{
disk: triedb.Disk(), disk: triedb.Disk(),
triedb: triedb, triedb: triedb,
snap: snap, snap: snap,
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
pointCache: utils.NewPointCache(pointCacheSize), pointCache: utils.NewPointCache(pointCacheSize),
TransitionStatePerRoot: lru.NewCache[common.Hash, *overlay.TransitionState](1000),
} }
} }
@ -224,7 +229,13 @@ func (db *CachingDB) ReadersWithCacheStats(stateRoot common.Hash) (ReaderWithSta
// OpenTrie opens the main account trie at a specific root hash. // OpenTrie opens the main account trie at a specific root hash.
func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) { func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) {
if db.triedb.IsVerkle() { if db.triedb.IsVerkle() {
return trie.NewVerkleTrie(root, db.triedb, db.pointCache) ts := overlay.LoadTransitionState(db.TrieDB().Disk(), root, db.triedb.IsVerkle())
if ts.InTransition() {
panic("transition isn't supported yet")
}
if ts.Transitioned() {
return trie.NewVerkleTrie(root, db.triedb, db.pointCache)
}
} }
tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb) tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb)
if err != nil { if err != nil {
@ -235,9 +246,6 @@ func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) {
// OpenStorageTrie opens the storage trie of an account. // OpenStorageTrie opens the storage trie of an account.
func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) { func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) {
// In the verkle case, there is only one tree. But the two-tree structure
// is hardcoded in the codebase. So we need to return the same trie in this
// case.
if db.triedb.IsVerkle() { if db.triedb.IsVerkle() {
return self, nil return self, nil
} }

View file

@ -241,6 +241,7 @@ func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCach
if !db.IsVerkle() { if !db.IsVerkle() {
tr, err = trie.NewStateTrie(trie.StateTrieID(root), db) tr, err = trie.NewStateTrie(trie.StateTrieID(root), db)
} else { } else {
// TODO @gballet determine the trie type (verkle or overlay) by transition state
tr, err = trie.NewVerkleTrie(root, db, cache) tr, err = trie.NewVerkleTrie(root, db, cache)
} }
if err != nil { if err != nil {

View file

@ -293,7 +293,7 @@ func newTracerAllHooks() *tracerAllHooks {
t := &tracerAllHooks{hooksCalled: make(map[string]bool)} t := &tracerAllHooks{hooksCalled: make(map[string]bool)}
// Initialize all hooks to false. We will use this to // Initialize all hooks to false. We will use this to
// get total count of hooks. // get total count of hooks.
hooksType := reflect.TypeOf((*Hooks)(nil)).Elem() hooksType := reflect.TypeFor[Hooks]()
for i := 0; i < hooksType.NumField(); i++ { for i := 0; i < hooksType.NumField(); i++ {
t.hooksCalled[hooksType.Field(i).Name] = false t.hooksCalled[hooksType.Field(i).Name] = false
} }

View file

@ -36,6 +36,7 @@ import (
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
@ -1299,32 +1300,86 @@ func (p *BlobPool) GetMetadata(hash common.Hash) *txpool.TxMetadata {
// GetBlobs returns a number of blobs and proofs for the given versioned hashes. // GetBlobs returns a number of blobs and proofs for the given versioned hashes.
// This is a utility method for the engine API, enabling consensus clients to // This is a utility method for the engine API, enabling consensus clients to
// retrieve blobs from the pools directly instead of the network. // retrieve blobs from the pools directly instead of the network.
func (p *BlobPool) GetBlobs(vhashes []common.Hash) []*types.BlobTxSidecar { func (p *BlobPool) GetBlobs(vhashes []common.Hash, version byte) ([]*kzg4844.Blob, []kzg4844.Commitment, [][]kzg4844.Proof, error) {
sidecars := make([]*types.BlobTxSidecar, len(vhashes)) var (
for idx, vhash := range vhashes { blobs = make([]*kzg4844.Blob, len(vhashes))
// Retrieve the datastore item (in a short lock) commitments = make([]kzg4844.Commitment, len(vhashes))
p.lock.RLock() proofs = make([][]kzg4844.Proof, len(vhashes))
id, exists := p.lookup.storeidOfBlob(vhash)
if !exists {
p.lock.RUnlock()
continue
}
data, err := p.store.Get(id)
p.lock.RUnlock()
// After releasing the lock, try to fill any blobs requested indices = make(map[common.Hash][]int)
if err != nil { filled = make(map[common.Hash]struct{})
log.Error("Tracked blob transaction missing from store", "id", id, "err", err) )
continue for i, h := range vhashes {
} indices[h] = append(indices[h], i)
item := new(types.Transaction)
if err = rlp.DecodeBytes(data, item); err != nil {
log.Error("Blobs corrupted for traced transaction", "id", id, "err", err)
continue
}
sidecars[idx] = item.BlobTxSidecar()
} }
return sidecars for _, vhash := range vhashes {
// Skip duplicate vhash that was already resolved in a previous iteration
if _, ok := filled[vhash]; ok {
continue
}
// Retrieve the corresponding blob tx with the vhash
p.lock.RLock()
txID, exists := p.lookup.storeidOfBlob(vhash)
p.lock.RUnlock()
if !exists {
return nil, nil, nil, fmt.Errorf("blob with vhash %x is not found", vhash)
}
data, err := p.store.Get(txID)
if err != nil {
return nil, nil, nil, err
}
// Decode the blob transaction
tx := new(types.Transaction)
if err := rlp.DecodeBytes(data, tx); err != nil {
return nil, nil, nil, err
}
sidecar := tx.BlobTxSidecar()
if sidecar == nil {
return nil, nil, nil, fmt.Errorf("blob tx without sidecar %x", tx.Hash())
}
// Traverse the blobs in the transaction
for i, hash := range tx.BlobHashes() {
list, ok := indices[hash]
if !ok {
continue // non-interesting blob
}
var pf []kzg4844.Proof
switch version {
case types.BlobSidecarVersion0:
if sidecar.Version == types.BlobSidecarVersion0 {
pf = []kzg4844.Proof{sidecar.Proofs[i]}
} else {
proof, err := kzg4844.ComputeBlobProof(&sidecar.Blobs[i], sidecar.Commitments[i])
if err != nil {
return nil, nil, nil, err
}
pf = []kzg4844.Proof{proof}
}
case types.BlobSidecarVersion1:
if sidecar.Version == types.BlobSidecarVersion0 {
cellProofs, err := kzg4844.ComputeCellProofs(&sidecar.Blobs[i])
if err != nil {
return nil, nil, nil, err
}
pf = cellProofs
} else {
cellProofs, err := sidecar.CellProofsAt(i)
if err != nil {
return nil, nil, nil, err
}
pf = cellProofs
}
}
for _, index := range list {
blobs[index] = &sidecar.Blobs[i]
commitments[index] = sidecar.Commitments[i]
proofs[index] = pf
}
filled[hash] = struct{}{}
}
}
return blobs, commitments, proofs, nil
} }
// AvailableBlobs returns the number of blobs that are available in the subpool. // AvailableBlobs returns the number of blobs that are available in the subpool.

View file

@ -26,6 +26,7 @@ import (
"math/big" "math/big"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"sync" "sync"
"testing" "testing"
@ -50,6 +51,7 @@ var (
testBlobCommits []kzg4844.Commitment testBlobCommits []kzg4844.Commitment
testBlobProofs []kzg4844.Proof testBlobProofs []kzg4844.Proof
testBlobVHashes [][32]byte testBlobVHashes [][32]byte
testBlobIndices = make(map[[32]byte]int)
) )
const testMaxBlobsPerBlock = 6 const testMaxBlobsPerBlock = 6
@ -66,6 +68,7 @@ func init() {
testBlobProofs = append(testBlobProofs, testBlobProof) testBlobProofs = append(testBlobProofs, testBlobProof)
testBlobVHash := kzg4844.CalcBlobHashV1(sha256.New(), &testBlobCommit) testBlobVHash := kzg4844.CalcBlobHashV1(sha256.New(), &testBlobCommit)
testBlobIndices[testBlobVHash] = len(testBlobVHashes)
testBlobVHashes = append(testBlobVHashes, testBlobVHash) testBlobVHashes = append(testBlobVHashes, testBlobVHash)
} }
} }
@ -216,7 +219,7 @@ func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64,
// makeMultiBlobTx is a utility method to construct a ramdom blob tx with // makeMultiBlobTx is a utility method to construct a ramdom blob tx with
// certain number of blobs in its sidecar. // certain number of blobs in its sidecar.
func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, blobCount int, key *ecdsa.PrivateKey) *types.Transaction { func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, blobCount int, blobOffset int, key *ecdsa.PrivateKey, version byte) *types.Transaction {
var ( var (
blobs []kzg4844.Blob blobs []kzg4844.Blob
blobHashes []common.Hash blobHashes []common.Hash
@ -224,10 +227,15 @@ func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCa
proofs []kzg4844.Proof proofs []kzg4844.Proof
) )
for i := 0; i < blobCount; i++ { for i := 0; i < blobCount; i++ {
blobs = append(blobs, *testBlobs[i]) blobs = append(blobs, *testBlobs[blobOffset+i])
commitments = append(commitments, testBlobCommits[i]) commitments = append(commitments, testBlobCommits[blobOffset+i])
proofs = append(proofs, testBlobProofs[i]) if version == types.BlobSidecarVersion0 {
blobHashes = append(blobHashes, testBlobVHashes[i]) proofs = append(proofs, testBlobProofs[blobOffset+i])
} else {
cellProofs, _ := kzg4844.ComputeCellProofs(testBlobs[blobOffset+i])
proofs = append(proofs, cellProofs...)
}
blobHashes = append(blobHashes, testBlobVHashes[blobOffset+i])
} }
blobtx := &types.BlobTx{ blobtx := &types.BlobTx{
ChainID: uint256.MustFromBig(params.MainnetChainConfig.ChainID), ChainID: uint256.MustFromBig(params.MainnetChainConfig.ChainID),
@ -238,7 +246,7 @@ func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCa
BlobFeeCap: uint256.NewInt(blobFeeCap), BlobFeeCap: uint256.NewInt(blobFeeCap),
BlobHashes: blobHashes, BlobHashes: blobHashes,
Value: uint256.NewInt(100), Value: uint256.NewInt(100),
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, blobs, commitments, proofs), Sidecar: types.NewBlobTxSidecar(version, blobs, commitments, proofs),
} }
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx) return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
} }
@ -396,35 +404,21 @@ func verifyPoolInternals(t *testing.T, pool *BlobPool) {
// whatever is in the pool, it can be retrieved correctly. // whatever is in the pool, it can be retrieved correctly.
func verifyBlobRetrievals(t *testing.T, pool *BlobPool) { func verifyBlobRetrievals(t *testing.T, pool *BlobPool) {
// Collect all the blobs tracked by the pool // Collect all the blobs tracked by the pool
known := make(map[common.Hash]struct{}) var (
hashes []common.Hash
known = make(map[common.Hash]struct{})
)
for _, txs := range pool.index { for _, txs := range pool.index {
for _, tx := range txs { for _, tx := range txs {
for _, vhash := range tx.vhashes { for _, vhash := range tx.vhashes {
known[vhash] = struct{}{} known[vhash] = struct{}{}
} }
hashes = append(hashes, tx.vhashes...)
} }
} }
// Attempt to retrieve all test blobs blobs, _, proofs, err := pool.GetBlobs(hashes, types.BlobSidecarVersion0)
hashes := make([]common.Hash, len(testBlobVHashes)) if err != nil {
for i := range testBlobVHashes { t.Fatal(err)
copy(hashes[i][:], testBlobVHashes[i][:])
}
sidecars := pool.GetBlobs(hashes)
var blobs []*kzg4844.Blob
var proofs []*kzg4844.Proof
for idx, sidecar := range sidecars {
if sidecar == nil {
blobs = append(blobs, nil)
proofs = append(proofs, nil)
continue
}
blobHashes := sidecar.BlobHashes()
for i, hash := range blobHashes {
if hash == hashes[idx] {
blobs = append(blobs, &sidecar.Blobs[i])
proofs = append(proofs, &sidecar.Proofs[i])
}
}
} }
// Cross validate what we received vs what we wanted // Cross validate what we received vs what we wanted
if len(blobs) != len(hashes) || len(proofs) != len(hashes) { if len(blobs) != len(hashes) || len(proofs) != len(hashes) {
@ -434,13 +428,12 @@ func verifyBlobRetrievals(t *testing.T, pool *BlobPool) {
for i, hash := range hashes { for i, hash := range hashes {
// If an item is missing, but shouldn't, error // If an item is missing, but shouldn't, error
if blobs[i] == nil || proofs[i] == nil { if blobs[i] == nil || proofs[i] == nil {
if _, ok := known[hash]; ok { t.Errorf("tracked blob retrieval failed: item %d, hash %x", i, hash)
t.Errorf("tracked blob retrieval failed: item %d, hash %x", i, hash)
}
continue continue
} }
// Item retrieved, make sure it matches the expectation // Item retrieved, make sure it matches the expectation
if *blobs[i] != *testBlobs[i] || *proofs[i] != testBlobProofs[i] { index := testBlobIndices[hash]
if *blobs[i] != *testBlobs[index] || proofs[i][0] != testBlobProofs[index] {
t.Errorf("retrieved blob or proof mismatch: item %d, hash %x", i, hash) t.Errorf("retrieved blob or proof mismatch: item %d, hash %x", i, hash)
continue continue
} }
@ -1071,9 +1064,9 @@ func TestChangingSlotterSize(t *testing.T) {
addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey)
tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, key1) tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0)
tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, key2) tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 0, key2, types.BlobSidecarVersion0)
tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, key3) tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, 0, key3, types.BlobSidecarVersion0)
blob1, _ = rlp.EncodeToBytes(tx1) blob1, _ = rlp.EncodeToBytes(tx1)
blob2, _ = rlp.EncodeToBytes(tx2) blob2, _ = rlp.EncodeToBytes(tx2)
@ -1191,8 +1184,8 @@ func TestBlobCountLimit(t *testing.T) {
// Attempt to add transactions. // Attempt to add transactions.
var ( var (
tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, key1) tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0)
tx2 = makeMultiBlobTx(0, 1, 800, 70, 7, key2) tx2 = makeMultiBlobTx(0, 1, 800, 70, 7, 0, key2, types.BlobSidecarVersion0)
) )
errs := pool.Add([]*types.Transaction{tx1, tx2}, true) errs := pool.Add([]*types.Transaction{tx1, tx2}, true)
@ -1675,6 +1668,181 @@ func TestAdd(t *testing.T) {
} }
} }
func TestGetBlobs(t *testing.T) {
//log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
// Create a temporary folder for the persistent backend
storage := t.TempDir()
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(params.BlobTxMaxBlobs), nil)
// Create transactions from a few accounts.
var (
key1, _ = crypto.GenerateKey()
key2, _ = crypto.GenerateKey()
key3, _ = crypto.GenerateKey()
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0) // [0, 6)
tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 6, key2, types.BlobSidecarVersion1) // [6, 12)
tx3 = makeMultiBlobTx(0, 1, 800, 110, 6, 12, key3, types.BlobSidecarVersion0) // [12, 18)
blob1, _ = rlp.EncodeToBytes(tx1)
blob2, _ = rlp.EncodeToBytes(tx2)
blob3, _ = rlp.EncodeToBytes(tx3)
)
// Write the two safely sized txs to store. note: although the store is
// configured for a blob count of 6, it can also support around ~1mb of call
// data - all this to say that we aren't using the the absolute largest shelf
// available.
store.Put(blob1)
store.Put(blob2)
store.Put(blob3)
store.Close()
// Mimic a blobpool with max blob count of 6 upgrading to a max blob count of 24.
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.Commit(0, true, false)
// Make custom chain config where the max blob count changes based on the loop variable.
cancunTime := uint64(0)
config := &params.ChainConfig{
ChainID: big.NewInt(1),
LondonBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
CancunTime: &cancunTime,
BlobScheduleConfig: &params.BlobScheduleConfig{
Cancun: &params.BlobConfig{
Target: 12,
Max: 24,
UpdateFraction: params.DefaultCancunBlobConfig.UpdateFraction,
},
},
}
chain := &testBlockChain{
config: config,
basefee: uint256.NewInt(1050),
blobfee: uint256.NewInt(105),
statedb: statedb,
}
pool := New(Config{Datadir: storage}, chain, nil)
if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil {
t.Fatalf("failed to create blob pool: %v", err)
}
// Verify the regular three txs are always available.
if got := pool.Get(tx1.Hash()); got == nil {
t.Errorf("expected tx %s from %s in pool", tx1.Hash(), addr1)
}
if got := pool.Get(tx2.Hash()); got == nil {
t.Errorf("expected tx %s from %s in pool", tx2.Hash(), addr2)
}
if got := pool.Get(tx3.Hash()); got == nil {
t.Errorf("expected tx %s from %s in pool", tx3.Hash(), addr3)
}
cases := []struct {
start int
limit int
version byte
expErr bool
}{
{
start: 0, limit: 6,
version: types.BlobSidecarVersion0,
},
{
start: 0, limit: 6,
version: types.BlobSidecarVersion1,
},
{
start: 3, limit: 9,
version: types.BlobSidecarVersion0,
},
{
start: 3, limit: 9,
version: types.BlobSidecarVersion1,
},
{
start: 3, limit: 15,
version: types.BlobSidecarVersion0,
},
{
start: 3, limit: 15,
version: types.BlobSidecarVersion1,
},
{
start: 0, limit: 18,
version: types.BlobSidecarVersion0,
},
{
start: 0, limit: 18,
version: types.BlobSidecarVersion1,
},
{
start: 18, limit: 20,
version: types.BlobSidecarVersion0,
expErr: true,
},
}
for i, c := range cases {
var vhashes []common.Hash
for j := c.start; j < c.limit; j++ {
vhashes = append(vhashes, testBlobVHashes[j])
}
blobs, _, proofs, err := pool.GetBlobs(vhashes, c.version)
if c.expErr {
if err == nil {
t.Errorf("Unexpected return, want error for case %d", i)
}
} else {
if err != nil {
t.Errorf("Unexpected error for case %d, %v", i, err)
}
// Cross validate what we received vs what we wanted
length := c.limit - c.start
if len(blobs) != length || len(proofs) != length {
t.Errorf("retrieved blobs/proofs size mismatch: have %d/%d, want %d", len(blobs), len(proofs), length)
continue
}
for j := 0; j < len(blobs); j++ {
// If an item is missing, but shouldn't, error
if blobs[j] == nil || proofs[j] == nil {
t.Errorf("tracked blob retrieval failed: item %d, hash %x", j, vhashes[j])
continue
}
// Item retrieved, make sure the blob matches the expectation
if *blobs[j] != *testBlobs[c.start+j] {
t.Errorf("retrieved blob mismatch: item %d, hash %x", j, vhashes[j])
continue
}
// Item retrieved, make sure the proof matches the expectation
if c.version == types.BlobSidecarVersion0 {
if proofs[j][0] != testBlobProofs[c.start+j] {
t.Errorf("retrieved proof mismatch: item %d, hash %x", j, vhashes[j])
}
} else {
want, _ := kzg4844.ComputeCellProofs(blobs[j])
if !reflect.DeepEqual(want, proofs[j]) {
t.Errorf("retrieved proof mismatch: item %d, hash %x", j, vhashes[j])
}
}
}
}
}
pool.Close()
}
// fakeBilly is a billy.Database implementation which just drops data on the floor. // fakeBilly is a billy.Database implementation which just drops data on the floor.
type fakeBilly struct { type fakeBilly struct {
billy.Database billy.Database

View file

@ -131,7 +131,7 @@ func (h *Header) Hash() common.Hash {
return rlpHash(h) return rlpHash(h)
} }
var headerSize = common.StorageSize(reflect.TypeOf(Header{}).Size()) var headerSize = common.StorageSize(reflect.TypeFor[Header]().Size())
// Size returns the approximate memory used by all internal contents. It is used // Size returns the approximate memory used by all internal contents. It is used
// to approximate and limit the memory consumption of various caches. // to approximate and limit the memory consumption of various caches.

View file

@ -49,7 +49,7 @@ type Withdrawals []*Withdrawal
// Len returns the length of s. // Len returns the length of s.
func (s Withdrawals) Len() int { return len(s) } func (s Withdrawals) Len() int { return len(s) }
var withdrawalSize = int(reflect.TypeOf(Withdrawal{}).Size()) var withdrawalSize = int(reflect.TypeFor[Withdrawal]().Size())
func (s Withdrawals) Size() int { func (s Withdrawals) Size() int {
return withdrawalSize * len(s) return withdrawalSize * len(s)

View file

@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"fmt"
"math/big" "math/big"
"slices" "slices"
"testing" "testing"
@ -202,12 +203,15 @@ func TestProcessVerkle(t *testing.T) {
t.Log("verified verkle proof, inserting blocks into the chain") t.Log("verified verkle proof, inserting blocks into the chain")
for i, b := range chain {
fmt.Printf("%d %x\n", i, b.Root())
}
endnum, err := blockchain.InsertChain(chain) endnum, err := blockchain.InsertChain(chain)
if err != nil { if err != nil {
t.Fatalf("block %d imported with error: %v", endnum, err) t.Fatalf("block %d imported with error: %v", endnum, err)
} }
for i := 0; i < 2; i++ { for i := range 2 {
b := blockchain.GetBlockByNumber(uint64(i) + 1) b := blockchain.GetBlockByNumber(uint64(i) + 1)
if b == nil { if b == nil {
t.Fatalf("expected block %d to be present in chain", i+1) t.Fatalf("expected block %d to be present in chain", i+1)

View file

@ -31,9 +31,9 @@ import (
var content embed.FS var content embed.FS
var ( var (
blobT = reflect.TypeOf(Blob{}) blobT = reflect.TypeFor[Blob]()
commitmentT = reflect.TypeOf(Commitment{}) commitmentT = reflect.TypeFor[Commitment]()
proofT = reflect.TypeOf(Proof{}) proofT = reflect.TypeFor[Proof]()
CellProofsPerBlob = 128 CellProofsPerBlob = 128
) )

View file

@ -18,7 +18,6 @@
package catalyst package catalyst
import ( import (
"crypto/sha256"
"errors" "errors"
"fmt" "fmt"
"strconv" "strconv"
@ -31,7 +30,6 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/internal/version"
@ -126,10 +124,13 @@ var caps = []string{
var ( var (
// Number of blobs requested via getBlobsV2 // Number of blobs requested via getBlobsV2
getBlobsRequestedCounter = metrics.NewRegisteredCounter("engine/getblobs/requested", nil) getBlobsRequestedCounter = metrics.NewRegisteredCounter("engine/getblobs/requested", nil)
// Number of blobs requested via getBlobsV2 that are present in the blobpool // Number of blobs requested via getBlobsV2 that are present in the blobpool
getBlobsAvailableCounter = metrics.NewRegisteredCounter("engine/getblobs/available", nil) getBlobsAvailableCounter = metrics.NewRegisteredCounter("engine/getblobs/available", nil)
// Number of times getBlobsV2 responded with “hit” // Number of times getBlobsV2 responded with “hit”
getBlobsV2RequestHit = metrics.NewRegisteredCounter("engine/getblobs/hit", nil) getBlobsV2RequestHit = metrics.NewRegisteredCounter("engine/getblobs/hit", nil)
// Number of times getBlobsV2 responded with “miss” // Number of times getBlobsV2 responded with “miss”
getBlobsV2RequestMiss = metrics.NewRegisteredCounter("engine/getblobs/miss", nil) getBlobsV2RequestMiss = metrics.NewRegisteredCounter("engine/getblobs/miss", nil)
) )
@ -537,29 +538,15 @@ func (api *ConsensusAPI) GetBlobsV1(hashes []common.Hash) ([]*engine.BlobAndProo
if len(hashes) > 128 { if len(hashes) > 128 {
return nil, engine.TooLargeRequest.With(fmt.Errorf("requested blob count too large: %v", len(hashes))) return nil, engine.TooLargeRequest.With(fmt.Errorf("requested blob count too large: %v", len(hashes)))
} }
var ( blobs, _, proofs, err := api.eth.BlobTxPool().GetBlobs(hashes, types.BlobSidecarVersion0)
res = make([]*engine.BlobAndProofV1, len(hashes)) if err != nil {
hasher = sha256.New() return nil, engine.InvalidParams.With(err)
index = make(map[common.Hash]int)
sidecars = api.eth.BlobTxPool().GetBlobs(hashes)
)
for i, hash := range hashes {
index[hash] = i
} }
for i, sidecar := range sidecars { res := make([]*engine.BlobAndProofV1, len(hashes))
if res[i] != nil || sidecar == nil { for i := 0; i < len(blobs); i++ {
// already filled res[i] = &engine.BlobAndProofV1{
continue Blob: blobs[i][:],
} Proof: proofs[i][0][:],
for cIdx, commitment := range sidecar.Commitments {
computed := kzg4844.CalcBlobHashV1(hasher, &commitment)
if idx, ok := index[computed]; ok {
res[idx] = &engine.BlobAndProofV1{
Blob: sidecar.Blobs[cIdx][:],
Proof: sidecar.Proofs[cIdx][:],
}
}
} }
} }
return res, nil return res, nil
@ -581,47 +568,19 @@ func (api *ConsensusAPI) GetBlobsV2(hashes []common.Hash) ([]*engine.BlobAndProo
} }
getBlobsV2RequestHit.Inc(1) getBlobsV2RequestHit.Inc(1)
// pull up the blob hashes blobs, _, proofs, err := api.eth.BlobTxPool().GetBlobs(hashes, types.BlobSidecarVersion1)
var ( if err != nil {
res = make([]*engine.BlobAndProofV2, len(hashes)) return nil, engine.InvalidParams.With(err)
index = make(map[common.Hash][]int)
sidecars = api.eth.BlobTxPool().GetBlobs(hashes)
)
for i, hash := range hashes {
index[hash] = append(index[hash], i)
} }
for i, sidecar := range sidecars { res := make([]*engine.BlobAndProofV2, len(hashes))
if res[i] != nil { for i := 0; i < len(blobs); i++ {
// already filled var cellProofs []hexutil.Bytes
continue for _, proof := range proofs[i] {
cellProofs = append(cellProofs, proof[:])
} }
if sidecar == nil { res[i] = &engine.BlobAndProofV2{
// not found, return empty response Blob: blobs[i][:],
return nil, nil CellProofs: cellProofs,
}
if sidecar.Version != types.BlobSidecarVersion1 {
log.Info("GetBlobs queried V0 transaction: index %v, blobhashes %v", index, sidecar.BlobHashes())
return nil, nil
}
blobHashes := sidecar.BlobHashes()
for bIdx, hash := range blobHashes {
if idxes, ok := index[hash]; ok {
proofs, err := sidecar.CellProofsAt(bIdx)
if err != nil {
return nil, engine.InvalidParams.With(err)
}
var cellProofs []hexutil.Bytes
for _, proof := range proofs {
cellProofs = append(cellProofs, proof[:])
}
for _, idx := range idxes {
res[idx] = &engine.BlobAndProofV2{
Blob: sidecar.Blobs[bIdx][:],
CellProofs: cellProofs,
}
}
}
} }
} }
return res, nil return res, nil

View file

@ -200,7 +200,7 @@ func (s *SyncStatusSubscription) Unsubscribe() {
} }
// SubscribeSyncStatus creates a subscription that will broadcast new synchronisation updates. // SubscribeSyncStatus creates a subscription that will broadcast new synchronisation updates.
// The given channel must receive interface values, the result can either. // The given channel must receive interface values, the result can either be a SyncingResult or false.
func (api *DownloaderAPI) SubscribeSyncStatus(status chan interface{}) *SyncStatusSubscription { func (api *DownloaderAPI) SubscribeSyncStatus(status chan interface{}) *SyncStatusSubscription {
api.installSyncSubscription <- status api.installSyncSubscription <- status
return &SyncStatusSubscription{api: api, c: status} return &SyncStatusSubscription{api: api, c: status}

View file

@ -62,6 +62,23 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin
if call.GasLimit >= params.TxGas { if call.GasLimit >= params.TxGas {
hi = call.GasLimit hi = call.GasLimit
} }
// Cap the maximum gas allowance according to EIP-7825 if the estimation targets Osaka
if hi > params.MaxTxGas {
blockNumber, blockTime := opts.Header.Number, opts.Header.Time
if opts.BlockOverrides != nil {
if opts.BlockOverrides.Number != nil {
blockNumber = opts.BlockOverrides.Number.ToInt()
}
if opts.BlockOverrides.Time != nil {
blockTime = uint64(*opts.BlockOverrides.Time)
}
}
if opts.Config.IsOsaka(blockNumber, blockTime) {
hi = params.MaxTxGas
}
}
// Normalize the max fee per gas the call is willing to spend. // Normalize the max fee per gas the call is willing to spend.
var feeCap *big.Int var feeCap *big.Int
if call.GasFeeCap != nil { if call.GasFeeCap != nil {
@ -209,6 +226,9 @@ func execute(ctx context.Context, call *core.Message, opts *Options, gasLimit ui
if errors.Is(err, core.ErrIntrinsicGas) { if errors.Is(err, core.ErrIntrinsicGas) {
return true, nil, nil // Special case, raise gas limit return true, nil, nil // Special case, raise gas limit
} }
if errors.Is(err, core.ErrGasLimitTooHigh) {
return true, nil, nil // Special case, lower gas limit
}
return true, nil, err // Bail out return true, nil, err // Bail out
} }
return result.Failed(), result, nil return result.Failed(), result, nil

2
go.mod
View file

@ -29,7 +29,7 @@ require (
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.6.0
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
github.com/gofrs/flock v0.12.1 github.com/gofrs/flock v0.12.1
github.com/golang-jwt/jwt/v4 v4.5.1 github.com/golang-jwt/jwt/v4 v4.5.2
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/google/gofuzz v1.2.0 github.com/google/gofuzz v1.2.0
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0

4
go.sum
View file

@ -148,8 +148,8 @@ github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=

View file

@ -31,6 +31,10 @@ import (
type precompileContract struct{} type precompileContract struct{}
func (p *precompileContract) Name() string {
panic("implement me")
}
func (p *precompileContract) RequiredGas(input []byte) uint64 { return 0 } func (p *precompileContract) RequiredGas(input []byte) uint64 { return 0 }
func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil } func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil }

View file

@ -45,7 +45,7 @@ const (
// current process. Setting ENR entries via the Set method updates the record. A new version // current process. Setting ENR entries via the Set method updates the record. A new version
// of the record is signed on demand when the Node method is called. // of the record is signed on demand when the Node method is called.
type LocalNode struct { type LocalNode struct {
cur atomic.Value // holds a non-nil node pointer while the record is up-to-date cur atomic.Pointer[Node] // holds a non-nil node pointer while the record is up-to-date
id ID id ID
key *ecdsa.PrivateKey key *ecdsa.PrivateKey
@ -82,7 +82,7 @@ func NewLocalNode(db *DB, key *ecdsa.PrivateKey) *LocalNode {
} }
ln.seq = db.localSeq(ln.id) ln.seq = db.localSeq(ln.id)
ln.update = time.Now() ln.update = time.Now()
ln.cur.Store((*Node)(nil)) ln.cur.Store(nil)
return ln return ln
} }
@ -94,7 +94,7 @@ func (ln *LocalNode) Database() *DB {
// Node returns the current version of the local node record. // Node returns the current version of the local node record.
func (ln *LocalNode) Node() *Node { func (ln *LocalNode) Node() *Node {
// If we have a valid record, return that // If we have a valid record, return that
n := ln.cur.Load().(*Node) n := ln.cur.Load()
if n != nil { if n != nil {
return n return n
} }
@ -105,7 +105,7 @@ func (ln *LocalNode) Node() *Node {
// Double check the current record, since multiple goroutines might be waiting // Double check the current record, since multiple goroutines might be waiting
// on the write mutex. // on the write mutex.
if n = ln.cur.Load().(*Node); n != nil { if n = ln.cur.Load(); n != nil {
return n return n
} }
@ -121,7 +121,7 @@ func (ln *LocalNode) Node() *Node {
ln.sign() ln.sign()
ln.update = time.Now() ln.update = time.Now()
return ln.cur.Load().(*Node) return ln.cur.Load()
} }
// Seq returns the current sequence number of the local node record. // Seq returns the current sequence number of the local node record.
@ -276,11 +276,11 @@ func (e *lnEndpoint) get() (newIP net.IP, newPort uint16) {
} }
func (ln *LocalNode) invalidate() { func (ln *LocalNode) invalidate() {
ln.cur.Store((*Node)(nil)) ln.cur.Store(nil)
} }
func (ln *LocalNode) sign() { func (ln *LocalNode) sign() {
if n := ln.cur.Load().(*Node); n != nil { if n := ln.cur.Load(); n != nil {
return // no changes return // no changes
} }

View file

@ -148,9 +148,9 @@ func addErrorContext(err error, ctx string) error {
} }
var ( var (
decoderInterface = reflect.TypeOf(new(Decoder)).Elem() decoderInterface = reflect.TypeFor[Decoder]()
bigInt = reflect.TypeOf(big.Int{}) bigInt = reflect.TypeFor[big.Int]()
u256Int = reflect.TypeOf(uint256.Int{}) u256Int = reflect.TypeFor[uint256.Int]()
) )
func makeDecoder(typ reflect.Type, tags rlpstruct.Tags) (dec decoder, err error) { func makeDecoder(typ reflect.Type, tags rlpstruct.Tags) (dec decoder, err error) {
@ -512,7 +512,7 @@ func makeNilPtrDecoder(etype reflect.Type, etypeinfo *typeinfo, ts rlpstruct.Tag
} }
} }
var ifsliceType = reflect.TypeOf([]interface{}{}) var ifsliceType = reflect.TypeFor[[]any]()
func decodeInterface(s *Stream, val reflect.Value) error { func decodeInterface(s *Stream, val reflect.Value) error {
if val.Type().NumMethod() != 0 { if val.Type().NumMethod() != 0 {

View file

@ -133,7 +133,7 @@ func puthead(buf []byte, smalltag, largetag byte, size uint64) int {
return sizesize + 1 return sizesize + 1
} }
var encoderInterface = reflect.TypeOf(new(Encoder)).Elem() var encoderInterface = reflect.TypeFor[Encoder]()
// makeWriter creates a writer function for the given type. // makeWriter creates a writer function for the given type.
func makeWriter(typ reflect.Type, ts rlpstruct.Tags) (writer, error) { func makeWriter(typ reflect.Type, ts rlpstruct.Tags) (writer, error) {

View file

@ -26,7 +26,7 @@ import (
// not verify whether the content of RawValues is valid RLP. // not verify whether the content of RawValues is valid RLP.
type RawValue []byte type RawValue []byte
var rawValueType = reflect.TypeOf(RawValue{}) var rawValueType = reflect.TypeFor[RawValue]()
// StringSize returns the encoded size of a string. // StringSize returns the encoded size of a string.
func StringSize(s string) uint64 { func StringSize(s string) uint64 {

View file

@ -29,10 +29,10 @@ import (
) )
var ( var (
contextType = reflect.TypeOf((*context.Context)(nil)).Elem() contextType = reflect.TypeFor[context.Context]()
errorType = reflect.TypeOf((*error)(nil)).Elem() errorType = reflect.TypeFor[error]()
subscriptionType = reflect.TypeOf(Subscription{}) subscriptionType = reflect.TypeFor[Subscription]()
stringType = reflect.TypeOf("") stringType = reflect.TypeFor[string]()
) )
type serviceRegistry struct { type serviceRegistry struct {

View file

@ -544,7 +544,7 @@ func parseBytes(encType interface{}) ([]byte, bool) {
// Handle array types. // Handle array types.
val := reflect.ValueOf(encType) val := reflect.ValueOf(encType)
if val.Kind() == reflect.Array && val.Type().Elem().Kind() == reflect.Uint8 { if val.Kind() == reflect.Array && val.Type().Elem().Kind() == reflect.Uint8 {
v := reflect.MakeSlice(reflect.TypeOf([]byte{}), val.Len(), val.Len()) v := reflect.ValueOf(make([]byte, val.Len()))
reflect.Copy(v, val) reflect.Copy(v, val)
return v.Bytes(), true return v.Bytes(), true
} }