diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index 47b54d2e85..2ebf4f7155 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -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 diff --git a/core/evm.go b/core/evm.go index 18d940fdd2..2e7e138b59 100644 --- a/core/evm.go +++ b/core/evm.go @@ -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 } diff --git a/core/state/journal.go b/core/state/journal.go index f3f976f24f..a79bd7331a 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -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 { diff --git a/core/state/state_object.go b/core/state/state_object.go index 2873c3cb8a..eecb72ce5d 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -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, diff --git a/core/state/statedb.go b/core/state/statedb.go index 3d329bab64..3a2d9c9ac2 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -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 diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 5a624191cf..5854af07c5 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -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 } diff --git a/core/vm/evm.go b/core/vm/evm.go index 25a3318c02..c365f637d2 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -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) } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index a57e9caa0f..a4c4b0703b 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -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 } diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index e54041f7e2..4181e08ee8 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -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, diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 7f376a27fc..b21e104abc 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -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) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e0baccbfe7..5fbe7db694 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -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) } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 3668bd0e14..837df8b662 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -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", diff --git a/internal/ethapi/testdata/eth_getBlockByHash-hash-latest-1-fullTx.json b/internal/ethapi/testdata/eth_getBlockByHash-hash-latest-1-fullTx.json index 3c8d42c9a9..6aac5b682e 100644 --- a/internal/ethapi/testdata/eth_getBlockByHash-hash-latest-1-fullTx.json +++ b/internal/ethapi/testdata/eth_getBlockByHash-hash-latest-1-fullTx.json @@ -20,6 +20,7 @@ { "blockHash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5", "blockNumber": "0x9", + "blockTimestamp": "0x5a", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "gas": "0x5208", "gasPrice": "0x121a9cca", diff --git a/internal/ethapi/testdata/eth_getBlockByNumber-number-latest-1.json b/internal/ethapi/testdata/eth_getBlockByNumber-number-latest-1.json index 3c8d42c9a9..6aac5b682e 100644 --- a/internal/ethapi/testdata/eth_getBlockByNumber-number-latest-1.json +++ b/internal/ethapi/testdata/eth_getBlockByNumber-number-latest-1.json @@ -20,6 +20,7 @@ { "blockHash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5", "blockNumber": "0x9", + "blockTimestamp": "0x5a", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "gas": "0x5208", "gasPrice": "0x121a9cca", diff --git a/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending-fullTx.json b/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending-fullTx.json index 2e323dcfe7..fc60111244 100644 --- a/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending-fullTx.json +++ b/internal/ethapi/testdata/eth_getBlockByNumber-tag-pending-fullTx.json @@ -20,6 +20,7 @@ { "blockHash": "0xfda6c7cb7a3a712e0c424909a7724cab0448e89e286617fa8d5fd27f63f28bd2", "blockNumber": "0xb", + "blockTimestamp": "0x6e", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "gas": "0x5208", "gasPrice": "0xde56ab3", diff --git a/params/config.go b/params/config.go index c5dfad1cd3..197ed56f8a 100644 --- a/params/config.go +++ b/params/config.go @@ -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), diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 046bcc0bf5..401f4fba07 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -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) diff --git a/signer/core/apitypes/types_test.go b/signer/core/apitypes/types_test.go index ab9d1b22d8..f010cef207 100644 --- a/signer/core/apitypes/types_test.go +++ b/signer/core/apitypes/types_test.go @@ -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") + } + } + } + }) + } +} diff --git a/triedb/pathdb/history_trienode.go b/triedb/pathdb/history_trienode.go index 05a43808c2..11d6112806 100644 --- a/triedb/pathdb/history_trienode.go +++ b/triedb/pathdb/history_trienode.go @@ -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)) } diff --git a/triedb/pathdb/states.go b/triedb/pathdb/states.go index c84e2dc60c..c54d8b1136 100644 --- a/triedb/pathdb/states.go +++ b/triedb/pathdb/states.go @@ -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)