Merge branch 'master' into fix-blob-range-copy

This commit is contained in:
Lessa 2026-02-03 02:24:18 -05:00 committed by GitHub
commit 2da10777a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 343 additions and 122 deletions

View file

@ -53,9 +53,9 @@ func (bc *BlobConfig) blobPrice(excessBlobGas uint64) *big.Int {
return new(big.Int).Mul(f, big.NewInt(params.BlobTxBlobGasPerBlob))
}
func latestBlobConfig(cfg *params.ChainConfig, time uint64) *BlobConfig {
func latestBlobConfig(cfg *params.ChainConfig, time uint64) (BlobConfig, error) {
if cfg.BlobScheduleConfig == nil {
return nil
return BlobConfig{}, errors.New("no blob config")
}
var (
london = cfg.LondonBlock
@ -80,14 +80,14 @@ func latestBlobConfig(cfg *params.ChainConfig, time uint64) *BlobConfig {
case cfg.IsCancun(london, time) && s.Cancun != nil:
bc = s.Cancun
default:
return nil
return BlobConfig{}, errors.New("no blob config")
}
return &BlobConfig{
return BlobConfig{
Target: bc.Target,
Max: bc.Max,
UpdateFraction: bc.UpdateFraction,
}
}, nil
}
// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that
@ -98,8 +98,8 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
panic("bad header pair")
}
bcfg := latestBlobConfig(config, header.Time)
if bcfg == nil {
bcfg, err := latestBlobConfig(config, header.Time)
if err != nil {
panic("called before EIP-4844 is active")
}
@ -130,11 +130,14 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
// blobs on top of the excess blob gas.
func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTimestamp uint64) uint64 {
isOsaka := config.IsOsaka(config.LondonBlock, headTimestamp)
bcfg := latestBlobConfig(config, headTimestamp)
bcfg, err := latestBlobConfig(config, headTimestamp)
if err != nil {
panic("calculating excess blob gas on nil blob config")
}
return calcExcessBlobGas(isOsaka, bcfg, parent)
}
func calcExcessBlobGas(isOsaka bool, bcfg *BlobConfig, parent *types.Header) uint64 {
func calcExcessBlobGas(isOsaka bool, bcfg BlobConfig, parent *types.Header) uint64 {
var parentExcessBlobGas, parentBlobGasUsed uint64
if parent.ExcessBlobGas != nil {
parentExcessBlobGas = *parent.ExcessBlobGas
@ -169,8 +172,8 @@ func calcExcessBlobGas(isOsaka bool, bcfg *BlobConfig, parent *types.Header) uin
// CalcBlobFee calculates the blobfee from the header's excess blob gas field.
func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int {
blobConfig := latestBlobConfig(config, header.Time)
if blobConfig == nil {
blobConfig, err := latestBlobConfig(config, header.Time)
if err != nil {
panic("calculating blob fee on unsupported fork")
}
return blobConfig.blobBaseFee(*header.ExcessBlobGas)
@ -178,8 +181,8 @@ func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int {
// MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp.
func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
blobConfig := latestBlobConfig(cfg, time)
if blobConfig == nil {
blobConfig, err := latestBlobConfig(cfg, time)
if err != nil {
return 0
}
return blobConfig.Max
@ -193,8 +196,8 @@ func MaxBlobGasPerBlock(cfg *params.ChainConfig, time uint64) uint64 {
// LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the
// configuration, regardless of the currently active fork.
func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int {
bcfg := latestBlobConfig(cfg, math.MaxUint64)
if bcfg == nil {
bcfg, err := latestBlobConfig(cfg, math.MaxUint64)
if err != nil {
return 0
}
return bcfg.Max
@ -202,8 +205,8 @@ func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int {
// TargetBlobsPerBlock returns the target blobs per block for a block at the given timestamp.
func TargetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
blobConfig := latestBlobConfig(cfg, time)
if blobConfig == nil {
blobConfig, err := latestBlobConfig(cfg, time)
if err != nil {
return 0
}
return blobConfig.Target

View file

@ -80,12 +80,9 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
func NewEVMTxContext(msg *Message) vm.TxContext {
ctx := vm.TxContext{
Origin: msg.From,
GasPrice: new(big.Int).Set(msg.GasPrice),
GasPrice: uint256.MustFromBig(msg.GasPrice),
BlobHashes: msg.BlobHashes,
}
if msg.BlobGasFeeCap != nil {
ctx.BlobFeeCap = new(big.Int).Set(msg.BlobGasFeeCap)
}
return ctx
}

View file

@ -39,7 +39,8 @@ type journalEntry interface {
revert(*StateDB)
// dirtied returns the Ethereum address modified by this journal entry.
dirtied() *common.Address
// indicates false if no address was changed.
dirtied() (common.Address, bool)
// copy returns a deep-copied journal entry.
copy() journalEntry
@ -100,8 +101,8 @@ func (j *journal) revertToSnapshot(revid int, s *StateDB) {
// append inserts a new modification entry to the end of the change journal.
func (j *journal) append(entry journalEntry) {
j.entries = append(j.entries, entry)
if addr := entry.dirtied(); addr != nil {
j.dirties[*addr]++
if addr, dirty := entry.dirtied(); dirty {
j.dirties[addr]++
}
}
@ -113,9 +114,9 @@ func (j *journal) revert(statedb *StateDB, snapshot int) {
j.entries[i].revert(statedb)
// Drop any dirty tracking induced by the change
if addr := j.entries[i].dirtied(); addr != nil {
if j.dirties[*addr]--; j.dirties[*addr] == 0 {
delete(j.dirties, *addr)
if addr, dirty := j.entries[i].dirtied(); dirty {
if j.dirties[addr]--; j.dirties[addr] == 0 {
delete(j.dirties, addr)
}
}
}
@ -294,8 +295,8 @@ func (ch createObjectChange) revert(s *StateDB) {
delete(s.stateObjects, ch.account)
}
func (ch createObjectChange) dirtied() *common.Address {
return &ch.account
func (ch createObjectChange) dirtied() (common.Address, bool) {
return ch.account, true
}
func (ch createObjectChange) copy() journalEntry {
@ -308,8 +309,8 @@ func (ch createContractChange) revert(s *StateDB) {
s.getStateObject(ch.account).newContract = false
}
func (ch createContractChange) dirtied() *common.Address {
return nil
func (ch createContractChange) dirtied() (common.Address, bool) {
return common.Address{}, false
}
func (ch createContractChange) copy() journalEntry {
@ -325,8 +326,8 @@ func (ch selfDestructChange) revert(s *StateDB) {
}
}
func (ch selfDestructChange) dirtied() *common.Address {
return &ch.account
func (ch selfDestructChange) dirtied() (common.Address, bool) {
return ch.account, true
}
func (ch selfDestructChange) copy() journalEntry {
@ -340,8 +341,8 @@ var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")
func (ch touchChange) revert(s *StateDB) {
}
func (ch touchChange) dirtied() *common.Address {
return &ch.account
func (ch touchChange) dirtied() (common.Address, bool) {
return ch.account, true
}
func (ch touchChange) copy() journalEntry {
@ -354,8 +355,8 @@ func (ch balanceChange) revert(s *StateDB) {
s.getStateObject(ch.account).setBalance(ch.prev)
}
func (ch balanceChange) dirtied() *common.Address {
return &ch.account
func (ch balanceChange) dirtied() (common.Address, bool) {
return ch.account, true
}
func (ch balanceChange) copy() journalEntry {
@ -369,8 +370,8 @@ func (ch nonceChange) revert(s *StateDB) {
s.getStateObject(ch.account).setNonce(ch.prev)
}
func (ch nonceChange) dirtied() *common.Address {
return &ch.account
func (ch nonceChange) dirtied() (common.Address, bool) {
return ch.account, true
}
func (ch nonceChange) copy() journalEntry {
@ -384,8 +385,8 @@ func (ch codeChange) revert(s *StateDB) {
s.getStateObject(ch.account).setCode(crypto.Keccak256Hash(ch.prevCode), ch.prevCode)
}
func (ch codeChange) dirtied() *common.Address {
return &ch.account
func (ch codeChange) dirtied() (common.Address, bool) {
return ch.account, true
}
func (ch codeChange) copy() journalEntry {
@ -399,8 +400,8 @@ func (ch storageChange) revert(s *StateDB) {
s.getStateObject(ch.account).setState(ch.key, ch.prevvalue, ch.origvalue)
}
func (ch storageChange) dirtied() *common.Address {
return &ch.account
func (ch storageChange) dirtied() (common.Address, bool) {
return ch.account, true
}
func (ch storageChange) copy() journalEntry {
@ -416,8 +417,8 @@ func (ch transientStorageChange) revert(s *StateDB) {
s.setTransientState(ch.account, ch.key, ch.prevalue)
}
func (ch transientStorageChange) dirtied() *common.Address {
return nil
func (ch transientStorageChange) dirtied() (common.Address, bool) {
return common.Address{}, false
}
func (ch transientStorageChange) copy() journalEntry {
@ -432,8 +433,8 @@ func (ch refundChange) revert(s *StateDB) {
s.refund = ch.prev
}
func (ch refundChange) dirtied() *common.Address {
return nil
func (ch refundChange) dirtied() (common.Address, bool) {
return common.Address{}, false
}
func (ch refundChange) copy() journalEntry {
@ -452,8 +453,8 @@ func (ch addLogChange) revert(s *StateDB) {
s.logSize--
}
func (ch addLogChange) dirtied() *common.Address {
return nil
func (ch addLogChange) dirtied() (common.Address, bool) {
return common.Address{}, false
}
func (ch addLogChange) copy() journalEntry {
@ -475,8 +476,8 @@ func (ch accessListAddAccountChange) revert(s *StateDB) {
s.accessList.DeleteAddress(ch.address)
}
func (ch accessListAddAccountChange) dirtied() *common.Address {
return nil
func (ch accessListAddAccountChange) dirtied() (common.Address, bool) {
return common.Address{}, false
}
func (ch accessListAddAccountChange) copy() journalEntry {
@ -489,8 +490,8 @@ func (ch accessListAddSlotChange) revert(s *StateDB) {
s.accessList.DeleteSlot(ch.address, ch.slot)
}
func (ch accessListAddSlotChange) dirtied() *common.Address {
return nil
func (ch accessListAddSlotChange) dirtied() (common.Address, bool) {
return common.Address{}, false
}
func (ch accessListAddSlotChange) copy() journalEntry {

View file

@ -48,11 +48,11 @@ func (s Storage) Copy() Storage {
// - Account values as well as storages can be accessed and modified through the object.
// - Finally, call commit to return the changes of storage trie and update account data.
type stateObject struct {
db *StateDB
address common.Address // address of ethereum account
addrHash common.Hash // hash of ethereum address of the account
origin *types.StateAccount // Account original data without any change applied, nil means it was not existent
data types.StateAccount // Account data with all mutations applied in the scope of block
db *StateDB
address common.Address // address of ethereum account
addressHash *common.Hash // hash of ethereum address of the account
origin *types.StateAccount // Account original data without any change applied, nil means it was not existent
data types.StateAccount // Account data with all mutations applied in the scope of block
// Write caches.
trie Trie // storage trie, which becomes non-nil on first access
@ -102,7 +102,6 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s
return &stateObject{
db: db,
address: address,
addrHash: crypto.Keccak256Hash(address[:]),
origin: origin,
data: *acct,
originStorage: make(Storage),
@ -112,6 +111,14 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s
}
}
func (s *stateObject) addrHash() common.Hash {
if s.addressHash == nil {
h := crypto.Keccak256Hash(s.address[:])
s.addressHash = &h
}
return *s.addressHash
}
func (s *stateObject) markSelfdestructed() {
s.selfDestructed = true
}
@ -151,7 +158,7 @@ func (s *stateObject) getPrefetchedTrie() Trie {
return nil
}
// Attempt to retrieve the trie from the prefetcher
return s.db.prefetcher.trie(s.addrHash, s.data.Root)
return s.db.prefetcher.trie(s.addrHash(), s.data.Root)
}
// GetState retrieves a value associated with the given storage key.
@ -203,7 +210,7 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
// Schedule the resolved storage slots for prefetching if it's enabled.
if s.db.prefetcher != nil && s.data.Root != types.EmptyRootHash {
if err = s.db.prefetcher.prefetch(s.addrHash, s.origin.Root, s.address, nil, []common.Hash{key}, true); err != nil {
if err = s.db.prefetcher.prefetch(s.addrHash(), s.origin.Root, s.address, nil, []common.Hash{key}, true); err != nil {
log.Error("Failed to prefetch storage slot", "addr", s.address, "key", key, "err", err)
}
}
@ -264,7 +271,7 @@ func (s *stateObject) finalise() {
s.pendingStorage[key] = value
}
if s.db.prefetcher != nil && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash {
if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, nil, slotsToPrefetch, false); err != nil {
if err := s.db.prefetcher.prefetch(s.addrHash(), s.data.Root, s.address, nil, slotsToPrefetch, false); err != nil {
log.Error("Failed to prefetch slots", "addr", s.address, "slots", len(slotsToPrefetch), "err", err)
}
}
@ -359,7 +366,7 @@ func (s *stateObject) updateTrie() (Trie, error) {
s.db.StorageDeleted.Add(1)
}
if s.db.prefetcher != nil {
s.db.prefetcher.used(s.addrHash, s.data.Root, nil, used)
s.db.prefetcher.used(s.addrHash(), s.data.Root, nil, used)
}
s.uncommittedStorage = make(Storage) // empties the commit markers
return tr, nil
@ -491,7 +498,7 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject {
obj := &stateObject{
db: db,
address: s.address,
addrHash: s.addrHash,
addressHash: nil,
origin: s.origin,
data: s.data,
code: s.code,

View file

@ -867,13 +867,13 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
witness := trie.Witness()
s.witness.AddState(witness)
if s.witnessStats != nil {
s.witnessStats.Add(witness, obj.addrHash)
s.witnessStats.Add(witness, obj.addrHash())
}
} else if obj.trie != nil {
witness := obj.trie.Witness()
s.witness.AddState(witness)
if s.witnessStats != nil {
s.witnessStats.Add(witness, obj.addrHash)
s.witnessStats.Add(witness, obj.addrHash())
}
}
}
@ -891,13 +891,13 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
witness := trie.Witness()
s.witness.AddState(witness)
if s.witnessStats != nil {
s.witnessStats.Add(witness, obj.addrHash)
s.witnessStats.Add(witness, obj.addrHash())
}
} else if obj.trie != nil {
witness := obj.trie.Witness()
s.witness.AddState(witness)
if s.witnessStats != nil {
s.witnessStats.Add(witness, obj.addrHash)
s.witnessStats.Add(witness, obj.addrHash())
}
}
}
@ -1284,7 +1284,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool, noStorageWiping bool, blockNum
return err
}
lock.Lock()
updates[obj.addrHash] = update
updates[obj.addrHash()] = update
s.StorageCommits = time.Since(start) // overwrite with the longest storage commit runtime
lock.Unlock()
return nil

View file

@ -330,7 +330,7 @@ func NewEIP2930Signer(chainId *big.Int) Signer {
// are replay-protected as well as unprotected homestead transactions.
// Deprecated: always use the Signer interface type
type EIP155Signer struct {
chainId, chainIdMul *big.Int
chainId *big.Int
}
func NewEIP155Signer(chainId *big.Int) EIP155Signer {
@ -338,8 +338,7 @@ func NewEIP155Signer(chainId *big.Int) EIP155Signer {
chainId = new(big.Int)
}
return EIP155Signer{
chainId: chainId,
chainIdMul: new(big.Int).Mul(chainId, big.NewInt(2)),
chainId: chainId,
}
}
@ -365,7 +364,8 @@ func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
}
V, R, S := tx.RawSignatureValues()
V = new(big.Int).Sub(V, s.chainIdMul)
V = new(big.Int).Sub(V, s.chainId)
V = new(big.Int).Sub(V, s.chainId)
V.Sub(V, big8)
return recoverPlain(s.Hash(tx), R, S, V, true)
}
@ -382,7 +382,8 @@ func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big
}
if s.chainId.Sign() != 0 {
V = big.NewInt(int64(sig[64] + 35))
V.Add(V, s.chainIdMul)
V.Add(V, s.chainId)
V.Add(V, s.chainId)
}
return R, S, V, nil
}

View file

@ -73,9 +73,8 @@ type BlockContext struct {
type TxContext struct {
// Message information
Origin common.Address // Provides information for ORIGIN
GasPrice *big.Int // Provides information for GASPRICE (and is used to zero the basefee if NoBaseFee is set)
GasPrice *uint256.Int // Provides information for GASPRICE (and is used to zero the basefee if NoBaseFee is set)
BlobHashes []common.Hash // Provides information for BLOBHASH
BlobFeeCap *big.Int // Is used to zero the blobbasefee if NoBaseFee is set
AccessEvents *state.AccessEvents // Capture all state accesses for this tx
}
@ -125,9 +124,6 @@ type EVM struct {
// jumpDests stores results of JUMPDEST analysis.
jumpDests JumpDestCache
hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes
hasherBuf common.Hash // Keccak256 hasher result array shared across opcodes
readOnly bool // Whether to throw on stateful modifications
returnData []byte // Last CALL's return data for subsequent reuse
}
@ -144,7 +140,6 @@ func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainCon
chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
jumpDests: newMapJumpDests(),
hasher: crypto.NewKeccakState(),
}
evm.precompiles = activePrecompiledContracts(evm.chainRules)
@ -618,7 +613,7 @@ func (evm *EVM) Create(caller common.Address, code []byte, gas uint64, value *ui
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
inithash := crypto.HashData(evm.hasher, code)
inithash := crypto.Keccak256Hash(code)
contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), inithash[:])
return evm.create(caller, code, gas, endowment, contractAddr, CREATE2)
}

View file

@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)
@ -233,14 +234,12 @@ func opKeccak256(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
offset, size := scope.Stack.pop(), scope.Stack.peek()
data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64())
evm.hasher.Reset()
evm.hasher.Write(data)
evm.hasher.Read(evm.hasherBuf[:])
hash := crypto.Keccak256Hash(data)
if evm.Config.EnablePreimageRecording {
evm.StateDB.AddPreimage(evm.hasherBuf, data)
evm.StateDB.AddPreimage(hash, data)
}
size.SetBytes(evm.hasherBuf[:])
size.SetBytes(hash[:])
return nil, nil
}
@ -417,8 +416,7 @@ func opExtCodeHash(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
}
func opGasprice(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
v, _ := uint256.FromBig(evm.GasPrice)
scope.Stack.push(v)
scope.Stack.push(evm.GasPrice.Clone())
return nil, nil
}

View file

@ -19,14 +19,14 @@ package runtime
import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/holiman/uint256"
)
func NewEnv(cfg *Config) *vm.EVM {
txContext := vm.TxContext{
Origin: cfg.Origin,
GasPrice: cfg.GasPrice,
GasPrice: uint256.MustFromBig(cfg.GasPrice),
BlobHashes: cfg.BlobHashes,
BlobFeeCap: cfg.BlobFeeCap,
}
blockContext := vm.BlockContext{
CanTransfer: core.CanTransfer,

View file

@ -46,7 +46,7 @@ type vmContext struct {
}
func testCtx() *vmContext {
return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1), BaseFee: big.NewInt(0)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}}
return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1), BaseFee: big.NewInt(0)}, txCtx: vm.TxContext{GasPrice: uint256.NewInt(100000)}}
}
func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) {
@ -63,7 +63,7 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo
contract.Code = contractCode
}
tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit, GasPrice: vmctx.txCtx.GasPrice}), contract.Caller())
tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit, GasPrice: vmctx.txCtx.GasPrice.ToBig()}), contract.Caller())
tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig())
ret, err := evm.Run(contract, []byte{}, false)
tracer.OnExit(0, ret, startGas-contract.Gas, err, true)
@ -186,7 +186,7 @@ func TestHaltBetweenSteps(t *testing.T) {
Contract: vm.NewContract(common.Address{}, common.Address{}, uint256.NewInt(0), 0, nil),
}
evm := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, chainConfig, vm.Config{Tracer: tracer.Hooks})
evm.SetTxContext(vm.TxContext{GasPrice: big.NewInt(1)})
evm.SetTxContext(vm.TxContext{GasPrice: uint256.NewInt(1)})
tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{})
tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 0, big.NewInt(0))
tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil)
@ -210,7 +210,7 @@ func TestNoStepExec(t *testing.T) {
t.Fatal(err)
}
evm := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, chainConfig, vm.Config{Tracer: tracer.Hooks})
evm.SetTxContext(vm.TxContext{GasPrice: big.NewInt(100)})
evm.SetTxContext(vm.TxContext{GasPrice: uint256.NewInt(100)})
tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{})
tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 1000, big.NewInt(0))
tracer.OnExit(0, nil, 0, nil, false)
@ -240,7 +240,7 @@ func TestIsPrecompile(t *testing.T) {
chaincfg.ByzantiumBlock = big.NewInt(100)
chaincfg.IstanbulBlock = big.NewInt(200)
chaincfg.BerlinBlock = big.NewInt(300)
txCtx := vm.TxContext{GasPrice: big.NewInt(100000)}
txCtx := vm.TxContext{GasPrice: uint256.NewInt(100000)}
tracer, err := newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil, chaincfg)
if err != nil {
t.Fatal(err)

View file

@ -974,6 +974,7 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param
type RPCTransaction struct {
BlockHash *common.Hash `json:"blockHash"`
BlockNumber *hexutil.Big `json:"blockNumber"`
BlockTimestamp *hexutil.Uint64 `json:"blockTimestamp"`
From common.Address `json:"from"`
Gas hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
@ -1020,6 +1021,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
if blockHash != (common.Hash{}) {
result.BlockHash = &blockHash
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
result.BlockTimestamp = (*hexutil.Uint64)(&blockTime)
result.TransactionIndex = (*hexutil.Uint64)(&index)
}

View file

@ -140,6 +140,7 @@ func allTransactionTypes(addr common.Address, config *params.ChainConfig) []txDa
Want: `{
"blockHash": null,
"blockNumber": null,
"blockTimestamp": null,
"from": "0x71562b71999873db5b286df957af199ec94617f7",
"gas": "0x7",
"gasPrice": "0x6",
@ -170,6 +171,7 @@ func allTransactionTypes(addr common.Address, config *params.ChainConfig) []txDa
Want: `{
"blockHash": null,
"blockNumber": null,
"blockTimestamp": null,
"from": "0x71562b71999873db5b286df957af199ec94617f7",
"gas": "0x7",
"gasPrice": "0x6",
@ -208,6 +210,7 @@ func allTransactionTypes(addr common.Address, config *params.ChainConfig) []txDa
Want: `{
"blockHash": null,
"blockNumber": null,
"blockTimestamp": null,
"from": "0x71562b71999873db5b286df957af199ec94617f7",
"gas": "0x7",
"gasPrice": "0x6",
@ -254,6 +257,7 @@ func allTransactionTypes(addr common.Address, config *params.ChainConfig) []txDa
Want: `{
"blockHash": null,
"blockNumber": null,
"blockTimestamp": null,
"from": "0x71562b71999873db5b286df957af199ec94617f7",
"gas": "0x7",
"gasPrice": "0x6",
@ -301,6 +305,7 @@ func allTransactionTypes(addr common.Address, config *params.ChainConfig) []txDa
Want: `{
"blockHash": null,
"blockNumber": null,
"blockTimestamp": null,
"from": "0x71562b71999873db5b286df957af199ec94617f7",
"gas": "0x7",
"gasPrice": "0x9",
@ -345,6 +350,7 @@ func allTransactionTypes(addr common.Address, config *params.ChainConfig) []txDa
Want: `{
"blockHash": null,
"blockNumber": null,
"blockTimestamp": null,
"from": "0x71562b71999873db5b286df957af199ec94617f7",
"gas": "0x7",
"gasPrice": "0x9",
@ -387,6 +393,7 @@ func allBlobTxs(addr common.Address, config *params.ChainConfig) []txData {
Want: `{
"blockHash": null,
"blockNumber": null,
"blockTimestamp": null,
"from": "0x71562b71999873db5b286df957af199ec94617f7",
"gas": "0x6",
"gasPrice": "0x5",
@ -3138,6 +3145,7 @@ func TestRPCMarshalBlock(t *testing.T) {
{
"blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
"blockNumber": "0x64",
"blockTimestamp": "0x0",
"from": "0x0000000000000000000000000000000000000000",
"gas": "0x457",
"gasPrice": "0x2b67",
@ -3158,6 +3166,7 @@ func TestRPCMarshalBlock(t *testing.T) {
{
"blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
"blockNumber": "0x64",
"blockTimestamp": "0x0",
"from": "0x0000000000000000000000000000000000000000",
"gas": "0x457",
"gasPrice": "0x2b67",
@ -3176,6 +3185,7 @@ func TestRPCMarshalBlock(t *testing.T) {
{
"blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
"blockNumber": "0x64",
"blockTimestamp": "0x0",
"from": "0x0000000000000000000000000000000000000000",
"gas": "0x457",
"gasPrice": "0x2b67",
@ -3196,6 +3206,7 @@ func TestRPCMarshalBlock(t *testing.T) {
{
"blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
"blockNumber": "0x64",
"blockTimestamp": "0x0",
"from": "0x0000000000000000000000000000000000000000",
"gas": "0x457",
"gasPrice": "0x2b67",

View file

@ -20,6 +20,7 @@
{
"blockHash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5",
"blockNumber": "0x9",
"blockTimestamp": "0x5a",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gas": "0x5208",
"gasPrice": "0x121a9cca",

View file

@ -20,6 +20,7 @@
{
"blockHash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5",
"blockNumber": "0x9",
"blockTimestamp": "0x5a",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gas": "0x5208",
"gasPrice": "0x121a9cca",

View file

@ -20,6 +20,7 @@
{
"blockHash": "0xfda6c7cb7a3a712e0c424909a7724cab0448e89e286617fa8d5fd27f63f28bd2",
"blockNumber": "0xb",
"blockTimestamp": "0x6e",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gas": "0x5208",
"gasPrice": "0xde56ab3",

View file

@ -1375,7 +1375,6 @@ func (err *ConfigCompatError) Error() string {
// Rules is a one time interface meaning that it shouldn't be used in between transition
// phases.
type Rules struct {
ChainID *big.Int
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
IsEIP2929, IsEIP4762 bool
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
@ -1386,15 +1385,10 @@ type Rules struct {
// Rules ensures c's ChainID is not nil.
func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules {
chainID := c.ChainID
if chainID == nil {
chainID = new(big.Int)
}
// disallow setting Merge out of order
isMerge = isMerge && c.IsLondon(num)
isVerkle := isMerge && c.IsVerkle(num, timestamp)
return Rules{
ChainID: new(big.Int).Set(chainID),
IsHomestead: c.IsHomestead(num),
IsEIP150: c.IsEIP150(num),
IsEIP155: c.IsEIP155(num),

View file

@ -108,6 +108,7 @@ type SendTxArgs struct {
BlobHashes []common.Hash `json:"blobVersionedHashes,omitempty"`
// For BlobTxType transactions with blob sidecar
BlobVersion byte `json:"blobVersion,omitempty"`
Blobs []kzg4844.Blob `json:"blobs,omitempty"`
Commitments []kzg4844.Commitment `json:"commitments,omitempty"`
Proofs []kzg4844.Proof `json:"proofs,omitempty"`
@ -235,37 +236,58 @@ func (args *SendTxArgs) validateTxSidecar() error {
if args.Commitments != nil && len(args.Commitments) != n {
return fmt.Errorf("number of blobs and commitments mismatch (have=%d, want=%d)", len(args.Commitments), n)
}
if args.Proofs != nil && len(args.Proofs) != n {
return fmt.Errorf("number of blobs and proofs mismatch (have=%d, want=%d)", len(args.Proofs), n)
}
if args.BlobHashes != nil && len(args.BlobHashes) != n {
return fmt.Errorf("number of blobs and hashes mismatch (have=%d, want=%d)", len(args.BlobHashes), n)
}
if args.Proofs != nil {
if len(args.Proofs) == n {
// v1 transaction
for i := range args.Blobs {
if err := kzg4844.VerifyBlobProof(&args.Blobs[i], args.Commitments[i], args.Proofs[i]); err != nil {
return fmt.Errorf("failed to verify blob proof: %v", err)
}
}
} else if len(args.Proofs) == n*kzg4844.CellProofsPerBlob {
// v2 transaction
if err := kzg4844.VerifyCellProofs(args.Blobs, args.Commitments, args.Proofs); err != nil {
return fmt.Errorf("failed to verify blob proof: %v", err)
}
} else {
return fmt.Errorf("number of proofs and blobs mismatch (have=%d, want=%d or %d)", len(args.Proofs), n, n*kzg4844.CellProofsPerBlob)
}
}
if args.Commitments == nil {
// Generate commitment and proof.
commitments := make([]kzg4844.Commitment, n)
proofs := make([]kzg4844.Proof, n)
for i := range args.Blobs {
c, err := kzg4844.BlobToCommitment(&args.Blobs[i])
if err != nil {
return fmt.Errorf("blobs[%d]: error computing commitment: %v", i, err)
}
commitments[i] = c
p, err := kzg4844.ComputeBlobProof(&args.Blobs[i], c)
if err != nil {
return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err)
}
var proofs []kzg4844.Proof
if args.BlobVersion == types.BlobSidecarVersion1 {
proofs = make([]kzg4844.Proof, 0, n*kzg4844.CellProofsPerBlob)
for i := range args.Blobs {
p, err := kzg4844.ComputeCellProofs(&args.Blobs[i])
if err != nil {
return fmt.Errorf("blobs[%d]: error computing cell proof: %v", i, err)
}
proofs = append(proofs, p...)
}
} else {
proofs = make([]kzg4844.Proof, 0, n)
for i := range args.Blobs {
p, err := kzg4844.ComputeBlobProof(&args.Blobs[i], commitments[i])
if err != nil {
return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err)
}
proofs = append(proofs, p)
}
proofs[i] = p
}
args.Commitments = commitments
args.Proofs = proofs
} else {
for i := range args.Blobs {
if err := kzg4844.VerifyBlobProof(&args.Blobs[i], args.Commitments[i], args.Proofs[i]); err != nil {
return fmt.Errorf("failed to verify blob proof: %v", err)
}
}
}
hashes := make([]common.Hash, n)

View file

@ -17,6 +17,7 @@
package apitypes
import (
"crypto/rand"
"crypto/sha256"
"encoding/json"
"testing"
@ -229,3 +230,183 @@ func TestType_TypeName(t *testing.T) {
}
}
}
func TestValidateTxSidecar(t *testing.T) {
t.Parallel()
// Helper function to create a test blob and its commitment/proof
createTestBlob := func() (kzg4844.Blob, kzg4844.Commitment, kzg4844.Proof, common.Hash) {
b := make([]byte, 31)
rand.Read(b)
var blob kzg4844.Blob
for i := range b {
blob[i+1] = b[i]
}
commitment, err := kzg4844.BlobToCommitment(&blob)
if err != nil {
t.Fatal(err)
}
proof, err := kzg4844.ComputeBlobProof(&blob, commitment)
if err != nil {
t.Fatal(err)
}
hash := kzg4844.CalcBlobHashV1(sha256.New(), &commitment)
return blob, commitment, proof, hash
}
// Helper function to create test cell proofs for v1 transactions
createTestCellProofs := func(blob kzg4844.Blob) []kzg4844.Proof {
cellProofs, err := kzg4844.ComputeCellProofs(&blob)
if err != nil {
t.Fatal(err)
}
return cellProofs
}
blob1, commitment1, proof1, hash1 := createTestBlob()
blob2, commitment2, proof2, hash2 := createTestBlob()
tests := []struct {
name string
args SendTxArgs
wantErr bool
}{
{
name: "no blobs - should pass",
args: SendTxArgs{},
wantErr: false,
},
{
name: "valid blobs with commitments and proofs",
args: SendTxArgs{
Blobs: []kzg4844.Blob{blob1, blob2},
Commitments: []kzg4844.Commitment{commitment1, commitment2},
Proofs: []kzg4844.Proof{proof1, proof2},
BlobHashes: []common.Hash{hash1, hash2},
},
wantErr: false,
},
{
name: "valid blobs without commitments/proofs - should generate them",
args: SendTxArgs{
Blobs: []kzg4844.Blob{blob1},
},
wantErr: false,
},
{
name: "valid blobs with v1 cell proofs",
args: SendTxArgs{
Blobs: []kzg4844.Blob{blob1},
Commitments: []kzg4844.Commitment{commitment1},
Proofs: createTestCellProofs(blob1),
BlobHashes: []common.Hash{hash1},
},
wantErr: false,
},
{
name: "blobs with v1 version flag - should generate cell proofs",
args: SendTxArgs{
Blobs: []kzg4844.Blob{blob1},
BlobVersion: types.BlobSidecarVersion1,
},
wantErr: false,
},
{
name: "proofs provided but commitments not",
args: SendTxArgs{
Blobs: []kzg4844.Blob{blob1},
Proofs: []kzg4844.Proof{proof1},
},
wantErr: true,
},
{
name: "commitments provided but proofs not",
args: SendTxArgs{
Blobs: []kzg4844.Blob{blob1},
Commitments: []kzg4844.Commitment{commitment1},
},
wantErr: true,
},
{
name: "mismatch between blobs and commitments",
args: SendTxArgs{
Blobs: []kzg4844.Blob{blob1, blob2},
Commitments: []kzg4844.Commitment{commitment1}, // Only one commitment for two blobs
Proofs: []kzg4844.Proof{proof1},
},
wantErr: true,
},
{
name: "mismatch between blobs and hashes",
args: SendTxArgs{
Blobs: []kzg4844.Blob{blob1, blob2},
Commitments: []kzg4844.Commitment{commitment1, commitment2},
Proofs: []kzg4844.Proof{proof1, proof2},
BlobHashes: []common.Hash{hash1}, // Only one hash for two blobs
},
wantErr: true,
},
{
name: "wrong number of proofs",
args: SendTxArgs{
Blobs: []kzg4844.Blob{blob1, blob2},
Commitments: []kzg4844.Commitment{commitment1, commitment2},
Proofs: []kzg4844.Proof{proof1, proof2, proof1}, // 3 proofs for 2 blobs
},
wantErr: true,
},
{
name: "invalid blob hash",
args: SendTxArgs{
Blobs: []kzg4844.Blob{blob1},
Commitments: []kzg4844.Commitment{commitment1},
Proofs: []kzg4844.Proof{proof1},
BlobHashes: []common.Hash{hash2}, // Wrong hash
},
wantErr: true,
},
{
name: "invalid proof",
args: SendTxArgs{
BlobVersion: types.BlobSidecarVersion1,
Blobs: []kzg4844.Blob{blob1},
Commitments: []kzg4844.Commitment{commitment1},
Proofs: []kzg4844.Proof{proof1, proof2}, // wrong proof
BlobHashes: []common.Hash{hash1},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Make a copy to avoid modifying the original test case
args := tt.args
err := args.validateTxSidecar()
if tt.wantErr {
if err == nil {
t.Errorf("validateTxSidecar() expected error but got none")
return
}
} else {
if err != nil {
t.Errorf("validateTxSidecar() unexpected error = %v", err)
}
// For successful cases, verify that commitments and proofs were generated if they weren't provided
if len(args.Blobs) > 0 {
if args.Commitments == nil || len(args.Commitments) != len(args.Blobs) {
t.Errorf("validateTxSidecar() should have generated commitments")
}
if args.Proofs == nil || (len(args.Proofs) != len(args.Blobs) && len(args.Proofs) != len(args.Blobs)*kzg4844.CellProofsPerBlob) {
t.Errorf("validateTxSidecar() should have generated proofs")
}
if args.BlobHashes == nil || len(args.BlobHashes) != len(args.Blobs) {
t.Errorf("validateTxSidecar() should have generated blob hashes")
}
}
}
})
}
}

View file

@ -391,10 +391,6 @@ func decodeKeyEntry(keySection []byte, offset int) (uint64, uint64, []byte, int,
// decodeRestartTrailer resolves all the offsets recorded at the trailer.
func decodeRestartTrailer(keySection []byte) ([]uint32, []uint32, int, error) {
var (
keyOffsets []uint32
valOffsets []uint32
)
// Decode the number of restart section
if len(keySection) < 4 {
return nil, nil, 0, fmt.Errorf("key section too short, size: %d", len(keySection))
@ -402,6 +398,10 @@ func decodeRestartTrailer(keySection []byte) ([]uint32, []uint32, int, error) {
nRestarts := binary.BigEndian.Uint32(keySection[len(keySection)-4:])
// Decode the trailer
var (
keyOffsets = make([]uint32, 0, int(nRestarts))
valOffsets = make([]uint32, 0, int(nRestarts))
)
if len(keySection) < int(8*nRestarts)+4 {
return nil, nil, 0, fmt.Errorf("key section too short, restarts: %d, size: %d", nRestarts, len(keySection))
}

View file

@ -342,7 +342,10 @@ func (s *stateSet) encode(w io.Writer) error {
AddrHashes []common.Hash
Accounts [][]byte
}
var enc accounts
enc := accounts{
AddrHashes: make([]common.Hash, 0, len(s.accountData)),
Accounts: make([][]byte, 0, len(s.accountData)),
}
for addrHash, blob := range s.accountData {
enc.AddrHashes = append(enc.AddrHashes, addrHash)
enc.Accounts = append(enc.Accounts, blob)
@ -505,7 +508,10 @@ func (s *StateSetWithOrigin) encode(w io.Writer) error {
Addresses []common.Address
Accounts [][]byte
}
var accounts Accounts
accounts := Accounts{
Addresses: make([]common.Address, 0, len(s.accountOrigin)),
Accounts: make([][]byte, 0, len(s.accountOrigin)),
}
for address, blob := range s.accountOrigin {
accounts.Addresses = append(accounts.Addresses, address)
accounts.Accounts = append(accounts.Accounts, blob)