Merge branch 'ethereum:master' into master

This commit is contained in:
Sascha Ronnie Daoudia 2024-01-17 15:19:19 +01:00 committed by GitHub
commit 55a394c919
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
98 changed files with 1501 additions and 2805 deletions

View file

@ -17,7 +17,7 @@ jobs:
with: with:
go-version: 1.21.4 go-version: 1.21.4
- name: Run tests - name: Run tests
run: go test ./... run: go test -short ./...
env: env:
GOOS: linux GOOS: linux
GOARCH: 386 GOARCH: 386

View file

@ -3,7 +3,7 @@
Official Golang execution layer implementation of the Ethereum protocol. Official Golang execution layer implementation of the Ethereum protocol.
[![API Reference]( [![API Reference](
https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667 https://pkg.go.dev/badge/github.com/ethereum/go-ethereum
)](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc) )](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc)
[![Go Report Card](https://goreportcard.com/badge/github.com/ethereum/go-ethereum)](https://goreportcard.com/report/github.com/ethereum/go-ethereum) [![Go Report Card](https://goreportcard.com/badge/github.com/ethereum/go-ethereum)](https://goreportcard.com/report/github.com/ethereum/go-ethereum)
[![Travis](https://travis-ci.com/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.com/ethereum/go-ethereum) [![Travis](https://travis-ci.com/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.com/ethereum/go-ethereum)

View file

@ -84,6 +84,11 @@ type BlockHashContractCaller interface {
// used when the user does not provide some needed values, but rather leaves it up // used when the user does not provide some needed values, but rather leaves it up
// to the transactor to decide. // to the transactor to decide.
type ContractTransactor interface { type ContractTransactor interface {
ethereum.GasEstimator
ethereum.GasPricer
ethereum.GasPricer1559
ethereum.TransactionSender
// HeaderByNumber returns a block header from the current canonical chain. If // HeaderByNumber returns a block header from the current canonical chain. If
// number is nil, the latest known header is returned. // number is nil, the latest known header is returned.
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
@ -93,38 +98,6 @@ type ContractTransactor interface {
// PendingNonceAt retrieves the current pending nonce associated with an account. // PendingNonceAt retrieves the current pending nonce associated with an account.
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
// execution of a transaction.
SuggestGasPrice(ctx context.Context) (*big.Int, error)
// SuggestGasTipCap retrieves the currently suggested 1559 priority fee to allow
// a timely execution of a transaction.
SuggestGasTipCap(ctx context.Context) (*big.Int, error)
// EstimateGas tries to estimate the gas needed to execute a specific
// transaction based on the current pending state of the backend blockchain.
// There is no guarantee that this is the true gas limit requirement as other
// transactions may be added or removed by miners, but it should provide a basis
// for setting a reasonable default.
EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error)
// SendTransaction injects the transaction into the pending pool for execution.
SendTransaction(ctx context.Context, tx *types.Transaction) error
}
// ContractFilterer defines the methods needed to access log events using one-off
// queries or continuous event subscriptions.
type ContractFilterer interface {
// FilterLogs executes a log filter operation, blocking during execution and
// returning all the results in one batch.
//
// TODO(karalabe): Deprecate when the subscription one can return past data too.
FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error)
// SubscribeFilterLogs creates a background log filtering operation, returning
// a subscription immediately, which can be used to stream the found events.
SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)
} }
// DeployBackend wraps the operations needed by WaitMined and WaitDeployed. // DeployBackend wraps the operations needed by WaitMined and WaitDeployed.
@ -133,6 +106,12 @@ type DeployBackend interface {
CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)
} }
// ContractFilterer defines the methods needed to access log events using one-off
// queries or continuous event subscriptions.
type ContractFilterer interface {
ethereum.LogFilterer
}
// ContractBackend defines the methods needed to work with contracts on a read-write basis. // ContractBackend defines the methods needed to work with contracts on a read-write basis.
type ContractBackend interface { type ContractBackend interface {
ContractCaller ContractCaller

View file

@ -18,958 +18,35 @@ package backends
import ( import (
"context" "context"
"errors"
"fmt"
"math/big"
"sync"
"time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/ethclient/simulated"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
) )
// This nil assignment ensures at compile time that SimulatedBackend implements bind.ContractBackend. // SimulatedBackend is a simulated blockchain.
var _ bind.ContractBackend = (*SimulatedBackend)(nil) // Deprecated: use package github.com/ethereum/go-ethereum/ethclient/simulated instead.
var (
errBlockNumberUnsupported = errors.New("simulatedBackend cannot access blocks other than the latest block")
errBlockHashUnsupported = errors.New("simulatedBackend cannot access blocks by hash other than the latest block")
errBlockDoesNotExist = errors.New("block does not exist in blockchain")
errTransactionDoesNotExist = errors.New("transaction does not exist")
)
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
// the background. Its main purpose is to allow for easy testing of contract bindings.
// Simulated backend implements the following interfaces:
// ChainReader, ChainStateReader, ContractBackend, ContractCaller, ContractFilterer, ContractTransactor,
// DeployBackend, GasEstimator, GasPricer, LogFilterer, PendingContractCaller, TransactionReader, and TransactionSender
type SimulatedBackend struct { type SimulatedBackend struct {
database ethdb.Database // In memory database to store our testing data *simulated.Backend
blockchain *core.BlockChain // Ethereum blockchain to handle the consensus simulated.Client
mu sync.Mutex
pendingBlock *types.Block // Currently pending block that will be imported on request
pendingState *state.StateDB // Currently pending state that will be the active on request
pendingReceipts types.Receipts // Currently receipts for the pending block
events *filters.EventSystem // for filtering log events live
filterSystem *filters.FilterSystem // for filtering database logs
config *params.ChainConfig
} }
// NewSimulatedBackendWithDatabase creates a new binding backend based on the given database // Fork sets the head to a new block, which is based on the provided parentHash.
// and uses a simulated blockchain for testing purposes. func (b *SimulatedBackend) Fork(ctx context.Context, parentHash common.Hash) error {
// A simulated backend always uses chainID 1337. return b.Backend.Fork(parentHash)
func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
genesis := core.Genesis{
Config: params.AllEthashProtocolChanges,
GasLimit: gasLimit,
Alloc: alloc,
}
blockchain, _ := core.NewBlockChain(database, nil, &genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
backend := &SimulatedBackend{
database: database,
blockchain: blockchain,
config: genesis.Config,
}
filterBackend := &filterBackend{database, blockchain, backend}
backend.filterSystem = filters.NewFilterSystem(filterBackend, filters.Config{})
backend.events = filters.NewEventSystem(backend.filterSystem, false)
header := backend.blockchain.CurrentBlock()
block := backend.blockchain.GetBlock(header.Hash(), header.Number.Uint64())
backend.rollback(block)
return backend
} }
// NewSimulatedBackend creates a new binding backend using a simulated blockchain // NewSimulatedBackend creates a new binding backend using a simulated blockchain
// for testing purposes. // for testing purposes.
//
// A simulated backend always uses chainID 1337. // A simulated backend always uses chainID 1337.
//
// Deprecated: please use simulated.Backend from package
// github.com/ethereum/go-ethereum/ethclient/simulated instead.
func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
return NewSimulatedBackendWithDatabase(rawdb.NewMemoryDatabase(), alloc, gasLimit) b := simulated.NewBackend(alloc, simulated.WithBlockGasLimit(gasLimit))
} return &SimulatedBackend{
Backend: b,
// Close terminates the underlying blockchain's update loop. Client: b.Client(),
func (b *SimulatedBackend) Close() error {
b.blockchain.Stop()
return nil
}
// Commit imports all the pending transactions as a single block and starts a
// fresh new state.
func (b *SimulatedBackend) Commit() common.Hash {
b.mu.Lock()
defer b.mu.Unlock()
if _, err := b.blockchain.InsertChain([]*types.Block{b.pendingBlock}); err != nil {
panic(err) // This cannot happen unless the simulator is wrong, fail in that case
}
blockHash := b.pendingBlock.Hash()
// Using the last inserted block here makes it possible to build on a side
// chain after a fork.
b.rollback(b.pendingBlock)
return blockHash
}
// Rollback aborts all pending transactions, reverting to the last committed state.
func (b *SimulatedBackend) Rollback() {
b.mu.Lock()
defer b.mu.Unlock()
header := b.blockchain.CurrentBlock()
block := b.blockchain.GetBlock(header.Hash(), header.Number.Uint64())
b.rollback(block)
}
func (b *SimulatedBackend) rollback(parent *types.Block) {
blocks, _ := core.GenerateChain(b.config, parent, ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {})
b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.blockchain.StateCache(), nil)
}
// Fork creates a side-chain that can be used to simulate reorgs.
//
// This function should be called with the ancestor block where the new side
// chain should be started. Transactions (old and new) can then be applied on
// top and Commit-ed.
//
// Note, the side-chain will only become canonical (and trigger the events) when
// it becomes longer. Until then CallContract will still operate on the current
// canonical chain.
//
// There is a % chance that the side chain becomes canonical at the same length
// to simulate live network behavior.
func (b *SimulatedBackend) Fork(ctx context.Context, parent common.Hash) error {
b.mu.Lock()
defer b.mu.Unlock()
if len(b.pendingBlock.Transactions()) != 0 {
return errors.New("pending block dirty")
}
block, err := b.blockByHash(ctx, parent)
if err != nil {
return err
}
b.rollback(block)
return nil
}
// stateByBlockNumber retrieves a state by a given blocknumber.
func (b *SimulatedBackend) stateByBlockNumber(ctx context.Context, blockNumber *big.Int) (*state.StateDB, error) {
if blockNumber == nil || blockNumber.Cmp(b.blockchain.CurrentBlock().Number) == 0 {
return b.blockchain.State()
}
block, err := b.blockByNumber(ctx, blockNumber)
if err != nil {
return nil, err
}
return b.blockchain.StateAt(block.Root())
}
// CodeAt returns the code associated with a certain account in the blockchain.
func (b *SimulatedBackend) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
b.mu.Lock()
defer b.mu.Unlock()
stateDB, err := b.stateByBlockNumber(ctx, blockNumber)
if err != nil {
return nil, err
}
return stateDB.GetCode(contract), nil
}
// CodeAtHash returns the code associated with a certain account in the blockchain.
func (b *SimulatedBackend) CodeAtHash(ctx context.Context, contract common.Address, blockHash common.Hash) ([]byte, error) {
b.mu.Lock()
defer b.mu.Unlock()
header, err := b.headerByHash(blockHash)
if err != nil {
return nil, err
}
stateDB, err := b.blockchain.StateAt(header.Root)
if err != nil {
return nil, err
}
return stateDB.GetCode(contract), nil
}
// BalanceAt returns the wei balance of a certain account in the blockchain.
func (b *SimulatedBackend) BalanceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (*big.Int, error) {
b.mu.Lock()
defer b.mu.Unlock()
stateDB, err := b.stateByBlockNumber(ctx, blockNumber)
if err != nil {
return nil, err
}
return stateDB.GetBalance(contract), nil
}
// NonceAt returns the nonce of a certain account in the blockchain.
func (b *SimulatedBackend) NonceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (uint64, error) {
b.mu.Lock()
defer b.mu.Unlock()
stateDB, err := b.stateByBlockNumber(ctx, blockNumber)
if err != nil {
return 0, err
}
return stateDB.GetNonce(contract), nil
}
// StorageAt returns the value of key in the storage of an account in the blockchain.
func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) {
b.mu.Lock()
defer b.mu.Unlock()
stateDB, err := b.stateByBlockNumber(ctx, blockNumber)
if err != nil {
return nil, err
}
val := stateDB.GetState(contract, key)
return val[:], nil
}
// TransactionReceipt returns the receipt of a transaction.
func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
b.mu.Lock()
defer b.mu.Unlock()
receipt, _, _, _ := rawdb.ReadReceipt(b.database, txHash, b.config)
if receipt == nil {
return nil, ethereum.NotFound
}
return receipt, nil
}
// TransactionByHash checks the pool of pending transactions in addition to the
// blockchain. The isPending return value indicates whether the transaction has been
// mined yet. Note that the transaction may not be part of the canonical chain even if
// it's not pending.
func (b *SimulatedBackend) TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) {
b.mu.Lock()
defer b.mu.Unlock()
tx := b.pendingBlock.Transaction(txHash)
if tx != nil {
return tx, true, nil
}
tx, _, _, _ = rawdb.ReadTransaction(b.database, txHash)
if tx != nil {
return tx, false, nil
}
return nil, false, ethereum.NotFound
}
// BlockByHash retrieves a block based on the block hash.
func (b *SimulatedBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
b.mu.Lock()
defer b.mu.Unlock()
return b.blockByHash(ctx, hash)
}
// blockByHash retrieves a block based on the block hash without Locking.
func (b *SimulatedBackend) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
if hash == b.pendingBlock.Hash() {
return b.pendingBlock, nil
}
block := b.blockchain.GetBlockByHash(hash)
if block != nil {
return block, nil
}
return nil, errBlockDoesNotExist
}
// BlockByNumber retrieves a block from the database by number, caching it
// (associated with its hash) if found.
func (b *SimulatedBackend) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
b.mu.Lock()
defer b.mu.Unlock()
return b.blockByNumber(ctx, number)
}
// blockByNumber retrieves a block from the database by number, caching it
// (associated with its hash) if found without Lock.
func (b *SimulatedBackend) blockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
if number == nil || number.Cmp(b.pendingBlock.Number()) == 0 {
return b.blockByHash(ctx, b.blockchain.CurrentBlock().Hash())
}
block := b.blockchain.GetBlockByNumber(uint64(number.Int64()))
if block == nil {
return nil, errBlockDoesNotExist
}
return block, nil
}
// HeaderByHash returns a block header from the current canonical chain.
func (b *SimulatedBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
b.mu.Lock()
defer b.mu.Unlock()
return b.headerByHash(hash)
}
// headerByHash retrieves a header from the database by hash without Lock.
func (b *SimulatedBackend) headerByHash(hash common.Hash) (*types.Header, error) {
if hash == b.pendingBlock.Hash() {
return b.pendingBlock.Header(), nil
}
header := b.blockchain.GetHeaderByHash(hash)
if header == nil {
return nil, errBlockDoesNotExist
}
return header, nil
}
// HeaderByNumber returns a block header from the current canonical chain. If number is
// nil, the latest known header is returned.
func (b *SimulatedBackend) HeaderByNumber(ctx context.Context, block *big.Int) (*types.Header, error) {
b.mu.Lock()
defer b.mu.Unlock()
if block == nil || block.Cmp(b.pendingBlock.Number()) == 0 {
return b.blockchain.CurrentHeader(), nil
}
return b.blockchain.GetHeaderByNumber(uint64(block.Int64())), nil
}
// TransactionCount returns the number of transactions in a given block.
func (b *SimulatedBackend) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) {
b.mu.Lock()
defer b.mu.Unlock()
if blockHash == b.pendingBlock.Hash() {
return uint(b.pendingBlock.Transactions().Len()), nil
}
block := b.blockchain.GetBlockByHash(blockHash)
if block == nil {
return uint(0), errBlockDoesNotExist
}
return uint(block.Transactions().Len()), nil
}
// TransactionInBlock returns the transaction for a specific block at a specific index.
func (b *SimulatedBackend) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) {
b.mu.Lock()
defer b.mu.Unlock()
if blockHash == b.pendingBlock.Hash() {
transactions := b.pendingBlock.Transactions()
if uint(len(transactions)) < index+1 {
return nil, errTransactionDoesNotExist
}
return transactions[index], nil
}
block := b.blockchain.GetBlockByHash(blockHash)
if block == nil {
return nil, errBlockDoesNotExist
}
transactions := block.Transactions()
if uint(len(transactions)) < index+1 {
return nil, errTransactionDoesNotExist
}
return transactions[index], nil
}
// PendingCodeAt returns the code associated with an account in the pending state.
func (b *SimulatedBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) {
b.mu.Lock()
defer b.mu.Unlock()
return b.pendingState.GetCode(contract), nil
}
func newRevertError(result *core.ExecutionResult) *revertError {
reason, errUnpack := abi.UnpackRevert(result.Revert())
err := errors.New("execution reverted")
if errUnpack == nil {
err = fmt.Errorf("execution reverted: %v", reason)
}
return &revertError{
error: err,
reason: hexutil.Encode(result.Revert()),
} }
} }
// revertError is an API error that encompasses an EVM revert with JSON error
// code and a binary data blob.
type revertError struct {
error
reason string // revert reason hex encoded
}
// ErrorCode returns the JSON error code for a revert.
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
func (e *revertError) ErrorCode() int {
return 3
}
// ErrorData returns the hex encoded revert reason.
func (e *revertError) ErrorData() interface{} {
return e.reason
}
// CallContract executes a contract call.
func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
b.mu.Lock()
defer b.mu.Unlock()
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number) != 0 {
return nil, errBlockNumberUnsupported
}
return b.callContractAtHead(ctx, call)
}
// CallContractAtHash executes a contract call on a specific block hash.
func (b *SimulatedBackend) CallContractAtHash(ctx context.Context, call ethereum.CallMsg, blockHash common.Hash) ([]byte, error) {
b.mu.Lock()
defer b.mu.Unlock()
if blockHash != b.blockchain.CurrentBlock().Hash() {
return nil, errBlockHashUnsupported
}
return b.callContractAtHead(ctx, call)
}
// callContractAtHead executes a contract call against the latest block state.
func (b *SimulatedBackend) callContractAtHead(ctx context.Context, call ethereum.CallMsg) ([]byte, error) {
stateDB, err := b.blockchain.State()
if err != nil {
return nil, err
}
res, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), stateDB)
if err != nil {
return nil, err
}
// If the result contains a revert reason, try to unpack and return it.
if len(res.Revert()) > 0 {
return nil, newRevertError(res)
}
return res.Return(), res.Err
}
// PendingCallContract executes a contract call on the pending state.
func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error) {
b.mu.Lock()
defer b.mu.Unlock()
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
res, err := b.callContract(ctx, call, b.pendingBlock.Header(), b.pendingState)
if err != nil {
return nil, err
}
// If the result contains a revert reason, try to unpack and return it.
if len(res.Revert()) > 0 {
return nil, newRevertError(res)
}
return res.Return(), res.Err
}
// PendingNonceAt implements PendingStateReader.PendingNonceAt, retrieving
// the nonce currently pending for the account.
func (b *SimulatedBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
b.mu.Lock()
defer b.mu.Unlock()
return b.pendingState.GetOrNewStateObject(account).Nonce(), nil
}
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated
// chain doesn't have miners, we just return a gas price of 1 for any call.
func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
b.mu.Lock()
defer b.mu.Unlock()
if b.pendingBlock.Header().BaseFee != nil {
return b.pendingBlock.Header().BaseFee, nil
}
return big.NewInt(1), nil
}
// SuggestGasTipCap implements ContractTransactor.SuggestGasTipCap. Since the simulated
// chain doesn't have miners, we just return a gas tip of 1 for any call.
func (b *SimulatedBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
return big.NewInt(1), nil
}
// EstimateGas executes the requested code against the currently pending block/state and
// returns the used amount of gas.
func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) {
b.mu.Lock()
defer b.mu.Unlock()
// Determine the lowest and highest possible gas limits to binary search in between
var (
lo uint64 = params.TxGas - 1
hi uint64
cap uint64
)
if call.Gas >= params.TxGas {
hi = call.Gas
} else {
hi = b.pendingBlock.GasLimit()
}
// Normalize the max fee per gas the call is willing to spend.
var feeCap *big.Int
if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) {
return 0, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
} else if call.GasPrice != nil {
feeCap = call.GasPrice
} else if call.GasFeeCap != nil {
feeCap = call.GasFeeCap
} else {
feeCap = common.Big0
}
// Recap the highest gas allowance with account's balance.
if feeCap.BitLen() != 0 {
balance := b.pendingState.GetBalance(call.From) // from can't be nil
available := new(big.Int).Set(balance)
if call.Value != nil {
if call.Value.Cmp(available) >= 0 {
return 0, core.ErrInsufficientFundsForTransfer
}
available.Sub(available, call.Value)
}
allowance := new(big.Int).Div(available, feeCap)
if allowance.IsUint64() && hi > allowance.Uint64() {
transfer := call.Value
if transfer == nil {
transfer = new(big.Int)
}
log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance,
"sent", transfer, "feecap", feeCap, "fundable", allowance)
hi = allowance.Uint64()
}
}
cap = hi
// Create a helper to check if a gas allowance results in an executable transaction
executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
call.Gas = gas
snapshot := b.pendingState.Snapshot()
res, err := b.callContract(ctx, call, b.pendingBlock.Header(), b.pendingState)
b.pendingState.RevertToSnapshot(snapshot)
if err != nil {
if errors.Is(err, core.ErrIntrinsicGas) {
return true, nil, nil // Special case, raise gas limit
}
return true, nil, err // Bail out
}
return res.Failed(), res, nil
}
// Execute the binary search and hone in on an executable gas limit
for lo+1 < hi {
mid := (hi + lo) / 2
failed, _, err := executable(mid)
// If the error is not nil(consensus error), it means the provided message
// call or transaction will never be accepted no matter how much gas it is
// assigned. Return the error directly, don't struggle any more
if err != nil {
return 0, err
}
if failed {
lo = mid
} else {
hi = mid
}
}
// Reject the transaction as invalid if it still fails at the highest allowance
if hi == cap {
failed, result, err := executable(hi)
if err != nil {
return 0, err
}
if failed {
if result != nil && !errors.Is(result.Err, vm.ErrOutOfGas) {
if len(result.Revert()) > 0 {
return 0, newRevertError(result)
}
return 0, result.Err
}
// Otherwise, the specified gas cap is too low
return 0, fmt.Errorf("gas required exceeds allowance (%d)", cap)
}
}
return hi, nil
}
// callContract implements common code between normal and pending contract calls.
// state is modified during execution, make sure to copy it if necessary.
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, header *types.Header, stateDB *state.StateDB) (*core.ExecutionResult, error) {
// Gas prices post 1559 need to be initialized
if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) {
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
}
if !b.blockchain.Config().IsLondon(header.Number) {
// If there's no basefee, then it must be a non-1559 execution
if call.GasPrice == nil {
call.GasPrice = new(big.Int)
}
call.GasFeeCap, call.GasTipCap = call.GasPrice, call.GasPrice
} else {
// A basefee is provided, necessitating 1559-type execution
if call.GasPrice != nil {
// User specified the legacy gas field, convert to 1559 gas typing
call.GasFeeCap, call.GasTipCap = call.GasPrice, call.GasPrice
} else {
// User specified 1559 gas fields (or none), use those
if call.GasFeeCap == nil {
call.GasFeeCap = new(big.Int)
}
if call.GasTipCap == nil {
call.GasTipCap = new(big.Int)
}
// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
call.GasPrice = new(big.Int)
if call.GasFeeCap.BitLen() > 0 || call.GasTipCap.BitLen() > 0 {
call.GasPrice = math.BigMin(new(big.Int).Add(call.GasTipCap, header.BaseFee), call.GasFeeCap)
}
}
}
// Ensure message is initialized properly.
if call.Gas == 0 {
call.Gas = 10 * header.GasLimit
}
if call.Value == nil {
call.Value = new(big.Int)
}
// Set infinite balance to the fake caller account.
from := stateDB.GetOrNewStateObject(call.From)
from.SetBalance(math.MaxBig256)
// Execute the call.
msg := &core.Message{
From: call.From,
To: call.To,
Value: call.Value,
GasLimit: call.Gas,
GasPrice: call.GasPrice,
GasFeeCap: call.GasFeeCap,
GasTipCap: call.GasTipCap,
Data: call.Data,
AccessList: call.AccessList,
SkipAccountChecks: true,
}
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
txContext := core.NewEVMTxContext(msg)
evmContext := core.NewEVMBlockContext(header, b.blockchain, nil)
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
return core.ApplyMessage(vmEnv, msg, gasPool)
}
// SendTransaction updates the pending block to include the given transaction.
func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
b.mu.Lock()
defer b.mu.Unlock()
// Get the last block
block, err := b.blockByHash(ctx, b.pendingBlock.ParentHash())
if err != nil {
return errors.New("could not fetch parent")
}
// Check transaction validity
signer := types.MakeSigner(b.blockchain.Config(), block.Number(), block.Time())
sender, err := types.Sender(signer, tx)
if err != nil {
return fmt.Errorf("invalid transaction: %v", err)
}
nonce := b.pendingState.GetNonce(sender)
if tx.Nonce() != nonce {
return fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce)
}
// Include tx in chain
blocks, receipts := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
for _, tx := range b.pendingBlock.Transactions() {
block.AddTxWithChain(b.blockchain, tx)
}
block.AddTxWithChain(b.blockchain, tx)
})
stateDB, err := b.blockchain.State()
if err != nil {
return err
}
b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil)
b.pendingReceipts = receipts[0]
return nil
}
// FilterLogs executes a log filter operation, blocking during execution and
// returning all the results in one batch.
//
// TODO(karalabe): Deprecate when the subscription one can return past data too.
func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) {
var filter *filters.Filter
if query.BlockHash != nil {
// Block filter requested, construct a single-shot filter
filter = b.filterSystem.NewBlockFilter(*query.BlockHash, query.Addresses, query.Topics)
} else {
// Initialize unset filter boundaries to run from genesis to chain head
from := int64(0)
if query.FromBlock != nil {
from = query.FromBlock.Int64()
}
to := int64(-1)
if query.ToBlock != nil {
to = query.ToBlock.Int64()
}
// Construct the range filter
filter = b.filterSystem.NewRangeFilter(from, to, query.Addresses, query.Topics)
}
// Run the filter and return all the logs
logs, err := filter.Logs(ctx)
if err != nil {
return nil, err
}
res := make([]types.Log, len(logs))
for i, nLog := range logs {
res[i] = *nLog
}
return res, nil
}
// SubscribeFilterLogs creates a background log filtering operation, returning a
// subscription immediately, which can be used to stream the found events.
func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
// Subscribe to contract events
sink := make(chan []*types.Log)
sub, err := b.events.SubscribeLogs(query, sink)
if err != nil {
return nil, err
}
// Since we're getting logs in batches, we need to flatten them into a plain stream
return event.NewSubscription(func(quit <-chan struct{}) error {
defer sub.Unsubscribe()
for {
select {
case logs := <-sink:
for _, nlog := range logs {
select {
case ch <- *nlog:
case err := <-sub.Err():
return err
case <-quit:
return nil
}
}
case err := <-sub.Err():
return err
case <-quit:
return nil
}
}
}), nil
}
// SubscribeNewHead returns an event subscription for a new header.
func (b *SimulatedBackend) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) {
// subscribe to a new head
sink := make(chan *types.Header)
sub := b.events.SubscribeNewHeads(sink)
return event.NewSubscription(func(quit <-chan struct{}) error {
defer sub.Unsubscribe()
for {
select {
case head := <-sink:
select {
case ch <- head:
case err := <-sub.Err():
return err
case <-quit:
return nil
}
case err := <-sub.Err():
return err
case <-quit:
return nil
}
}
}), nil
}
// AdjustTime adds a time shift to the simulated clock.
// It can only be called on empty blocks.
func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
b.mu.Lock()
defer b.mu.Unlock()
if len(b.pendingBlock.Transactions()) != 0 {
return errors.New("could not adjust time on non-empty block")
}
// Get the last block
block := b.blockchain.GetBlockByHash(b.pendingBlock.ParentHash())
if block == nil {
return errors.New("could not find parent")
}
blocks, _ := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
block.OffsetTime(int64(adjustment.Seconds()))
})
stateDB, err := b.blockchain.State()
if err != nil {
return err
}
b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil)
return nil
}
// Blockchain returns the underlying blockchain.
func (b *SimulatedBackend) Blockchain() *core.BlockChain {
return b.blockchain
}
// filterBackend implements filters.Backend to support filtering for logs without
// taking bloom-bits acceleration structures into account.
type filterBackend struct {
db ethdb.Database
bc *core.BlockChain
backend *SimulatedBackend
}
func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db }
func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") }
func (fb *filterBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
switch number {
case rpc.PendingBlockNumber:
if block := fb.backend.pendingBlock; block != nil {
return block.Header(), nil
}
return nil, nil
case rpc.LatestBlockNumber:
return fb.bc.CurrentHeader(), nil
case rpc.FinalizedBlockNumber:
return fb.bc.CurrentFinalBlock(), nil
case rpc.SafeBlockNumber:
return fb.bc.CurrentSafeBlock(), nil
default:
return fb.bc.GetHeaderByNumber(uint64(number.Int64())), nil
}
}
func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
return fb.bc.GetHeaderByHash(hash), nil
}
func (fb *filterBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) {
if body := fb.bc.GetBody(hash); body != nil {
return body, nil
}
return nil, errors.New("block body not found")
}
func (fb *filterBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) {
return fb.backend.pendingBlock, fb.backend.pendingReceipts
}
func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
number := rawdb.ReadHeaderNumber(fb.db, hash)
if number == nil {
return nil, nil
}
header := rawdb.ReadHeader(fb.db, hash, *number)
if header == nil {
return nil, nil
}
return rawdb.ReadReceipts(fb.db, hash, *number, header.Time, fb.bc.Config()), nil
}
func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) {
logs := rawdb.ReadLogs(fb.db, hash, number)
return logs, nil
}
func (fb *filterBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return nullSubscription()
}
func (fb *filterBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
return fb.bc.SubscribeChainEvent(ch)
}
func (fb *filterBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
return fb.bc.SubscribeRemovedLogsEvent(ch)
}
func (fb *filterBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
return fb.bc.SubscribeLogsEvent(ch)
}
func (fb *filterBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription {
return nullSubscription()
}
func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 }
func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.MatcherSession) {
panic("not supported")
}
func (fb *filterBackend) ChainConfig() *params.ChainConfig {
panic("not supported")
}
func (fb *filterBackend) CurrentHeader() *types.Header {
panic("not supported")
}
func nullSubscription() event.Subscription {
return event.NewSubscription(func(quit <-chan struct{}) error {
<-quit
return nil
})
}

File diff suppressed because it is too large Load diff

View file

@ -305,6 +305,7 @@ var bindTests = []struct {
if err != nil { if err != nil {
t.Fatalf("Failed to deploy interactor contract: %v", err) t.Fatalf("Failed to deploy interactor contract: %v", err)
} }
sim.Commit()
if _, err := interactor.Transact(auth, "Transact string"); err != nil { if _, err := interactor.Transact(auth, "Transact string"); err != nil {
t.Fatalf("Failed to transact with interactor contract: %v", err) t.Fatalf("Failed to transact with interactor contract: %v", err)
} }
@ -512,6 +513,7 @@ var bindTests = []struct {
if err != nil { if err != nil {
t.Fatalf("Failed to deploy defaulter contract: %v", err) t.Fatalf("Failed to deploy defaulter contract: %v", err)
} }
sim.Commit()
if _, err := (&DefaulterRaw{defaulter}).Transfer(auth); err != nil { if _, err := (&DefaulterRaw{defaulter}).Transfer(auth); err != nil {
t.Fatalf("Failed to invoke default method: %v", err) t.Fatalf("Failed to invoke default method: %v", err)
} }
@ -1874,6 +1876,7 @@ var bindTests = []struct {
[]string{"0x6080604052348015600f57600080fd5b5060998061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063726c638214602d575b600080fd5b60336035565b005b60405163024876cd60e61b815260016004820152600260248201526003604482015260640160405180910390fdfea264697066735822122093f786a1bc60216540cd999fbb4a6109e0fef20abcff6e9107fb2817ca968f3c64736f6c63430008070033"}, []string{"0x6080604052348015600f57600080fd5b5060998061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063726c638214602d575b600080fd5b60336035565b005b60405163024876cd60e61b815260016004820152600260248201526003604482015260640160405180910390fdfea264697066735822122093f786a1bc60216540cd999fbb4a6109e0fef20abcff6e9107fb2817ca968f3c64736f6c63430008070033"},
[]string{`[{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError1","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError2","type":"error"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"},{"internalType":"uint256","name":"c","type":"uint256"}],"name":"MyError3","type":"error"},{"inputs":[],"name":"Error","outputs":[],"stateMutability":"pure","type":"function"}]`}, []string{`[{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError1","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError2","type":"error"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"},{"internalType":"uint256","name":"c","type":"uint256"}],"name":"MyError3","type":"error"},{"inputs":[],"name":"Error","outputs":[],"stateMutability":"pure","type":"function"}]`},
` `
"context"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
@ -1895,7 +1898,7 @@ var bindTests = []struct {
t.Fatal(err) t.Fatal(err)
} }
sim.Commit() sim.Commit()
_, err = bind.WaitDeployed(nil, sim, tx) _, err = bind.WaitDeployed(context.Background(), sim, tx)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -1926,6 +1929,7 @@ var bindTests = []struct {
bytecode: []string{`0x608060405234801561001057600080fd5b506040516101c43803806101c48339818101604052810190610032919061014a565b50610177565b6000604051905090565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6100958261004c565b810181811067ffffffffffffffff821117156100b4576100b361005d565b5b80604052505050565b60006100c7610038565b90506100d3828261008c565b919050565b6000819050919050565b6100eb816100d8565b81146100f657600080fd5b50565b600081519050610108816100e2565b92915050565b60006020828403121561012457610123610047565b5b61012e60206100bd565b9050600061013e848285016100f9565b60008301525092915050565b6000602082840312156101605761015f610042565b5b600061016e8482850161010e565b91505092915050565b603f806101856000396000f3fe6080604052600080fdfea2646970667358221220cdffa667affecefac5561f65f4a4ba914204a8d4eb859d8cd426fb306e5c12a364736f6c634300080a0033`}, bytecode: []string{`0x608060405234801561001057600080fd5b506040516101c43803806101c48339818101604052810190610032919061014a565b50610177565b6000604051905090565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6100958261004c565b810181811067ffffffffffffffff821117156100b4576100b361005d565b5b80604052505050565b60006100c7610038565b90506100d3828261008c565b919050565b6000819050919050565b6100eb816100d8565b81146100f657600080fd5b50565b600081519050610108816100e2565b92915050565b60006020828403121561012457610123610047565b5b61012e60206100bd565b9050600061013e848285016100f9565b60008301525092915050565b6000602082840312156101605761015f610042565b5b600061016e8482850161010e565b91505092915050565b603f806101856000396000f3fe6080604052600080fdfea2646970667358221220cdffa667affecefac5561f65f4a4ba914204a8d4eb859d8cd426fb306e5c12a364736f6c634300080a0033`},
abi: []string{`[{"inputs":[{"components":[{"internalType":"uint256","name":"field","type":"uint256"}],"internalType":"struct ConstructorWithStructParam.StructType","name":"st","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"}]`}, abi: []string{`[{"inputs":[{"components":[{"internalType":"uint256","name":"field","type":"uint256"}],"internalType":"struct ConstructorWithStructParam.StructType","name":"st","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"}]`},
imports: ` imports: `
"context"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
@ -1948,7 +1952,7 @@ var bindTests = []struct {
} }
sim.Commit() sim.Commit()
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil { if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil {
t.Logf("Deployment tx: %+v", tx) t.Logf("Deployment tx: %+v", tx)
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err) t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
} }
@ -1974,6 +1978,7 @@ var bindTests = []struct {
bytecode: []string{"0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033"}, bytecode: []string{"0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033"},
abi: []string{`[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "int256", "name": "msg", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "_msg", "type": "int256" } ], "name": "log", "type": "event" }, { "inputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "req", "type": "tuple" } ], "name": "addRequest", "outputs": [], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getRequest", "outputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "", "type": "tuple" } ], "stateMutability": "pure", "type": "function" } ]`}, abi: []string{`[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "int256", "name": "msg", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "_msg", "type": "int256" } ], "name": "log", "type": "event" }, { "inputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "req", "type": "tuple" } ], "name": "addRequest", "outputs": [], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getRequest", "outputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "", "type": "tuple" } ], "stateMutability": "pure", "type": "function" } ]`},
imports: ` imports: `
"context"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
@ -1996,7 +2001,7 @@ var bindTests = []struct {
} }
sim.Commit() sim.Commit()
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil { if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil {
t.Logf("Deployment tx: %+v", tx) t.Logf("Deployment tx: %+v", tx)
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err) t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
} }
@ -2014,6 +2019,7 @@ var bindTests = []struct {
bytecode: []string{"0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033"}, bytecode: []string{"0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033"},
abi: []string{`[{"inputs":[{"internalType":"uint256","name":"range","type":"uint256"}],"name":"functionWithKeywordParameter","outputs":[],"stateMutability":"pure","type":"function"}]`}, abi: []string{`[{"inputs":[{"internalType":"uint256","name":"range","type":"uint256"}],"name":"functionWithKeywordParameter","outputs":[],"stateMutability":"pure","type":"function"}]`},
imports: ` imports: `
"context"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
@ -2034,7 +2040,7 @@ var bindTests = []struct {
} }
sim.Commit() sim.Commit()
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil { if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil {
t.Errorf("error deploying the contract: %v", err) t.Errorf("error deploying the contract: %v", err)
} }
`, `,

View file

@ -24,11 +24,12 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient/simulated"
"github.com/ethereum/go-ethereum/params"
) )
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
@ -55,20 +56,19 @@ var waitDeployedTests = map[string]struct {
func TestWaitDeployed(t *testing.T) { func TestWaitDeployed(t *testing.T) {
t.Parallel() t.Parallel()
for name, test := range waitDeployedTests { for name, test := range waitDeployedTests {
backend := backends.NewSimulatedBackend( backend := simulated.NewBackend(
core.GenesisAlloc{ core.GenesisAlloc{
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)}, crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)},
}, },
10000000,
) )
defer backend.Close() defer backend.Close()
// Create the transaction // Create the transaction
head, _ := backend.HeaderByNumber(context.Background(), nil) // Should be child's, good enough head, _ := backend.Client().HeaderByNumber(context.Background(), nil) // Should be child's, good enough
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1)) gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, gasPrice, common.FromHex(test.code)) tx := types.NewContractCreation(0, big.NewInt(0), test.gas, gasPrice, common.FromHex(test.code))
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) tx, _ = types.SignTx(tx, types.LatestSignerForChainID(big.NewInt(1337)), testKey)
// Wait for it to get mined in the background. // Wait for it to get mined in the background.
var ( var (
@ -78,12 +78,12 @@ func TestWaitDeployed(t *testing.T) {
ctx = context.Background() ctx = context.Background()
) )
go func() { go func() {
address, err = bind.WaitDeployed(ctx, backend, tx) address, err = bind.WaitDeployed(ctx, backend.Client(), tx)
close(mined) close(mined)
}() }()
// Send and mine the transaction. // Send and mine the transaction.
backend.SendTransaction(ctx, tx) backend.Client().SendTransaction(ctx, tx)
backend.Commit() backend.Commit()
select { select {
@ -101,42 +101,40 @@ func TestWaitDeployed(t *testing.T) {
} }
func TestWaitDeployedCornerCases(t *testing.T) { func TestWaitDeployedCornerCases(t *testing.T) {
t.Parallel() backend := simulated.NewBackend(
backend := backends.NewSimulatedBackend(
core.GenesisAlloc{ core.GenesisAlloc{
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)}, crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)},
}, },
10000000,
) )
defer backend.Close() defer backend.Close()
head, _ := backend.HeaderByNumber(context.Background(), nil) // Should be child's, good enough head, _ := backend.Client().HeaderByNumber(context.Background(), nil) // Should be child's, good enough
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1)) gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
// Create a transaction to an account. // Create a transaction to an account.
code := "6060604052600a8060106000396000f360606040526008565b00" code := "6060604052600a8060106000396000f360606040526008565b00"
tx := types.NewTransaction(0, common.HexToAddress("0x01"), big.NewInt(0), 3000000, gasPrice, common.FromHex(code)) tx := types.NewTransaction(0, common.HexToAddress("0x01"), big.NewInt(0), 3000000, gasPrice, common.FromHex(code))
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) tx, _ = types.SignTx(tx, types.LatestSigner(params.AllDevChainProtocolChanges), testKey)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
backend.SendTransaction(ctx, tx) backend.Client().SendTransaction(ctx, tx)
backend.Commit() backend.Commit()
notContractCreation := errors.New("tx is not contract creation") notContractCreation := errors.New("tx is not contract creation")
if _, err := bind.WaitDeployed(ctx, backend, tx); err.Error() != notContractCreation.Error() { if _, err := bind.WaitDeployed(ctx, backend.Client(), tx); err.Error() != notContractCreation.Error() {
t.Errorf("error mismatch: want %q, got %q, ", notContractCreation, err) t.Errorf("error mismatch: want %q, got %q, ", notContractCreation, err)
} }
// Create a transaction that is not mined. // Create a transaction that is not mined.
tx = types.NewContractCreation(1, big.NewInt(0), 3000000, gasPrice, common.FromHex(code)) tx = types.NewContractCreation(1, big.NewInt(0), 3000000, gasPrice, common.FromHex(code))
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) tx, _ = types.SignTx(tx, types.LatestSigner(params.AllDevChainProtocolChanges), testKey)
go func() { go func() {
contextCanceled := errors.New("context canceled") contextCanceled := errors.New("context canceled")
if _, err := bind.WaitDeployed(ctx, backend, tx); err.Error() != contextCanceled.Error() { if _, err := bind.WaitDeployed(ctx, backend.Client(), tx); err.Error() != contextCanceled.Error() {
t.Errorf("error mismatch: want %q, got %q, ", contextCanceled, err) t.Errorf("error mismatch: want %q, got %q, ", contextCanceled, err)
} }
}() }()
backend.SendTransaction(ctx, tx) backend.Client().SendTransaction(ctx, tx)
cancel() cancel()
} }

View file

@ -24,6 +24,7 @@ import (
"reflect" "reflect"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
) )
@ -41,8 +42,7 @@ func MakeTopics(query ...[]interface{}) ([][]common.Hash, error) {
case common.Address: case common.Address:
copy(topic[common.HashLength-common.AddressLength:], rule[:]) copy(topic[common.HashLength-common.AddressLength:], rule[:])
case *big.Int: case *big.Int:
blob := rule.Bytes() copy(topic[:], math.U256Bytes(rule))
copy(topic[common.HashLength-len(blob):], blob)
case bool: case bool:
if rule { if rule {
topic[common.HashLength-1] = 1 topic[common.HashLength-1] = 1

View file

@ -17,6 +17,7 @@
package abi package abi
import ( import (
"math"
"math/big" "math/big"
"reflect" "reflect"
"testing" "testing"
@ -55,9 +56,27 @@ func TestMakeTopics(t *testing.T) {
false, false,
}, },
{ {
"support *big.Int types in topics", "support positive *big.Int types in topics",
args{[][]interface{}{{big.NewInt(1).Lsh(big.NewInt(2), 254)}}}, args{[][]interface{}{
[][]common.Hash{{common.Hash{128}}}, {big.NewInt(1)},
{big.NewInt(1).Lsh(big.NewInt(2), 254)},
}},
[][]common.Hash{
{common.HexToHash("0000000000000000000000000000000000000000000000000000000000000001")},
{common.Hash{128}},
},
false,
},
{
"support negative *big.Int types in topics",
args{[][]interface{}{
{big.NewInt(-1)},
{big.NewInt(math.MinInt64)},
}},
[][]common.Hash{
{common.MaxHash},
{common.HexToHash("ffffffffffffffffffffffffffffffffffffffffffffffff8000000000000000")},
},
false, false,
}, },
{ {

View file

@ -279,7 +279,7 @@ func (w *ledgerDriver) ledgerDerive(derivationPath []uint32) (common.Address, er
} }
hexstr := reply[1 : 1+int(reply[0])] hexstr := reply[1 : 1+int(reply[0])]
// Decode the hex sting into an Ethereum address and return // Decode the hex string into an Ethereum address and return
var address common.Address var address common.Address
if _, err = hex.Decode(address[:], hexstr); err != nil { if _, err = hex.Decode(address[:], hexstr); err != nil {
return common.Address{}, err return common.Address{}, err

View file

@ -20,7 +20,7 @@
# - NSIS Large Strings build, http://nsis.sourceforge.net/Special_Builds # - NSIS Large Strings build, http://nsis.sourceforge.net/Special_Builds
# - SFP, http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin (put dll in NSIS\Plugins\x86-ansi) # - SFP, http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin (put dll in NSIS\Plugins\x86-ansi)
# #
# After intalling NSIS extra the NSIS Large Strings build zip and replace the makensis.exe and the # After installing NSIS extra the NSIS Large Strings build zip and replace the makensis.exe and the
# files found in Stub. # files found in Stub.
# #
# based on: http://nsis.sourceforge.net/A_simple_installer_with_start_menu_shortcut_and_uninstaller # based on: http://nsis.sourceforge.net/A_simple_installer_with_start_menu_shortcut_and_uninstaller

View file

@ -76,9 +76,9 @@ func (s *Suite) EthTests() []utesting.Test {
{Name: "TestMaliciousHandshake", Fn: s.TestMaliciousHandshake}, {Name: "TestMaliciousHandshake", Fn: s.TestMaliciousHandshake},
{Name: "TestMaliciousStatus", Fn: s.TestMaliciousStatus}, {Name: "TestMaliciousStatus", Fn: s.TestMaliciousStatus},
// test transactions // test transactions
{Name: "TestLargeTxRequest", Fn: s.TestLargeTxRequest, Slow: true},
{Name: "TestTransaction", Fn: s.TestTransaction}, {Name: "TestTransaction", Fn: s.TestTransaction},
{Name: "TestInvalidTxs", Fn: s.TestInvalidTxs}, {Name: "TestInvalidTxs", Fn: s.TestInvalidTxs},
{Name: "TestLargeTxRequest", Fn: s.TestLargeTxRequest},
{Name: "TestNewPooledTxs", Fn: s.TestNewPooledTxs}, {Name: "TestNewPooledTxs", Fn: s.TestNewPooledTxs},
{Name: "TestBlobViolations", Fn: s.TestBlobViolations}, {Name: "TestBlobViolations", Fn: s.TestBlobViolations},
} }
@ -790,7 +790,7 @@ func (s *Suite) TestBlobViolations(t *utesting.T) {
if err := s.engine.sendForkchoiceUpdated(); err != nil { if err := s.engine.sendForkchoiceUpdated(); err != nil {
t.Fatalf("send fcu failed: %v", err) t.Fatalf("send fcu failed: %v", err)
} }
// Create blob txs for each tests with unqiue tx hashes. // Create blob txs for each tests with unique tx hashes.
var ( var (
t1 = s.makeBlobTxs(2, 3, 0x1) t1 = s.makeBlobTxs(2, 3, 0x1)
t2 = s.makeBlobTxs(2, 3, 0x2) t2 = s.makeBlobTxs(2, 3, 0x2)

View file

@ -63,6 +63,9 @@ func TestEthSuite(t *testing.T) {
} }
for _, test := range suite.EthTests() { for _, test := range suite.EthTests() {
t.Run(test.Name, func(t *testing.T) { t.Run(test.Name, func(t *testing.T) {
if test.Slow && testing.Short() {
t.Skipf("%s: skipping in -short mode", test.Name)
}
result := utesting.RunTests([]utesting.Test{{Name: test.Name, Fn: test.Fn}}, os.Stdout) result := utesting.RunTests([]utesting.Test{{Name: test.Name, Fn: test.Fn}}, os.Stdout)
if result[0].Failed { if result[0].Failed {
t.Fatal() t.Fatal()

View file

@ -128,7 +128,7 @@ func (s *Suite) sendInvalidTxs(txs []*types.Transaction) error {
invalids[tx.Hash()] = struct{}{} invalids[tx.Hash()] = struct{}{}
} }
// Get repsonses. // Get responses.
recvConn.SetReadDeadline(time.Now().Add(timeout)) recvConn.SetReadDeadline(time.Now().Add(timeout))
for { for {
msg, err := recvConn.ReadEth() msg, err := recvConn.ReadEth()

View file

@ -497,7 +497,7 @@ func FindnodeAmplificationWrongIP(t *utesting.T) {
// If we receive a NEIGHBORS response, the attack worked and the test fails. // If we receive a NEIGHBORS response, the attack worked and the test fails.
reply, _, _ := te.read(te.l2) reply, _, _ := te.read(te.l2)
if reply != nil { if reply != nil {
t.Error("Got NEIGHORS response for FINDNODE from wrong IP") t.Error("Got NEIGHBORS response for FINDNODE from wrong IP")
} }
} }

View file

@ -214,7 +214,7 @@ exitcode:3 OK
The chain configuration to be used for a transition is specified via the The chain configuration to be used for a transition is specified via the
`--state.fork` CLI flag. A list of possible values and configurations can be `--state.fork` CLI flag. A list of possible values and configurations can be
found in [`tests/init.go`](tests/init.go). found in [`tests/init.go`](../../tests/init.go).
#### Examples #### Examples
##### Basic usage ##### Basic usage

View file

@ -140,6 +140,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
rejectedTxs []*rejectedTx rejectedTxs []*rejectedTx
includedTxs types.Transactions includedTxs types.Transactions
gasUsed = uint64(0) gasUsed = uint64(0)
blobGasUsed = uint64(0)
receipts = make(types.Receipts, 0) receipts = make(types.Receipts, 0)
txIndex = 0 txIndex = 0
) )
@ -189,7 +190,6 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
} }
var blobGasUsed uint64
for i := 0; txIt.Next(); i++ { for i := 0; txIt.Next(); i++ {
tx, err := txIt.Tx() tx, err := txIt.Tx()
@ -210,15 +210,15 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
continue continue
} }
txBlobGas := uint64(0)
if tx.Type() == types.BlobTxType { if tx.Type() == types.BlobTxType {
txBlobGas := uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes())) txBlobGas = uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes()))
if used, max := blobGasUsed+txBlobGas, uint64(params.MaxBlobGasPerBlock); used > max { if used, max := blobGasUsed+txBlobGas, uint64(params.MaxBlobGasPerBlock); used > max {
err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max) err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max)
log.Warn("rejected tx", "index", i, "err", err) log.Warn("rejected tx", "index", i, "err", err)
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
continue continue
} }
blobGasUsed += txBlobGas
} }
tracer, err := getTracerFn(txIndex, tx.Hash()) tracer, err := getTracerFn(txIndex, tx.Hash())
if err != nil { if err != nil {
@ -247,6 +247,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
if hashError != nil { if hashError != nil {
return nil, nil, nil, NewError(ErrorMissingBlockhash, hashError) return nil, nil, nil, NewError(ErrorMissingBlockhash, hashError)
} }
blobGasUsed += txBlobGas
gasUsed += msgResult.UsedGas gasUsed += msgResult.UsedGas
// Receipt: // Receipt:

View file

@ -188,7 +188,7 @@ func Transition(ctx *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
// Dump the excution result // Dump the execution result
collector := make(Alloc) collector := make(Alloc)
s.DumpToCollector(collector, nil) s.DumpToCollector(collector, nil)
return dispatchOutput(ctx, baseDir, result, collector, body) return dispatchOutput(ctx, baseDir, result, collector, body)

View file

@ -43,12 +43,22 @@ import (
) )
var ( var (
removeStateDataFlag = &cli.BoolFlag{
Name: "remove.state",
Usage: "If set, selects the state data for removal",
}
removeChainDataFlag = &cli.BoolFlag{
Name: "remove.chain",
Usage: "If set, selects the state data for removal",
}
removedbCommand = &cli.Command{ removedbCommand = &cli.Command{
Action: removeDB, Action: removeDB,
Name: "removedb", Name: "removedb",
Usage: "Remove blockchain and state databases", Usage: "Remove blockchain and state databases",
ArgsUsage: "", ArgsUsage: "",
Flags: utils.DatabaseFlags, Flags: flags.Merge(utils.DatabaseFlags,
[]cli.Flag{removeStateDataFlag, removeChainDataFlag}),
Description: ` Description: `
Remove blockchain and state databases`, Remove blockchain and state databases`,
} }
@ -211,11 +221,11 @@ func removeDB(ctx *cli.Context) error {
} }
// Delete state data // Delete state data
statePaths := []string{rootDir, filepath.Join(ancientDir, rawdb.StateFreezerName)} statePaths := []string{rootDir, filepath.Join(ancientDir, rawdb.StateFreezerName)}
confirmAndRemoveDB(statePaths, "state data") confirmAndRemoveDB(statePaths, "state data", ctx, removeStateDataFlag.Name)
// Delete ancient chain // Delete ancient chain
chainPaths := []string{filepath.Join(ancientDir, rawdb.ChainFreezerName)} chainPaths := []string{filepath.Join(ancientDir, rawdb.ChainFreezerName)}
confirmAndRemoveDB(chainPaths, "ancient chain") confirmAndRemoveDB(chainPaths, "ancient chain", ctx, removeChainDataFlag.Name)
return nil return nil
} }
@ -238,14 +248,26 @@ func removeFolder(dir string) {
// confirmAndRemoveDB prompts the user for a last confirmation and removes the // confirmAndRemoveDB prompts the user for a last confirmation and removes the
// list of folders if accepted. // list of folders if accepted.
func confirmAndRemoveDB(paths []string, kind string) { func confirmAndRemoveDB(paths []string, kind string, ctx *cli.Context, removeFlagName string) {
var (
confirm bool
err error
)
msg := fmt.Sprintf("Location(s) of '%s': \n", kind) msg := fmt.Sprintf("Location(s) of '%s': \n", kind)
for _, path := range paths { for _, path := range paths {
msg += fmt.Sprintf("\t- %s\n", path) msg += fmt.Sprintf("\t- %s\n", path)
} }
fmt.Println(msg) fmt.Println(msg)
if ctx.IsSet(removeFlagName) {
confirm, err := prompt.Stdin.PromptConfirm(fmt.Sprintf("Remove '%s'?", kind)) confirm = ctx.Bool(removeFlagName)
if confirm {
fmt.Printf("Remove '%s'? [y/n] y\n", kind)
} else {
fmt.Printf("Remove '%s'? [y/n] n\n", kind)
}
} else {
confirm, err = prompt.Stdin.PromptConfirm(fmt.Sprintf("Remove '%s'?", kind))
}
switch { switch {
case err != nil: case err != nil:
utils.Fatalf("%v", err) utils.Fatalf("%v", err)

View file

@ -26,7 +26,6 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/holiman/uint256" "github.com/holiman/uint256"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@ -51,9 +50,6 @@ func (c customQuotedStringer) String() string {
// logTest is an entry point which spits out some logs. This is used by testing // logTest is an entry point which spits out some logs. This is used by testing
// to verify expected outputs // to verify expected outputs
func logTest(ctx *cli.Context) error { func logTest(ctx *cli.Context) error {
// clear field padding map
debug.ResetLogging()
{ // big.Int { // big.Int
ba, _ := new(big.Int).SetString("111222333444555678999", 10) // "111,222,333,444,555,678,999" ba, _ := new(big.Int).SetString("111222333444555678999", 10) // "111,222,333,444,555,678,999"
bb, _ := new(big.Int).SetString("-111222333444555678999", 10) // "-111,222,333,444,555,678,999" bb, _ := new(big.Int).SetString("-111222333444555678999", 10) // "-111,222,333,444,555,678,999"

View file

@ -203,7 +203,6 @@ var app = flags.NewApp("the go-ethereum command line interface")
func init() { func init() {
// Initialize the CLI app and start Geth // Initialize the CLI app and start Geth
app.Action = geth app.Action = geth
app.Copyright = "Copyright 2013-2023 The go-ethereum Authors"
app.Commands = []*cli.Command{ app.Commands = []*cli.Command{
// See chaincmd.go: // See chaincmd.go:
initCommand, initCommand,

View file

@ -29,7 +29,7 @@
{"t":"2023-11-22T15:42:00.408237+08:00","lvl":"info","msg":"repeated-key 2","xx":"short","xx":"longer"} {"t":"2023-11-22T15:42:00.408237+08:00","lvl":"info","msg":"repeated-key 2","xx":"short","xx":"longer"}
{"t":"2023-11-22T15:42:00.408241+08:00","lvl":"info","msg":"log at level info"} {"t":"2023-11-22T15:42:00.408241+08:00","lvl":"info","msg":"log at level info"}
{"t":"2023-11-22T15:42:00.408244+08:00","lvl":"warn","msg":"log at level warn"} {"t":"2023-11-22T15:42:00.408244+08:00","lvl":"warn","msg":"log at level warn"}
{"t":"2023-11-22T15:42:00.408247+08:00","lvl":"eror","msg":"log at level error"} {"t":"2023-11-22T15:42:00.408247+08:00","lvl":"error","msg":"log at level error"}
{"t":"2023-11-22T15:42:00.408251+08:00","lvl":"info","msg":"test","bar":"short","a":"aligned left"} {"t":"2023-11-22T15:42:00.408251+08:00","lvl":"info","msg":"test","bar":"short","a":"aligned left"}
{"t":"2023-11-22T15:42:00.408254+08:00","lvl":"info","msg":"test","bar":"a long message","a":1} {"t":"2023-11-22T15:42:00.408254+08:00","lvl":"info","msg":"test","bar":"a long message","a":1}
{"t":"2023-11-22T15:42:00.408258+08:00","lvl":"info","msg":"test","bar":"short","a":"aligned right"} {"t":"2023-11-22T15:42:00.408258+08:00","lvl":"info","msg":"test","bar":"short","a":"aligned right"}

View file

@ -29,7 +29,7 @@ t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="repeated-key 1" foo=alpha foo=beta
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="repeated-key 2" xx=short xx=longer t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="repeated-key 2" xx=short xx=longer
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="log at level info" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="log at level info"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=warn msg="log at level warn" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=warn msg="log at level warn"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=eror msg="log at level error" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=error msg="log at level error"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=test bar=short a="aligned left" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=test bar=short a="aligned left"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=test bar="a long message" a=1 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=test bar="a long message" a=1
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=test bar=short a="aligned right" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=test bar=short a="aligned right"

View file

@ -25,7 +25,9 @@ import (
"flag" "flag"
"fmt" "fmt"
"io" "io"
"math"
"os" "os"
"strconv"
"strings" "strings"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -37,6 +39,7 @@ var (
reverseMode = flag.Bool("reverse", false, "convert ASCII to rlp") reverseMode = flag.Bool("reverse", false, "convert ASCII to rlp")
noASCII = flag.Bool("noascii", false, "don't print ASCII strings readably") noASCII = flag.Bool("noascii", false, "don't print ASCII strings readably")
single = flag.Bool("single", false, "print only the first element, discard the rest") single = flag.Bool("single", false, "print only the first element, discard the rest")
showpos = flag.Bool("pos", false, "display element byte posititions")
) )
func init() { func init() {
@ -52,17 +55,17 @@ If the filename is omitted, data is read from stdin.`)
func main() { func main() {
flag.Parse() flag.Parse()
var r io.Reader var r *inStream
switch { switch {
case *hexMode != "": case *hexMode != "":
data, err := hex.DecodeString(strings.TrimPrefix(*hexMode, "0x")) data, err := hex.DecodeString(strings.TrimPrefix(*hexMode, "0x"))
if err != nil { if err != nil {
die(err) die(err)
} }
r = bytes.NewReader(data) r = newInStream(bytes.NewReader(data), int64(len(data)))
case flag.NArg() == 0: case flag.NArg() == 0:
r = os.Stdin r = newInStream(bufio.NewReader(os.Stdin), 0)
case flag.NArg() == 1: case flag.NArg() == 1:
fd, err := os.Open(flag.Arg(0)) fd, err := os.Open(flag.Arg(0))
@ -70,13 +73,19 @@ func main() {
die(err) die(err)
} }
defer fd.Close() defer fd.Close()
r = fd var size int64
finfo, err := fd.Stat()
if err == nil {
size = finfo.Size()
}
r = newInStream(bufio.NewReader(fd), size)
default: default:
fmt.Fprintln(os.Stderr, "Error: too many arguments") fmt.Fprintln(os.Stderr, "Error: too many arguments")
flag.Usage() flag.Usage()
os.Exit(2) os.Exit(2)
} }
out := os.Stdout out := os.Stdout
if *reverseMode { if *reverseMode {
data, err := textToRlp(r) data, err := textToRlp(r)
@ -93,10 +102,10 @@ func main() {
} }
} }
func rlpToText(r io.Reader, out io.Writer) error { func rlpToText(in *inStream, out io.Writer) error {
s := rlp.NewStream(r, 0) stream := rlp.NewStream(in, 0)
for { for {
if err := dump(s, 0, out); err != nil { if err := dump(in, stream, 0, out); err != nil {
if err != io.EOF { if err != io.EOF {
return err return err
} }
@ -110,7 +119,10 @@ func rlpToText(r io.Reader, out io.Writer) error {
return nil return nil
} }
func dump(s *rlp.Stream, depth int, out io.Writer) error { func dump(in *inStream, s *rlp.Stream, depth int, out io.Writer) error {
if *showpos {
fmt.Fprintf(out, "%s: ", in.posLabel())
}
kind, size, err := s.Kind() kind, size, err := s.Kind()
if err != nil { if err != nil {
return err return err
@ -137,7 +149,7 @@ func dump(s *rlp.Stream, depth int, out io.Writer) error {
if i > 0 { if i > 0 {
fmt.Fprint(out, ",\n") fmt.Fprint(out, ",\n")
} }
if err := dump(s, depth+1, out); err == rlp.EOL { if err := dump(in, s, depth+1, out); err == rlp.EOL {
break break
} else if err != nil { } else if err != nil {
return err return err
@ -208,3 +220,36 @@ func textToRlp(r io.Reader) ([]byte, error) {
data, err := rlp.EncodeToBytes(obj[0]) data, err := rlp.EncodeToBytes(obj[0])
return data, err return data, err
} }
type inStream struct {
br rlp.ByteReader
pos int
columns int
}
func newInStream(br rlp.ByteReader, totalSize int64) *inStream {
col := int(math.Ceil(math.Log10(float64(totalSize))))
return &inStream{br: br, columns: col}
}
func (rc *inStream) Read(b []byte) (n int, err error) {
n, err = rc.br.Read(b)
rc.pos += n
return n, err
}
func (rc *inStream) ReadByte() (byte, error) {
b, err := rc.br.ReadByte()
if err == nil {
rc.pos++
}
return b, err
}
func (rc *inStream) posLabel() string {
l := strconv.FormatInt(int64(rc.pos), 10)
if len(l) < rc.columns {
l = strings.Repeat(" ", rc.columns-len(l)) + l
}
return l
}

View file

@ -34,7 +34,8 @@ func TestRoundtrip(t *testing.T) {
"0xc780c0c1c0825208", "0xc780c0c1c0825208",
} { } {
var out strings.Builder var out strings.Builder
err := rlpToText(bytes.NewReader(common.FromHex(want)), &out) in := newInStream(bytes.NewReader(common.FromHex(want)), 0)
err := rlpToText(in, &out)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -104,4 +104,10 @@ var (
// ErrBlobFeeCapTooLow is returned if the transaction fee cap is less than the // ErrBlobFeeCapTooLow is returned if the transaction fee cap is less than the
// blob gas fee of the block. // blob gas fee of the block.
ErrBlobFeeCapTooLow = errors.New("max fee per blob gas less than block blob gas fee") ErrBlobFeeCapTooLow = errors.New("max fee per blob gas less than block blob gas fee")
// ErrMissingBlobHashes is returned if a blob transaction has no blob hashes.
ErrMissingBlobHashes = errors.New("blob transaction missing blob hashes")
// ErrBlobTxCreate is returned if a blob transaction has no explicit to field.
ErrBlobTxCreate = errors.New("blob transaction of type create")
) )

View file

@ -91,8 +91,10 @@ func TestCreation(t *testing.T) {
{5000000, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block {5000000, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block
{5062605, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // First London block {5062605, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // First London block
{6000000, 1678832735, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // Last London block {6000000, 1678832735, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // Last London block
{6000001, 1678832736, ID{Hash: checksumToBytes(0xf9843abf), Next: 0}}, // First Shanghai block {6000001, 1678832736, ID{Hash: checksumToBytes(0xf9843abf), Next: 1705473120}}, // First Shanghai block
{6500000, 2678832736, ID{Hash: checksumToBytes(0xf9843abf), Next: 0}}, // Future Shanghai block {6500002, 1705473119, ID{Hash: checksumToBytes(0xf9843abf), Next: 1705473120}}, // Last Shanghai block
{6500003, 1705473120, ID{Hash: checksumToBytes(0x70cc14e2), Next: 0}}, // First Cancun block
{6500003, 2705473120, ID{Hash: checksumToBytes(0x70cc14e2), Next: 0}}, // Future Cancun block
}, },
}, },
// Sepolia test cases // Sepolia test cases

View file

@ -48,11 +48,11 @@ func TestDump(t *testing.T) {
s := &stateEnv{db: db, state: sdb} s := &stateEnv{db: db, state: sdb}
// generate a few entries // generate a few entries
obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01})) obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
obj1.AddBalance(big.NewInt(22)) obj1.AddBalance(big.NewInt(22))
obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02})) obj2 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3}) obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3})
obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02})) obj3 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x02}))
obj3.SetBalance(big.NewInt(44)) obj3.SetBalance(big.NewInt(44))
// write some of them to the trie // write some of them to the trie
@ -105,13 +105,13 @@ func TestIterativeDump(t *testing.T) {
s := &stateEnv{db: db, state: sdb} s := &stateEnv{db: db, state: sdb}
// generate a few entries // generate a few entries
obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01})) obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
obj1.AddBalance(big.NewInt(22)) obj1.AddBalance(big.NewInt(22))
obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02})) obj2 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3}) obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3})
obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02})) obj3 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x02}))
obj3.SetBalance(big.NewInt(44)) obj3.SetBalance(big.NewInt(44))
obj4 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x00})) obj4 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x00}))
obj4.AddBalance(big.NewInt(1337)) obj4.AddBalance(big.NewInt(1337))
// write some of them to the trie // write some of them to the trie

View file

@ -374,7 +374,7 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
// AddBalance adds amount to the account associated with addr. // AddBalance adds amount to the account associated with addr.
func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) { func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) {
stateObject := s.GetOrNewStateObject(addr) stateObject := s.getOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.AddBalance(amount) stateObject.AddBalance(amount)
} }
@ -382,35 +382,35 @@ func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) {
// SubBalance subtracts amount from the account associated with addr. // SubBalance subtracts amount from the account associated with addr.
func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) { func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) {
stateObject := s.GetOrNewStateObject(addr) stateObject := s.getOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SubBalance(amount) stateObject.SubBalance(amount)
} }
} }
func (s *StateDB) SetBalance(addr common.Address, amount *big.Int) { func (s *StateDB) SetBalance(addr common.Address, amount *big.Int) {
stateObject := s.GetOrNewStateObject(addr) stateObject := s.getOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetBalance(amount) stateObject.SetBalance(amount)
} }
} }
func (s *StateDB) SetNonce(addr common.Address, nonce uint64) { func (s *StateDB) SetNonce(addr common.Address, nonce uint64) {
stateObject := s.GetOrNewStateObject(addr) stateObject := s.getOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetNonce(nonce) stateObject.SetNonce(nonce)
} }
} }
func (s *StateDB) SetCode(addr common.Address, code []byte) { func (s *StateDB) SetCode(addr common.Address, code []byte) {
stateObject := s.GetOrNewStateObject(addr) stateObject := s.getOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetCode(crypto.Keccak256Hash(code), code) stateObject.SetCode(crypto.Keccak256Hash(code), code)
} }
} }
func (s *StateDB) SetState(addr common.Address, key, value common.Hash) { func (s *StateDB) SetState(addr common.Address, key, value common.Hash) {
stateObject := s.GetOrNewStateObject(addr) stateObject := s.getOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetState(key, value) stateObject.SetState(key, value)
} }
@ -431,7 +431,7 @@ func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common
if _, ok := s.stateObjectsDestruct[addr]; !ok { if _, ok := s.stateObjectsDestruct[addr]; !ok {
s.stateObjectsDestruct[addr] = nil s.stateObjectsDestruct[addr] = nil
} }
stateObject := s.GetOrNewStateObject(addr) stateObject := s.getOrNewStateObject(addr)
for k, v := range storage { for k, v := range storage {
stateObject.SetState(k, v) stateObject.SetState(k, v)
} }
@ -614,8 +614,8 @@ func (s *StateDB) setStateObject(object *stateObject) {
s.stateObjects[object.Address()] = object s.stateObjects[object.Address()] = object
} }
// GetOrNewStateObject retrieves a state object or create a new state object if nil. // getOrNewStateObject retrieves a state object or create a new state object if nil.
func (s *StateDB) GetOrNewStateObject(addr common.Address) *stateObject { func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject {
stateObject := s.getStateObject(addr) stateObject := s.getStateObject(addr)
if stateObject == nil { if stateObject == nil {
stateObject, _ = s.createObject(addr) stateObject, _ = s.createObject(addr)

View file

@ -166,7 +166,7 @@ func TestCopy(t *testing.T) {
orig, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) orig, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
for i := byte(0); i < 255; i++ { for i := byte(0); i < 255; i++ {
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
obj.AddBalance(big.NewInt(int64(i))) obj.AddBalance(big.NewInt(int64(i)))
orig.updateStateObject(obj) orig.updateStateObject(obj)
} }
@ -180,9 +180,9 @@ func TestCopy(t *testing.T) {
// modify all in memory // modify all in memory
for i := byte(0); i < 255; i++ { for i := byte(0); i < 255; i++ {
origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) origObj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) copyObj := copy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) ccopyObj := ccopy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
origObj.AddBalance(big.NewInt(2 * int64(i))) origObj.AddBalance(big.NewInt(2 * int64(i)))
copyObj.AddBalance(big.NewInt(3 * int64(i))) copyObj.AddBalance(big.NewInt(3 * int64(i)))
@ -208,9 +208,9 @@ func TestCopy(t *testing.T) {
// Verify that the three states have been updated independently // Verify that the three states have been updated independently
for i := byte(0); i < 255; i++ { for i := byte(0); i < 255; i++ {
origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) origObj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) copyObj := copy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) ccopyObj := ccopy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 { if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 {
t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want) t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want)
@ -531,7 +531,7 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
func TestTouchDelete(t *testing.T) { func TestTouchDelete(t *testing.T) {
s := newStateEnv() s := newStateEnv()
s.state.GetOrNewStateObject(common.Address{}) s.state.getOrNewStateObject(common.Address{})
root, _ := s.state.Commit(0, false) root, _ := s.state.Commit(0, false)
s.state, _ = New(root, s.state.db, s.state.snaps) s.state, _ = New(root, s.state.db, s.state.snaps)
@ -1158,7 +1158,7 @@ func TestDeleteStorage(t *testing.T) {
fastState, _ := New(root, db, snaps) fastState, _ := New(root, db, snaps)
slowState, _ := New(root, db, nil) slowState, _ := New(root, db, nil)
obj := fastState.GetOrNewStateObject(addr) obj := fastState.getOrNewStateObject(addr)
storageRoot := obj.data.Root storageRoot := obj.data.Root
_, _, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) _, _, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot)

View file

@ -57,7 +57,7 @@ func makeTestState(scheme string) (ethdb.Database, Database, *trie.Database, com
// Fill it with some arbitrary data // Fill it with some arbitrary data
var accounts []*testAccount var accounts []*testAccount
for i := byte(0); i < 96; i++ { for i := byte(0); i < 96; i++ {
obj := state.GetOrNewStateObject(common.BytesToAddress([]byte{i})) obj := state.getOrNewStateObject(common.BytesToAddress([]byte{i}))
acc := &testAccount{address: common.BytesToAddress([]byte{i})} acc := &testAccount{address: common.BytesToAddress([]byte{i})}
obj.AddBalance(big.NewInt(int64(11 * i))) obj.AddBalance(big.NewInt(int64(11 * i)))

View file

@ -17,7 +17,6 @@
package core package core
import ( import (
"errors"
"fmt" "fmt"
"math" "math"
"math/big" "math/big"
@ -315,8 +314,14 @@ func (st *StateTransition) preCheck() error {
} }
// Check the blob version validity // Check the blob version validity
if msg.BlobHashes != nil { if msg.BlobHashes != nil {
// The to field of a blob tx type is mandatory, and a `BlobTx` transaction internally
// has it as a non-nillable value, so any msg derived from blob transaction has it non-nil.
// However, messages created through RPC (eth_call) don't have this restriction.
if msg.To == nil {
return ErrBlobTxCreate
}
if len(msg.BlobHashes) == 0 { if len(msg.BlobHashes) == 0 {
return errors.New("blob transaction missing blob hashes") return ErrMissingBlobHashes
} }
for i, hash := range msg.BlobHashes { for i, hash := range msg.BlobHashes {
if hash[0] != params.BlobTxHashVersion { if hash[0] != params.BlobTxHashVersion {

View file

@ -583,7 +583,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
txs[0].evictionBlobFeeJumps = txs[0].blobfeeJumps txs[0].evictionBlobFeeJumps = txs[0].blobfeeJumps
for i := 1; i < len(txs); i++ { for i := 1; i < len(txs); i++ {
// If there's no nonce gap, initialize the evicion thresholds as the // If there's no nonce gap, initialize the eviction thresholds as the
// minimum between the cumulative thresholds and the current tx fees // minimum between the cumulative thresholds and the current tx fees
if txs[i].nonce == txs[i-1].nonce+1 { if txs[i].nonce == txs[i-1].nonce+1 {
txs[i].evictionExecTip = txs[i-1].evictionExecTip txs[i].evictionExecTip = txs[i-1].evictionExecTip
@ -1355,7 +1355,7 @@ func (p *BlobPool) drop() {
p.stored -= uint64(drop.size) p.stored -= uint64(drop.size)
delete(p.lookup, drop.hash) delete(p.lookup, drop.hash)
// Remove the transaction from the pool's evicion heap: // Remove the transaction from the pool's eviction heap:
// - If the entire account was dropped, pop off the address // - If the entire account was dropped, pop off the address
// - Otherwise, if the new tail has better eviction caps, fix the heap // - Otherwise, if the new tail has better eviction caps, fix the heap
if last { if last {

View file

@ -197,7 +197,7 @@ var (
gasStaticCallEIP2929 = makeCallVariantGasCallEIP2929(gasStaticCall) gasStaticCallEIP2929 = makeCallVariantGasCallEIP2929(gasStaticCall)
gasCallCodeEIP2929 = makeCallVariantGasCallEIP2929(gasCallCode) gasCallCodeEIP2929 = makeCallVariantGasCallEIP2929(gasCallCode)
gasSelfdestructEIP2929 = makeSelfdestructGasFn(true) gasSelfdestructEIP2929 = makeSelfdestructGasFn(true)
// gasSelfdestructEIP3529 implements the changes in EIP-2539 (no refunds) // gasSelfdestructEIP3529 implements the changes in EIP-3529 (no refunds)
gasSelfdestructEIP3529 = makeSelfdestructGasFn(false) gasSelfdestructEIP3529 = makeSelfdestructGasFn(false)
// gasSStoreEIP2929 implements gas cost for SSTORE according to EIP-2929 // gasSStoreEIP2929 implements gas cost for SSTORE according to EIP-2929
@ -214,12 +214,12 @@ var (
// see gasSStoreEIP2200(...) in core/vm/gas_table.go for more info about how EIP 2200 is specified // see gasSStoreEIP2200(...) in core/vm/gas_table.go for more info about how EIP 2200 is specified
gasSStoreEIP2929 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP2200) gasSStoreEIP2929 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP2200)
// gasSStoreEIP2539 implements gas cost for SSTORE according to EIP-2539 // gasSStoreEIP3529 implements gas cost for SSTORE according to EIP-3529
// Replace `SSTORE_CLEARS_SCHEDULE` with `SSTORE_RESET_GAS + ACCESS_LIST_STORAGE_KEY_COST` (4,800) // Replace `SSTORE_CLEARS_SCHEDULE` with `SSTORE_RESET_GAS + ACCESS_LIST_STORAGE_KEY_COST` (4,800)
gasSStoreEIP3529 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP3529) gasSStoreEIP3529 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP3529)
) )
// makeSelfdestructGasFn can create the selfdestruct dynamic gas function for EIP-2929 and EIP-2539 // makeSelfdestructGasFn can create the selfdestruct dynamic gas function for EIP-2929 and EIP-3529
func makeSelfdestructGasFn(refundsEnabled bool) gasFunc { func makeSelfdestructGasFn(refundsEnabled bool) gasFunc {
gasFunc := func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { gasFunc := func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var ( var (

View file

@ -179,7 +179,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
var ( var (
vmenv = NewEnv(cfg) vmenv = NewEnv(cfg)
sender = cfg.State.GetOrNewStateObject(cfg.Origin) sender = vm.AccountRef(cfg.Origin)
statedb = cfg.State statedb = cfg.State
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time)
) )

View file

@ -260,7 +260,7 @@ func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *st
} else { } else {
context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil)
} }
return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig) return vm.NewEVM(context, txContext, state, b.ChainConfig(), *vmConfig)
} }
func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {

View file

@ -19,16 +19,17 @@ package catalyst
import ( import (
"crypto/rand" "crypto/rand"
"errors" "errors"
"math/big"
"sync" "sync"
"time" "time"
"github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
@ -81,6 +82,11 @@ type SimulatedBeacon struct {
lastBlockTime uint64 lastBlockTime uint64
} }
// NewSimulatedBeacon constructs a new simulated beacon chain.
// Period sets the period in which blocks should be produced.
//
// - If period is set to 0, a block is produced on every transaction.
// via Commit, Fork and AdjustTime.
func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, error) { func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, error) {
block := eth.BlockChain().CurrentBlock() block := eth.BlockChain().CurrentBlock()
current := engine.ForkchoiceStateV1{ current := engine.ForkchoiceStateV1{
@ -116,7 +122,9 @@ func (c *SimulatedBeacon) setFeeRecipient(feeRecipient common.Address) {
// Start invokes the SimulatedBeacon life-cycle function in a goroutine. // Start invokes the SimulatedBeacon life-cycle function in a goroutine.
func (c *SimulatedBeacon) Start() error { func (c *SimulatedBeacon) Start() error {
if c.period == 0 { if c.period == 0 {
go c.loopOnDemand() // if period is set to 0, do not mine at all
// this is used in the simulated backend where blocks
// are explicitly mined via Commit, AdjustTime and Fork
} else { } else {
go c.loop() go c.loop()
} }
@ -131,10 +139,9 @@ func (c *SimulatedBeacon) Stop() error {
// sealBlock initiates payload building for a new block and creates a new block // sealBlock initiates payload building for a new block and creates a new block
// with the completed payload. // with the completed payload.
func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal) error { func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp uint64) error {
tstamp := uint64(time.Now().Unix()) if timestamp <= c.lastBlockTime {
if tstamp <= c.lastBlockTime { timestamp = c.lastBlockTime + 1
tstamp = c.lastBlockTime + 1
} }
c.feeRecipientLock.Lock() c.feeRecipientLock.Lock()
feeRecipient := c.feeRecipient feeRecipient := c.feeRecipient
@ -149,7 +156,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal) error {
var random [32]byte var random [32]byte
rand.Read(random[:]) rand.Read(random[:])
fcResponse, err := c.engineAPI.ForkchoiceUpdatedV2(c.curForkchoiceState, &engine.PayloadAttributes{ fcResponse, err := c.engineAPI.ForkchoiceUpdatedV2(c.curForkchoiceState, &engine.PayloadAttributes{
Timestamp: tstamp, Timestamp: timestamp,
SuggestedFeeRecipient: feeRecipient, SuggestedFeeRecipient: feeRecipient,
Withdrawals: withdrawals, Withdrawals: withdrawals,
Random: random, Random: random,
@ -183,6 +190,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal) error {
return err return err
} }
c.setCurrentState(payload.BlockHash, finalizedHash) c.setCurrentState(payload.BlockHash, finalizedHash)
// Mark the block containing the payload as canonical // Mark the block containing the payload as canonical
if _, err = c.engineAPI.ForkchoiceUpdatedV2(c.curForkchoiceState, nil); err != nil { if _, err = c.engineAPI.ForkchoiceUpdatedV2(c.curForkchoiceState, nil); err != nil {
return err return err
@ -191,32 +199,6 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal) error {
return nil return nil
} }
// loopOnDemand runs the block production loop for "on-demand" configuration (period = 0)
func (c *SimulatedBeacon) loopOnDemand() {
var (
newTxs = make(chan core.NewTxsEvent)
sub = c.eth.TxPool().SubscribeTransactions(newTxs, true)
)
defer sub.Unsubscribe()
for {
select {
case <-c.shutdownCh:
return
case w := <-c.withdrawals.pending:
withdrawals := append(c.withdrawals.gatherPending(9), w)
if err := c.sealBlock(withdrawals); err != nil {
log.Warn("Error performing sealing work", "err", err)
}
case <-newTxs:
withdrawals := c.withdrawals.gatherPending(10)
if err := c.sealBlock(withdrawals); err != nil {
log.Warn("Error performing sealing work", "err", err)
}
}
}
}
// loop runs the block production loop for non-zero period configuration // loop runs the block production loop for non-zero period configuration
func (c *SimulatedBeacon) loop() { func (c *SimulatedBeacon) loop() {
timer := time.NewTimer(0) timer := time.NewTimer(0)
@ -226,7 +208,7 @@ func (c *SimulatedBeacon) loop() {
return return
case <-timer.C: case <-timer.C:
withdrawals := c.withdrawals.gatherPending(10) withdrawals := c.withdrawals.gatherPending(10)
if err := c.sealBlock(withdrawals); err != nil { if err := c.sealBlock(withdrawals, uint64(time.Now().Unix())); err != nil {
log.Warn("Error performing sealing work", "err", err) log.Warn("Error performing sealing work", "err", err)
} else { } else {
timer.Reset(time.Second * time.Duration(c.period)) timer.Reset(time.Second * time.Duration(c.period))
@ -235,8 +217,8 @@ func (c *SimulatedBeacon) loop() {
} }
} }
// finalizedBlockHash returns the block hash of the finalized block corresponding to the given number // finalizedBlockHash returns the block hash of the finalized block corresponding
// or nil if doesn't exist in the chain. // to the given number or nil if doesn't exist in the chain.
func (c *SimulatedBeacon) finalizedBlockHash(number uint64) *common.Hash { func (c *SimulatedBeacon) finalizedBlockHash(number uint64) *common.Hash {
var finalizedNumber uint64 var finalizedNumber uint64
if number%devEpochLength == 0 { if number%devEpochLength == 0 {
@ -244,7 +226,6 @@ func (c *SimulatedBeacon) finalizedBlockHash(number uint64) *common.Hash {
} else { } else {
finalizedNumber = (number - 1) / devEpochLength * devEpochLength finalizedNumber = (number - 1) / devEpochLength * devEpochLength
} }
if finalizedBlock := c.eth.BlockChain().GetBlockByNumber(finalizedNumber); finalizedBlock != nil { if finalizedBlock := c.eth.BlockChain().GetBlockByNumber(finalizedNumber); finalizedBlock != nil {
fh := finalizedBlock.Hash() fh := finalizedBlock.Hash()
return &fh return &fh
@ -261,11 +242,60 @@ func (c *SimulatedBeacon) setCurrentState(headHash, finalizedHash common.Hash) {
} }
} }
// Commit seals a block on demand.
func (c *SimulatedBeacon) Commit() common.Hash {
withdrawals := c.withdrawals.gatherPending(10)
if err := c.sealBlock(withdrawals, uint64(time.Now().Unix())); err != nil {
log.Warn("Error performing sealing work", "err", err)
}
return c.eth.BlockChain().CurrentBlock().Hash()
}
// Rollback un-sends previously added transactions.
func (c *SimulatedBeacon) Rollback() {
// Flush all transactions from the transaction pools
maxUint256 := new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1)
c.eth.TxPool().SetGasTip(maxUint256)
// Set the gas tip back to accept new transactions
// TODO (Marius van der Wijden): set gas tip to parameter passed by config
c.eth.TxPool().SetGasTip(big.NewInt(params.GWei))
}
// Fork sets the head to the provided hash.
func (c *SimulatedBeacon) Fork(parentHash common.Hash) error {
if len(c.eth.TxPool().Pending(false)) != 0 {
return errors.New("pending block dirty")
}
parent := c.eth.BlockChain().GetBlockByHash(parentHash)
if parent == nil {
return errors.New("parent not found")
}
return c.eth.BlockChain().SetHead(parent.NumberU64())
}
// AdjustTime creates a new block with an adjusted timestamp.
func (c *SimulatedBeacon) AdjustTime(adjustment time.Duration) error {
if len(c.eth.TxPool().Pending(false)) != 0 {
return errors.New("could not adjust time on non-empty block")
}
parent := c.eth.BlockChain().CurrentBlock()
if parent == nil {
return errors.New("parent not found")
}
withdrawals := c.withdrawals.gatherPending(10)
return c.sealBlock(withdrawals, parent.Time+uint64(adjustment))
}
func RegisterSimulatedBeaconAPIs(stack *node.Node, sim *SimulatedBeacon) { func RegisterSimulatedBeaconAPIs(stack *node.Node, sim *SimulatedBeacon) {
api := &api{sim}
if sim.period == 0 {
// mine on demand if period is set to 0
go api.loop()
}
stack.RegisterAPIs([]rpc.API{ stack.RegisterAPIs([]rpc.API{
{ {
Namespace: "dev", Namespace: "dev",
Service: &api{sim}, Service: api,
Version: "1.0", Version: "1.0",
}, },
}) })

View file

@ -18,19 +18,44 @@ package catalyst
import ( import (
"context" "context"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
) )
type api struct { type api struct {
simBeacon *SimulatedBeacon sim *SimulatedBeacon
}
func (a *api) loop() {
var (
newTxs = make(chan core.NewTxsEvent)
sub = a.sim.eth.TxPool().SubscribeTransactions(newTxs, true)
)
defer sub.Unsubscribe()
for {
select {
case <-a.sim.shutdownCh:
return
case w := <-a.sim.withdrawals.pending:
withdrawals := append(a.sim.withdrawals.gatherPending(9), w)
if err := a.sim.sealBlock(withdrawals, uint64(time.Now().Unix())); err != nil {
log.Warn("Error performing sealing work", "err", err)
}
case <-newTxs:
a.sim.Commit()
}
}
} }
func (a *api) AddWithdrawal(ctx context.Context, withdrawal *types.Withdrawal) error { func (a *api) AddWithdrawal(ctx context.Context, withdrawal *types.Withdrawal) error {
return a.simBeacon.withdrawals.add(withdrawal) return a.sim.withdrawals.add(withdrawal)
} }
func (a *api) SetFeeRecipient(ctx context.Context, feeRecipient common.Address) { func (a *api) SetFeeRecipient(ctx context.Context, feeRecipient common.Address) {
a.simBeacon.setFeeRecipient(feeRecipient) a.sim.setFeeRecipient(feeRecipient)
} }

View file

@ -101,16 +101,15 @@ func (api *DownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, error
go func() { go func() {
statuses := make(chan interface{}) statuses := make(chan interface{})
sub := api.SubscribeSyncStatus(statuses) sub := api.SubscribeSyncStatus(statuses)
defer sub.Unsubscribe()
for { for {
select { select {
case status := <-statuses: case status := <-statuses:
notifier.Notify(rpcSub.ID, status) notifier.Notify(rpcSub.ID, status)
case <-rpcSub.Err(): case <-rpcSub.Err():
sub.Unsubscribe()
return return
case <-notifier.Closed(): case <-notifier.Closed():
sub.Unsubscribe()
return return
} }
} }

View file

@ -159,6 +159,8 @@ func (api *FilterAPI) NewPendingTransactions(ctx context.Context, fullTx *bool)
go func() { go func() {
txs := make(chan []*types.Transaction, 128) txs := make(chan []*types.Transaction, 128)
pendingTxSub := api.events.SubscribePendingTxs(txs) pendingTxSub := api.events.SubscribePendingTxs(txs)
defer pendingTxSub.Unsubscribe()
chainConfig := api.sys.backend.ChainConfig() chainConfig := api.sys.backend.ChainConfig()
for { for {
@ -176,10 +178,8 @@ func (api *FilterAPI) NewPendingTransactions(ctx context.Context, fullTx *bool)
} }
} }
case <-rpcSub.Err(): case <-rpcSub.Err():
pendingTxSub.Unsubscribe()
return return
case <-notifier.Closed(): case <-notifier.Closed():
pendingTxSub.Unsubscribe()
return return
} }
} }
@ -233,16 +233,15 @@ func (api *FilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, error) {
go func() { go func() {
headers := make(chan *types.Header) headers := make(chan *types.Header)
headersSub := api.events.SubscribeNewHeads(headers) headersSub := api.events.SubscribeNewHeads(headers)
defer headersSub.Unsubscribe()
for { for {
select { select {
case h := <-headers: case h := <-headers:
notifier.Notify(rpcSub.ID, h) notifier.Notify(rpcSub.ID, h)
case <-rpcSub.Err(): case <-rpcSub.Err():
headersSub.Unsubscribe()
return return
case <-notifier.Closed(): case <-notifier.Closed():
headersSub.Unsubscribe()
return return
} }
} }
@ -269,6 +268,7 @@ func (api *FilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subsc
} }
go func() { go func() {
defer logsSub.Unsubscribe()
for { for {
select { select {
case logs := <-matchedLogs: case logs := <-matchedLogs:
@ -277,10 +277,8 @@ func (api *FilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subsc
notifier.Notify(rpcSub.ID, &log) notifier.Notify(rpcSub.ID, &log)
} }
case <-rpcSub.Err(): // client send an unsubscribe request case <-rpcSub.Err(): // client send an unsubscribe request
logsSub.Unsubscribe()
return return
case <-notifier.Closed(): // connection dropped case <-notifier.Closed(): // connection dropped
logsSub.Unsubscribe()
return return
} }
} }

View file

@ -57,6 +57,7 @@ type peerSet struct {
lock sync.RWMutex lock sync.RWMutex
closed bool closed bool
quitCh chan struct{} // Quit channel to signal termination
} }
// newPeerSet creates a new peer set to track the active participants. // newPeerSet creates a new peer set to track the active participants.
@ -65,6 +66,7 @@ func newPeerSet() *peerSet {
peers: make(map[string]*ethPeer), peers: make(map[string]*ethPeer),
snapWait: make(map[string]chan *snap.Peer), snapWait: make(map[string]chan *snap.Peer),
snapPend: make(map[string]*snap.Peer), snapPend: make(map[string]*snap.Peer),
quitCh: make(chan struct{}),
} }
} }
@ -129,7 +131,15 @@ func (ps *peerSet) waitSnapExtension(peer *eth.Peer) (*snap.Peer, error) {
ps.snapWait[id] = wait ps.snapWait[id] = wait
ps.lock.Unlock() ps.lock.Unlock()
return <-wait, nil select {
case p := <-wait:
return p, nil
case <-ps.quitCh:
ps.lock.Lock()
delete(ps.snapWait, id)
ps.lock.Unlock()
return nil, errPeerSetClosed
}
} }
// registerPeer injects a new `eth` peer into the working set, or returns an error // registerPeer injects a new `eth` peer into the working set, or returns an error
@ -256,5 +266,8 @@ func (ps *peerSet) close() {
for _, p := range ps.peers { for _, p := range ps.peers {
p.Disconnect(p2p.DiscQuitting) p.Disconnect(p2p.DiscQuitting)
} }
if !ps.closed {
close(ps.quitCh)
}
ps.closed = true ps.closed = true
} }

View file

@ -122,12 +122,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
} }
// Configure a blockchain with the given prestate // Configure a blockchain with the given prestate
var ( var (
signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
origin, _ = signer.Sender(tx)
txContext = vm.TxContext{
Origin: origin,
GasPrice: tx.GasPrice(),
}
context = vm.BlockContext{ context = vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
@ -146,11 +141,11 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to create call tracer: %v", err) t.Fatalf("failed to create call tracer: %v", err)
} }
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)
} }
evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if err != nil { if err != nil {
t.Fatalf("failed to execute transaction: %v", err) t.Fatalf("failed to execute transaction: %v", err)
@ -222,10 +217,6 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
b.Fatalf("failed to parse testcase input: %v", err) b.Fatalf("failed to parse testcase input: %v", err)
} }
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil {
b.Fatalf("failed to prepare transaction for tracing: %v", err)
}
origin, _ := signer.Sender(tx) origin, _ := signer.Sender(tx)
txContext := vm.TxContext{ txContext := vm.TxContext{
Origin: origin, Origin: origin,
@ -240,6 +231,10 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
Difficulty: (*big.Int)(test.Context.Difficulty), Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit), GasLimit: uint64(test.Context.GasLimit),
} }
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
if err != nil {
b.Fatalf("failed to prepare transaction for tracing: %v", err)
}
triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
defer triedb.Close() defer triedb.Close()

View file

@ -86,11 +86,6 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
return fmt.Errorf("failed to parse testcase input: %v", err) return fmt.Errorf("failed to parse testcase input: %v", err)
} }
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
origin, _ := signer.Sender(tx)
txContext := vm.TxContext{
Origin: origin,
GasPrice: tx.GasPrice(),
}
context := vm.BlockContext{ context := vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
@ -108,12 +103,11 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
if err != nil { if err != nil {
return fmt.Errorf("failed to create call tracer: %v", err) return fmt.Errorf("failed to create call tracer: %v", err)
} }
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil { if err != nil {
return fmt.Errorf("failed to prepare transaction for tracing: %v", err) return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
} }
evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if _, err = st.TransitionDb(); err != nil { if _, err = st.TransitionDb(); err != nil {

View file

@ -92,12 +92,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
} }
// Configure a blockchain with the given prestate // Configure a blockchain with the given prestate
var ( var (
signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
origin, _ = signer.Sender(tx)
txContext = vm.TxContext{
Origin: origin,
GasPrice: tx.GasPrice(),
}
context = vm.BlockContext{ context = vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
@ -116,11 +111,11 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to create call tracer: %v", err) t.Fatalf("failed to create call tracer: %v", err)
} }
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)
} }
evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if _, err = st.TransitionDb(); err != nil { if _, err = st.TransitionDb(); err != nil {
t.Fatalf("failed to execute transaction: %v", err) t.Fatalf("failed to execute transaction: %v", err)

View file

@ -83,7 +83,7 @@
}, },
"post": { "post": {
"0x808b4da0be6c9512e948521452227efc619bea52": { "0x808b4da0be6c9512e948521452227efc619bea52": {
"balance": "0x2cd72a36dd031f089", "balance": "0x2cd987071ba2346b6",
"nonce": 1223933 "nonce": 1223933
}, },
"0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": { "0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": {

View file

@ -90,7 +90,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
//EnableReturnData: false, //EnableReturnData: false,
}) })
evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer})
msg, err := core.TransactionToMessage(tx, signer, nil) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
if err != nil { if err != nil {
b.Fatalf("failed to prepare transaction for tracing: %v", err) b.Fatalf("failed to prepare transaction for tracing: %v", err)
} }

View file

@ -307,10 +307,8 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
var r *types.Receipt var r *types.Receipt
err := ec.c.CallContext(ctx, &r, "eth_getTransactionReceipt", txHash) err := ec.c.CallContext(ctx, &r, "eth_getTransactionReceipt", txHash)
if err == nil { if err == nil && r == nil {
if r == nil { return nil, ethereum.NotFound
return nil, ethereum.NotFound
}
} }
return r, err return r, err
} }

View file

@ -264,7 +264,7 @@ func TestEthClient(t *testing.T) {
func(t *testing.T) { testBalanceAt(t, client) }, func(t *testing.T) { testBalanceAt(t, client) },
}, },
"TxInBlockInterrupted": { "TxInBlockInterrupted": {
func(t *testing.T) { testTransactionInBlockInterrupted(t, client) }, func(t *testing.T) { testTransactionInBlock(t, client) },
}, },
"ChainID": { "ChainID": {
func(t *testing.T) { testChainID(t, client) }, func(t *testing.T) { testChainID(t, client) },
@ -329,7 +329,7 @@ func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) {
got.Number = big.NewInt(0) // hack to make DeepEqual work got.Number = big.NewInt(0) // hack to make DeepEqual work
} }
if !reflect.DeepEqual(got, tt.want) { if !reflect.DeepEqual(got, tt.want) {
t.Fatalf("HeaderByNumber(%v)\n = %v\nwant %v", tt.block, got, tt.want) t.Fatalf("HeaderByNumber(%v) got = %v, want %v", tt.block, got, tt.want)
} }
}) })
} }
@ -381,7 +381,7 @@ func testBalanceAt(t *testing.T, client *rpc.Client) {
} }
} }
func testTransactionInBlockInterrupted(t *testing.T, client *rpc.Client) { func testTransactionInBlock(t *testing.T, client *rpc.Client) {
ec := NewClient(client) ec := NewClient(client)
// Get current block by number. // Get current block by number.
@ -390,22 +390,27 @@ func testTransactionInBlockInterrupted(t *testing.T, client *rpc.Client) {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
// Test tx in block interrupted.
ctx, cancel := context.WithCancel(context.Background())
cancel()
<-ctx.Done() // Ensure the close of the Done channel
tx, err := ec.TransactionInBlock(ctx, block.Hash(), 0)
if tx != nil {
t.Fatal("transaction should be nil")
}
if err == nil || err == ethereum.NotFound {
t.Fatal("error should not be nil/notfound")
}
// Test tx in block not found. // Test tx in block not found.
if _, err := ec.TransactionInBlock(context.Background(), block.Hash(), 20); err != ethereum.NotFound { if _, err := ec.TransactionInBlock(context.Background(), block.Hash(), 20); err != ethereum.NotFound {
t.Fatal("error should be ethereum.NotFound") t.Fatal("error should be ethereum.NotFound")
} }
// Test tx in block found.
tx, err := ec.TransactionInBlock(context.Background(), block.Hash(), 0)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if tx.Hash() != testTx1.Hash() {
t.Fatalf("unexpected transaction: %v", tx)
}
tx, err = ec.TransactionInBlock(context.Background(), block.Hash(), 1)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if tx.Hash() != testTx2.Hash() {
t.Fatalf("unexpected transaction: %v", tx)
}
} }
func testChainID(t *testing.T, client *rpc.Client) { func testChainID(t *testing.T, client *rpc.Client) {

View file

@ -169,7 +169,7 @@ func testAccessList(t *testing.T, client *rpc.Client) {
From: testAddr, From: testAddr,
To: &common.Address{}, To: &common.Address{},
Gas: 21000, Gas: 21000,
GasPrice: big.NewInt(765625000), GasPrice: big.NewInt(875000000),
Value: big.NewInt(1), Value: big.NewInt(1),
} }
al, gas, vmErr, err := ec.CreateAccessList(context.Background(), msg) al, gas, vmErr, err := ec.CreateAccessList(context.Background(), msg)

View file

@ -0,0 +1,187 @@
// Copyright 2023 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 simulated
import (
"time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/catalyst"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
// Client exposes the methods provided by the Ethereum RPC client.
type Client interface {
ethereum.BlockNumberReader
ethereum.ChainReader
ethereum.ChainStateReader
ethereum.ContractCaller
ethereum.GasEstimator
ethereum.GasPricer
ethereum.GasPricer1559
ethereum.FeeHistoryReader
ethereum.LogFilterer
ethereum.PendingStateReader
ethereum.PendingContractCaller
ethereum.TransactionReader
ethereum.TransactionSender
ethereum.ChainIDReader
}
// simClient wraps ethclient. This exists to prevent extracting ethclient.Client
// from the Client interface returned by Backend.
type simClient struct {
*ethclient.Client
}
// Backend is a simulated blockchain. You can use it to test your contracts or
// other code that interacts with the Ethereum chain.
type Backend struct {
eth *eth.Ethereum
beacon *catalyst.SimulatedBeacon
client simClient
}
// NewBackend creates a new simulated blockchain that can be used as a backend for
// contract bindings in unit tests.
//
// A simulated backend always uses chainID 1337.
func NewBackend(alloc core.GenesisAlloc, options ...func(nodeConf *node.Config, ethConf *ethconfig.Config)) *Backend {
// Create the default configurations for the outer node shell and the Ethereum
// service to mutate with the options afterwards
nodeConf := node.DefaultConfig
nodeConf.DataDir = ""
nodeConf.P2P = p2p.Config{NoDiscovery: true}
ethConf := ethconfig.Defaults
ethConf.Genesis = &core.Genesis{
Config: params.AllDevChainProtocolChanges,
GasLimit: ethconfig.Defaults.Miner.GasCeil,
Alloc: alloc,
}
ethConf.SyncMode = downloader.FullSync
ethConf.TxPool.NoLocals = true
for _, option := range options {
option(&nodeConf, &ethConf)
}
// Assemble the Ethereum stack to run the chain with
stack, err := node.New(&nodeConf)
if err != nil {
panic(err) // this should never happen
}
sim, err := newWithNode(stack, &ethConf, 0)
if err != nil {
panic(err) // this should never happen
}
return sim
}
// newWithNode sets up a simulated backend on an existing node. The provided node
// must not be started and will be started by this method.
func newWithNode(stack *node.Node, conf *eth.Config, blockPeriod uint64) (*Backend, error) {
backend, err := eth.New(stack, conf)
if err != nil {
return nil, err
}
// Register the filter system
filterSystem := filters.NewFilterSystem(backend.APIBackend, filters.Config{})
stack.RegisterAPIs([]rpc.API{{
Namespace: "eth",
Service: filters.NewFilterAPI(filterSystem, false),
}})
// Start the node
if err := stack.Start(); err != nil {
return nil, err
}
// Set up the simulated beacon
beacon, err := catalyst.NewSimulatedBeacon(blockPeriod, backend)
if err != nil {
return nil, err
}
// Reorg our chain back to genesis
if err := beacon.Fork(backend.BlockChain().GetCanonicalHash(0)); err != nil {
return nil, err
}
return &Backend{
eth: backend,
beacon: beacon,
client: simClient{ethclient.NewClient(stack.Attach())},
}, nil
}
// Close shuts down the simBackend.
// The simulated backend can't be used afterwards.
func (n *Backend) Close() error {
if n.client.Client != nil {
n.client.Close()
n.client = simClient{}
}
if n.beacon != nil {
err := n.beacon.Stop()
n.beacon = nil
return err
}
return nil
}
// Commit seals a block and moves the chain forward to a new empty block.
func (n *Backend) Commit() common.Hash {
return n.beacon.Commit()
}
// Rollback removes all pending transactions, reverting to the last committed state.
func (n *Backend) Rollback() {
n.beacon.Rollback()
}
// Fork creates a side-chain that can be used to simulate reorgs.
//
// This function should be called with the ancestor block where the new side
// chain should be started. Transactions (old and new) can then be applied on
// top and Commit-ed.
//
// Note, the side-chain will only become canonical (and trigger the events) when
// it becomes longer. Until then CallContract will still operate on the current
// canonical chain.
//
// There is a % chance that the side chain becomes canonical at the same length
// to simulate live network behavior.
func (n *Backend) Fork(parentHash common.Hash) error {
return n.beacon.Fork(parentHash)
}
// AdjustTime changes the block timestamp and creates a new block.
// It can only be called on empty blocks.
func (n *Backend) AdjustTime(adjustment time.Duration) error {
return n.beacon.AdjustTime(adjustment)
}
// Client returns a client that accesses the simulated chain.
func (n *Backend) Client() Client {
return n.client
}

View file

@ -0,0 +1,309 @@
// Copyright 2019 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 simulated
import (
"context"
"crypto/ecdsa"
"math/big"
"math/rand"
"testing"
"time"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)
var _ bind.ContractBackend = (Client)(nil)
var (
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
)
func simTestBackend(testAddr common.Address) *Backend {
return NewBackend(
core.GenesisAlloc{
testAddr: {Balance: big.NewInt(10000000000000000)},
},
)
}
func newTx(sim *Backend, key *ecdsa.PrivateKey) (*types.Transaction, error) {
client := sim.Client()
// create a signed transaction to send
head, _ := client.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
addr := crypto.PubkeyToAddress(key.PublicKey)
chainid, _ := client.ChainID(context.Background())
nonce, err := client.PendingNonceAt(context.Background(), addr)
if err != nil {
return nil, err
}
tx := types.NewTx(&types.DynamicFeeTx{
ChainID: chainid,
Nonce: nonce,
GasTipCap: big.NewInt(1),
GasFeeCap: gasPrice,
Gas: 21000,
To: &addr,
})
return types.SignTx(tx, types.LatestSignerForChainID(chainid), key)
}
func TestNewBackend(t *testing.T) {
sim := NewBackend(core.GenesisAlloc{})
defer sim.Close()
client := sim.Client()
num, err := client.BlockNumber(context.Background())
if err != nil {
t.Fatal(err)
}
if num != 0 {
t.Fatalf("expected 0 got %v", num)
}
// Create a block
sim.Commit()
num, err = client.BlockNumber(context.Background())
if err != nil {
t.Fatal(err)
}
if num != 1 {
t.Fatalf("expected 1 got %v", num)
}
}
func TestAdjustTime(t *testing.T) {
sim := NewBackend(core.GenesisAlloc{})
defer sim.Close()
client := sim.Client()
block1, _ := client.BlockByNumber(context.Background(), nil)
// Create a block
if err := sim.AdjustTime(time.Minute); err != nil {
t.Fatal(err)
}
block2, _ := client.BlockByNumber(context.Background(), nil)
prevTime := block1.Time()
newTime := block2.Time()
if newTime-prevTime != uint64(time.Minute) {
t.Errorf("adjusted time not equal to 60 seconds. prev: %v, new: %v", prevTime, newTime)
}
}
func TestSendTransaction(t *testing.T) {
sim := simTestBackend(testAddr)
defer sim.Close()
client := sim.Client()
ctx := context.Background()
signedTx, err := newTx(sim, testKey)
if err != nil {
t.Errorf("could not create transaction: %v", err)
}
// send tx to simulated backend
err = client.SendTransaction(ctx, signedTx)
if err != nil {
t.Errorf("could not add tx to pending block: %v", err)
}
sim.Commit()
block, err := client.BlockByNumber(ctx, big.NewInt(1))
if err != nil {
t.Errorf("could not get block at height 1: %v", err)
}
if signedTx.Hash() != block.Transactions()[0].Hash() {
t.Errorf("did not commit sent transaction. expected hash %v got hash %v", block.Transactions()[0].Hash(), signedTx.Hash())
}
}
// TestFork check that the chain length after a reorg is correct.
// Steps:
// 1. Save the current block which will serve as parent for the fork.
// 2. Mine n blocks with n ∈ [0, 20].
// 3. Assert that the chain length is n.
// 4. Fork by using the parent block as ancestor.
// 5. Mine n+1 blocks which should trigger a reorg.
// 6. Assert that the chain length is n+1.
// Since Commit() was called 2n+1 times in total,
// having a chain length of just n+1 means that a reorg occurred.
func TestFork(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr)
defer sim.Close()
client := sim.Client()
ctx := context.Background()
// 1.
parent, _ := client.HeaderByNumber(ctx, nil)
// 2.
n := int(rand.Int31n(21))
for i := 0; i < n; i++ {
sim.Commit()
}
// 3.
b, _ := client.BlockNumber(ctx)
if b != uint64(n) {
t.Error("wrong chain length")
}
// 4.
sim.Fork(parent.Hash())
// 5.
for i := 0; i < n+1; i++ {
sim.Commit()
}
// 6.
b, _ = client.BlockNumber(ctx)
if b != uint64(n+1) {
t.Error("wrong chain length")
}
}
// TestForkResendTx checks that re-sending a TX after a fork
// is possible and does not cause a "nonce mismatch" panic.
// Steps:
// 1. Save the current block which will serve as parent for the fork.
// 2. Send a transaction.
// 3. Check that the TX is included in block 1.
// 4. Fork by using the parent block as ancestor.
// 5. Mine a block, Re-send the transaction and mine another one.
// 6. Check that the TX is now included in block 2.
func TestForkResendTx(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr)
defer sim.Close()
client := sim.Client()
ctx := context.Background()
// 1.
parent, _ := client.HeaderByNumber(ctx, nil)
// 2.
tx, err := newTx(sim, testKey)
if err != nil {
t.Fatalf("could not create transaction: %v", err)
}
client.SendTransaction(ctx, tx)
sim.Commit()
// 3.
receipt, _ := client.TransactionReceipt(ctx, tx.Hash())
if h := receipt.BlockNumber.Uint64(); h != 1 {
t.Errorf("TX included in wrong block: %d", h)
}
// 4.
if err := sim.Fork(parent.Hash()); err != nil {
t.Errorf("forking: %v", err)
}
// 5.
sim.Commit()
if err := client.SendTransaction(ctx, tx); err != nil {
t.Fatalf("sending transaction: %v", err)
}
sim.Commit()
receipt, _ = client.TransactionReceipt(ctx, tx.Hash())
if h := receipt.BlockNumber.Uint64(); h != 2 {
t.Errorf("TX included in wrong block: %d", h)
}
}
func TestCommitReturnValue(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr)
defer sim.Close()
client := sim.Client()
ctx := context.Background()
// Test if Commit returns the correct block hash
h1 := sim.Commit()
cur, _ := client.HeaderByNumber(ctx, nil)
if h1 != cur.Hash() {
t.Error("Commit did not return the hash of the last block.")
}
// Create a block in the original chain (containing a transaction to force different block hashes)
head, _ := client.HeaderByNumber(ctx, nil) // Should be child's, good enough
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
_tx := types.NewTransaction(0, testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
tx, _ := types.SignTx(_tx, types.HomesteadSigner{}, testKey)
client.SendTransaction(ctx, tx)
h2 := sim.Commit()
// Create another block in the original chain
sim.Commit()
// Fork at the first bock
if err := sim.Fork(h1); err != nil {
t.Errorf("forking: %v", err)
}
// Test if Commit returns the correct block hash after the reorg
h2fork := sim.Commit()
if h2 == h2fork {
t.Error("The block in the fork and the original block are the same block!")
}
if header, err := client.HeaderByHash(ctx, h2fork); err != nil || header == nil {
t.Error("Could not retrieve the just created block (side-chain)")
}
}
// TestAdjustTimeAfterFork ensures that after a fork, AdjustTime uses the pending fork
// block's parent rather than the canonical head's parent.
func TestAdjustTimeAfterFork(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr)
defer sim.Close()
client := sim.Client()
ctx := context.Background()
sim.Commit() // h1
h1, _ := client.HeaderByNumber(ctx, nil)
sim.Commit() // h2
sim.Fork(h1.Hash())
sim.AdjustTime(1 * time.Second)
sim.Commit()
head, _ := client.HeaderByNumber(ctx, nil)
if head.Number.Uint64() == 2 && head.ParentHash != h1.Hash() {
t.Errorf("failed to build block on fork")
}
}

View file

@ -0,0 +1,39 @@
// Copyright 2024 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 simulated
import (
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/node"
)
// WithBlockGasLimit configures the simulated backend to target a specific gas limit
// when producing blocks.
func WithBlockGasLimit(gaslimit uint64) func(nodeConf *node.Config, ethConf *ethconfig.Config) {
return func(nodeConf *node.Config, ethConf *ethconfig.Config) {
ethConf.Genesis.GasLimit = gaslimit
ethConf.Miner.GasCeil = gaslimit
}
}
// WithCallGasLimit configures the simulated backend to cap eth_calls to a specific
// gas limit when running client operations.
func WithCallGasLimit(gaslimit uint64) func(nodeConf *node.Config, ethConf *ethconfig.Config) {
return func(nodeConf *node.Config, ethConf *ethconfig.Config) {
ethConf.RPCGasCap = gaslimit
}
}

View file

@ -0,0 +1,73 @@
// Copyright 2024 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 simulated
import (
"context"
"math/big"
"strings"
"testing"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/params"
)
// Tests that the simulator starts with the initial gas limit in the genesis block,
// and that it keeps the same target value.
func TestWithBlockGasLimitOption(t *testing.T) {
// Construct a simulator, targeting a different gas limit
sim := NewBackend(core.GenesisAlloc{}, WithBlockGasLimit(12_345_678))
defer sim.Close()
client := sim.Client()
genesis, err := client.BlockByNumber(context.Background(), big.NewInt(0))
if err != nil {
t.Fatalf("failed to retrieve genesis block: %v", err)
}
if genesis.GasLimit() != 12_345_678 {
t.Errorf("genesis gas limit mismatch: have %v, want %v", genesis.GasLimit(), 12_345_678)
}
// Produce a number of blocks and verify the locked in gas target
sim.Commit()
head, err := client.BlockByNumber(context.Background(), big.NewInt(1))
if err != nil {
t.Fatalf("failed to retrieve head block: %v", err)
}
if head.GasLimit() != 12_345_678 {
t.Errorf("head gas limit mismatch: have %v, want %v", head.GasLimit(), 12_345_678)
}
}
// Tests that the simulator honors the RPC call caps set by the options.
func TestWithCallGasLimitOption(t *testing.T) {
// Construct a simulator, targeting a different gas limit
sim := NewBackend(core.GenesisAlloc{
testAddr: {Balance: big.NewInt(10000000000000000)},
}, WithCallGasLimit(params.TxGas-1))
defer sim.Close()
client := sim.Client()
_, err := client.CallContract(context.Background(), ethereum.CallMsg{
From: testAddr,
To: &testAddr,
Gas: 21000,
}, nil)
if !strings.Contains(err.Error(), core.ErrIntrinsicGas.Error()) {
t.Fatalf("error mismatch: have %v, want %v", err, core.ErrIntrinsicGas)
}
}

View file

@ -199,6 +199,16 @@ type GasPricer interface {
SuggestGasPrice(ctx context.Context) (*big.Int, error) SuggestGasPrice(ctx context.Context) (*big.Int, error)
} }
// GasPricer1559 provides access to the EIP-1559 gas price oracle.
type GasPricer1559 interface {
SuggestGasTipCap(ctx context.Context) (*big.Int, error)
}
// FeeHistoryReader provides access to the fee history oracle.
type FeeHistoryReader interface {
FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*FeeHistory, error)
}
// FeeHistory provides recent fee market data that consumers can use to determine // FeeHistory provides recent fee market data that consumers can use to determine
// a reasonable maxPriorityFeePerGas value. // a reasonable maxPriorityFeePerGas value.
type FeeHistory struct { type FeeHistory struct {
@ -239,3 +249,13 @@ type GasEstimator interface {
type PendingStateEventer interface { type PendingStateEventer interface {
SubscribePendingTransactions(ctx context.Context, ch chan<- *types.Transaction) (Subscription, error) SubscribePendingTransactions(ctx context.Context, ch chan<- *types.Transaction) (Subscription, error)
} }
// BlockNumberReader provides access to the current block number.
type BlockNumberReader interface {
BlockNumber(ctx context.Context) (uint64, error)
}
// ChainIDReader provides access to the chain ID.
type ChainIDReader interface {
ChainID(ctx context.Context) (*big.Int, error)
}

View file

@ -168,22 +168,12 @@ var Flags = []cli.Flag{
} }
var ( var (
glogger *log.GlogHandler glogger *log.GlogHandler
logOutputFile io.WriteCloser logOutputFile io.WriteCloser
defaultTerminalHandler *log.TerminalHandler
) )
func init() { func init() {
defaultTerminalHandler = log.NewTerminalHandler(os.Stderr, false) glogger = log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
glogger = log.NewGlogHandler(defaultTerminalHandler)
glogger.Verbosity(log.LvlInfo)
log.SetDefault(log.NewLogger(glogger))
}
func ResetLogging() {
if defaultTerminalHandler != nil {
defaultTerminalHandler.ResetFieldPadding()
}
} }
// Setup initializes profiling and logging based on the CLI flags. // Setup initializes profiling and logging based on the CLI flags.

View file

@ -55,6 +55,8 @@ import (
// allowed to produce in order to speed up calculations. // allowed to produce in order to speed up calculations.
const estimateGasErrorRatio = 0.015 const estimateGasErrorRatio = 0.015
var errBlobTxNotSupported = errors.New("signing blob transactions not supported")
// EthereumAPI provides an API to access Ethereum related information. // EthereumAPI provides an API to access Ethereum related information.
type EthereumAPI struct { type EthereumAPI struct {
b Backend b Backend
@ -468,6 +470,9 @@ func (s *PersonalAccountAPI) SendTransaction(ctx context.Context, args Transacti
s.nonceLock.LockAddr(args.from()) s.nonceLock.LockAddr(args.from())
defer s.nonceLock.UnlockAddr(args.from()) defer s.nonceLock.UnlockAddr(args.from())
} }
if args.IsEIP4844() {
return common.Hash{}, errBlobTxNotSupported
}
signed, err := s.signTransaction(ctx, &args, passwd) signed, err := s.signTransaction(ctx, &args, passwd)
if err != nil { if err != nil {
log.Warn("Failed transaction send attempt", "from", args.from(), "to", args.To, "value", args.Value.ToInt(), "err", err) log.Warn("Failed transaction send attempt", "from", args.from(), "to", args.To, "value", args.Value.ToInt(), "err", err)
@ -492,6 +497,9 @@ func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args Transacti
if args.GasPrice == nil && (args.MaxFeePerGas == nil || args.MaxPriorityFeePerGas == nil) { if args.GasPrice == nil && (args.MaxFeePerGas == nil || args.MaxPriorityFeePerGas == nil) {
return nil, errors.New("missing gasPrice or maxFeePerGas/maxPriorityFeePerGas") return nil, errors.New("missing gasPrice or maxFeePerGas/maxPriorityFeePerGas")
} }
if args.IsEIP4844() {
return nil, errBlobTxNotSupported
}
if args.Nonce == nil { if args.Nonce == nil {
return nil, errors.New("nonce not specified") return nil, errors.New("nonce not specified")
} }
@ -1219,6 +1227,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
// returns error if the transaction would revert or if there are unexpected failures. The returned // returns error if the transaction would revert or if there are unexpected failures. The returned
// value is capped by both `args.Gas` (if non-nil & non-zero) and the backend's RPCGasCap // value is capped by both `args.Gas` (if non-nil & non-zero) and the backend's RPCGasCap
// configuration (if non-zero). // configuration (if non-zero).
// Note: Required blob gas is not computed in this method.
func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) { func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) {
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
if blockNrOrHash != nil { if blockNrOrHash != nil {
@ -1478,7 +1487,7 @@ type accessListResult struct {
// CreateAccessList creates an EIP-2930 type AccessList for the given transaction. // CreateAccessList creates an EIP-2930 type AccessList for the given transaction.
// Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state. // Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state.
func (s *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) { func (s *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) {
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
if blockNrOrHash != nil { if blockNrOrHash != nil {
bNrOrHash = *blockNrOrHash bNrOrHash = *blockNrOrHash
} }
@ -1809,6 +1818,9 @@ func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionAr
s.nonceLock.LockAddr(args.from()) s.nonceLock.LockAddr(args.from())
defer s.nonceLock.UnlockAddr(args.from()) defer s.nonceLock.UnlockAddr(args.from())
} }
if args.IsEIP4844() {
return common.Hash{}, errBlobTxNotSupported
}
// Set some sanity defaults and terminate on failure // Set some sanity defaults and terminate on failure
if err := args.setDefaults(ctx, s.b); err != nil { if err := args.setDefaults(ctx, s.b); err != nil {
@ -1834,6 +1846,7 @@ func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionAr
} }
// Assemble the transaction and obtain rlp // Assemble the transaction and obtain rlp
tx := args.toTransaction() tx := args.toTransaction()
// TODO(s1na): fill in blob proofs, commitments
data, err := tx.MarshalBinary() data, err := tx.MarshalBinary()
if err != nil { if err != nil {
return nil, err return nil, err
@ -1892,6 +1905,9 @@ func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionAr
if args.GasPrice == nil && (args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil) { if args.GasPrice == nil && (args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil) {
return nil, errors.New("missing gasPrice or maxFeePerGas/maxPriorityFeePerGas") return nil, errors.New("missing gasPrice or maxFeePerGas/maxPriorityFeePerGas")
} }
if args.IsEIP4844() {
return nil, errBlobTxNotSupported
}
if args.Nonce == nil { if args.Nonce == nil {
return nil, errors.New("nonce not specified") return nil, errors.New("nonce not specified")
} }

View file

@ -17,6 +17,7 @@
package ethapi package ethapi
import ( import (
"bytes"
"context" "context"
"crypto/ecdsa" "crypto/ecdsa"
"encoding/json" "encoding/json"
@ -31,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
@ -403,10 +405,30 @@ func allBlobTxs(addr common.Address, config *params.ChainConfig) []txData {
} }
} }
func newTestAccountManager(t *testing.T) (*accounts.Manager, accounts.Account) {
var (
dir = t.TempDir()
am = accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: true})
b = keystore.NewKeyStore(dir, 2, 1)
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
)
acc, err := b.ImportECDSA(testKey, "")
if err != nil {
t.Fatalf("failed to create test account: %v", err)
}
if err := b.Unlock(acc, ""); err != nil {
t.Fatalf("failed to unlock account: %v\n", err)
}
am.AddBackend(b)
return am, acc
}
type testBackend struct { type testBackend struct {
db ethdb.Database db ethdb.Database
chain *core.BlockChain chain *core.BlockChain
pending *types.Block pending *types.Block
accman *accounts.Manager
acc accounts.Account
} }
func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.Engine, generator func(i int, b *core.BlockGen)) *testBackend { func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.Engine, generator func(i int, b *core.BlockGen)) *testBackend {
@ -419,6 +441,8 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.E
TrieDirtyDisabled: true, // Archive mode TrieDirtyDisabled: true, // Archive mode
} }
) )
accman, acc := newTestAccountManager(t)
gspec.Alloc[acc.Address] = core.GenesisAccount{Balance: big.NewInt(params.Ether)}
// Generate blocks for testing // Generate blocks for testing
db, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, generator) db, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, generator)
txlookupLimit := uint64(0) txlookupLimit := uint64(0)
@ -430,7 +454,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.E
t.Fatalf("block %d: failed to insert into chain: %v", n, err) t.Fatalf("block %d: failed to insert into chain: %v", n, err)
} }
backend := &testBackend{db: db, chain: chain} backend := &testBackend{db: db, chain: chain, accman: accman, acc: acc}
return backend return backend
} }
@ -446,7 +470,7 @@ func (b testBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBloc
return nil, nil, nil, nil, nil return nil, nil, nil, nil, nil
} }
func (b testBackend) ChainDb() ethdb.Database { return b.db } func (b testBackend) ChainDb() ethdb.Database { return b.db }
func (b testBackend) AccountManager() *accounts.Manager { return nil } func (b testBackend) AccountManager() *accounts.Manager { return b.accman }
func (b testBackend) ExtRPCEnabled() bool { return false } func (b testBackend) ExtRPCEnabled() bool { return false }
func (b testBackend) RPCGasCap() uint64 { return 10000000 } func (b testBackend) RPCGasCap() uint64 { return 10000000 }
func (b testBackend) RPCEVMTimeout() time.Duration { return time.Second } func (b testBackend) RPCEVMTimeout() time.Duration { return time.Second }
@ -566,7 +590,7 @@ func (b testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*t
func (b testBackend) GetPoolTransactions() (types.Transactions, error) { panic("implement me") } func (b testBackend) GetPoolTransactions() (types.Transactions, error) { panic("implement me") }
func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("implement me") } func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("implement me") }
func (b testBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { func (b testBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
panic("implement me") return 0, nil
} }
func (b testBackend) Stats() (pending int, queued int) { panic("implement me") } func (b testBackend) Stats() (pending int, queued int) { panic("implement me") }
func (b testBackend) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) { func (b testBackend) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) {
@ -603,7 +627,7 @@ func TestEstimateGas(t *testing.T) {
var ( var (
accounts = newAccounts(2) accounts = newAccounts(2)
genesis = &core.Genesis{ genesis = &core.Genesis{
Config: params.TestChainConfig, Config: params.MergedTestChainConfig,
Alloc: core.GenesisAlloc{ Alloc: core.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)}, accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)}, accounts[1].addr: {Balance: big.NewInt(params.Ether)},
@ -613,12 +637,13 @@ func TestEstimateGas(t *testing.T) {
signer = types.HomesteadSigner{} signer = types.HomesteadSigner{}
randomAccounts = newAccounts(2) randomAccounts = newAccounts(2)
) )
api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, ethash.NewFaker(), func(i int, b *core.BlockGen) { api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
// Transfer from account[0] to account[1] // Transfer from account[0] to account[1]
// value: 1000 wei // value: 1000 wei
// fee: 0 wei // fee: 0 wei
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key) tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key)
b.AddTx(tx) b.AddTx(tx)
b.SetPoS()
})) }))
var testSuite = []struct { var testSuite = []struct {
blockNumber rpc.BlockNumber blockNumber rpc.BlockNumber
@ -718,6 +743,18 @@ func TestEstimateGas(t *testing.T) {
expectErr: nil, expectErr: nil,
want: 67595, want: 67595,
}, },
// Blobs should have no effect on gas estimate
{
blockNumber: rpc.LatestBlockNumber,
call: TransactionArgs{
From: &accounts[0].addr,
To: &accounts[1].addr,
Value: (*hexutil.Big)(big.NewInt(1)),
BlobHashes: []common.Hash{common.Hash{0x01, 0x22}},
BlobFeeCap: (*hexutil.Big)(big.NewInt(1)),
},
want: 21000,
},
} }
for i, tc := range testSuite { for i, tc := range testSuite {
result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides) result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides)
@ -747,7 +784,7 @@ func TestCall(t *testing.T) {
var ( var (
accounts = newAccounts(3) accounts = newAccounts(3)
genesis = &core.Genesis{ genesis = &core.Genesis{
Config: params.TestChainConfig, Config: params.MergedTestChainConfig,
Alloc: core.GenesisAlloc{ Alloc: core.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)}, accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)}, accounts[1].addr: {Balance: big.NewInt(params.Ether)},
@ -757,12 +794,13 @@ func TestCall(t *testing.T) {
genBlocks = 10 genBlocks = 10
signer = types.HomesteadSigner{} signer = types.HomesteadSigner{}
) )
api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, ethash.NewFaker(), func(i int, b *core.BlockGen) { api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
// Transfer from account[0] to account[1] // Transfer from account[0] to account[1]
// value: 1000 wei // value: 1000 wei
// fee: 0 wei // fee: 0 wei
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key) tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key)
b.AddTx(tx) b.AddTx(tx)
b.SetPoS()
})) }))
randomAccounts := newAccounts(3) randomAccounts := newAccounts(3)
var testSuite = []struct { var testSuite = []struct {
@ -884,6 +922,32 @@ func TestCall(t *testing.T) {
blockOverrides: BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))}, blockOverrides: BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))},
want: "0x000000000000000000000000000000000000000000000000000000000000000b", want: "0x000000000000000000000000000000000000000000000000000000000000000b",
}, },
// Invalid blob tx
{
blockNumber: rpc.LatestBlockNumber,
call: TransactionArgs{
From: &accounts[1].addr,
Input: &hexutil.Bytes{0x00},
BlobHashes: []common.Hash{},
},
expectErr: core.ErrBlobTxCreate,
},
// BLOBHASH opcode
{
blockNumber: rpc.LatestBlockNumber,
call: TransactionArgs{
From: &accounts[1].addr,
To: &randomAccounts[2].addr,
BlobHashes: []common.Hash{common.Hash{0x01, 0x22}},
BlobFeeCap: (*hexutil.Big)(big.NewInt(1)),
},
overrides: StateOverride{
randomAccounts[2].addr: {
Code: hex2Bytes("60004960005260206000f3"),
},
},
want: "0x0122000000000000000000000000000000000000000000000000000000000000",
},
} }
for i, tc := range testSuite { for i, tc := range testSuite {
result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)
@ -910,6 +974,134 @@ func TestCall(t *testing.T) {
} }
} }
func TestSignTransaction(t *testing.T) {
t.Parallel()
// Initialize test accounts
var (
key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
to = crypto.PubkeyToAddress(key.PublicKey)
genesis = &core.Genesis{
Config: params.MergedTestChainConfig,
Alloc: core.GenesisAlloc{},
}
)
b := newTestBackend(t, 1, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
b.SetPoS()
})
api := NewTransactionAPI(b, nil)
res, err := api.FillTransaction(context.Background(), TransactionArgs{
From: &b.acc.Address,
To: &to,
Value: (*hexutil.Big)(big.NewInt(1)),
})
if err != nil {
t.Fatalf("failed to fill tx defaults: %v\n", err)
}
res, err = api.SignTransaction(context.Background(), argsFromTransaction(res.Tx, b.acc.Address))
if err != nil {
t.Fatalf("failed to sign tx: %v\n", err)
}
tx, err := json.Marshal(res.Tx)
if err != nil {
t.Fatal(err)
}
expect := `{"type":"0x2","chainId":"0x1","nonce":"0x0","to":"0x703c4b2bd70c169f5717101caee543299fc946c7","gas":"0x5208","gasPrice":null,"maxPriorityFeePerGas":"0x0","maxFeePerGas":"0x684ee180","value":"0x1","input":"0x","accessList":[],"v":"0x0","r":"0x8fabeb142d585dd9247f459f7e6fe77e2520c88d50ba5d220da1533cea8b34e1","s":"0x582dd68b21aef36ba23f34e49607329c20d981d30404daf749077f5606785ce7","yParity":"0x0","hash":"0x93927839207cfbec395da84b8a2bc38b7b65d2cb2819e9fef1f091f5b1d4cc8f"}`
if !bytes.Equal(tx, []byte(expect)) {
t.Errorf("result mismatch. Have:\n%s\nWant:\n%s\n", tx, expect)
}
}
func TestSignBlobTransaction(t *testing.T) {
t.Parallel()
// Initialize test accounts
var (
key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
to = crypto.PubkeyToAddress(key.PublicKey)
genesis = &core.Genesis{
Config: params.MergedTestChainConfig,
Alloc: core.GenesisAlloc{},
}
)
b := newTestBackend(t, 1, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
b.SetPoS()
})
api := NewTransactionAPI(b, nil)
res, err := api.FillTransaction(context.Background(), TransactionArgs{
From: &b.acc.Address,
To: &to,
Value: (*hexutil.Big)(big.NewInt(1)),
BlobHashes: []common.Hash{{0x01, 0x22}},
})
if err != nil {
t.Fatalf("failed to fill tx defaults: %v\n", err)
}
_, err = api.SignTransaction(context.Background(), argsFromTransaction(res.Tx, b.acc.Address))
if err == nil {
t.Fatalf("should fail on blob transaction")
}
if !errors.Is(err, errBlobTxNotSupported) {
t.Errorf("error mismatch. Have: %v, want: %v", err, errBlobTxNotSupported)
}
}
func TestSendBlobTransaction(t *testing.T) {
t.Parallel()
// Initialize test accounts
var (
key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
to = crypto.PubkeyToAddress(key.PublicKey)
genesis = &core.Genesis{
Config: params.MergedTestChainConfig,
Alloc: core.GenesisAlloc{},
}
)
b := newTestBackend(t, 1, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
b.SetPoS()
})
api := NewTransactionAPI(b, nil)
res, err := api.FillTransaction(context.Background(), TransactionArgs{
From: &b.acc.Address,
To: &to,
Value: (*hexutil.Big)(big.NewInt(1)),
BlobHashes: []common.Hash{common.Hash{0x01, 0x22}},
})
if err != nil {
t.Fatalf("failed to fill tx defaults: %v\n", err)
}
_, err = api.SendTransaction(context.Background(), argsFromTransaction(res.Tx, b.acc.Address))
if err == nil {
t.Errorf("sending tx should have failed")
} else if !errors.Is(err, errBlobTxNotSupported) {
t.Errorf("unexpected error. Have %v, want %v\n", err, errBlobTxNotSupported)
}
}
func argsFromTransaction(tx *types.Transaction, from common.Address) TransactionArgs {
var (
gas = tx.Gas()
nonce = tx.Nonce()
input = tx.Data()
)
return TransactionArgs{
From: &from,
To: tx.To(),
Gas: (*hexutil.Uint64)(&gas),
MaxFeePerGas: (*hexutil.Big)(tx.GasFeeCap()),
MaxPriorityFeePerGas: (*hexutil.Big)(tx.GasTipCap()),
Value: (*hexutil.Big)(tx.Value()),
Nonce: (*hexutil.Uint64)(&nonce),
Input: (*hexutil.Bytes)(&input),
ChainID: (*hexutil.Big)(tx.ChainId()),
// TODO: impl accessList conversion
//AccessList: tx.AccessList(),
BlobFeeCap: (*hexutil.Big)(tx.BlobGasFeeCap()),
BlobHashes: tx.BlobHashes(),
}
}
type account struct { type account struct {
key *ecdsa.PrivateKey key *ecdsa.PrivateKey
addr common.Address addr common.Address
@ -1399,9 +1591,7 @@ func TestRPCGetBlockOrHeader(t *testing.T) {
} }
func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Hash) { func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Hash) {
config := *params.TestChainConfig config := *params.MergedTestChainConfig
config.ShanghaiTime = new(uint64)
config.CancunTime = new(uint64)
var ( var (
acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
@ -1432,9 +1622,6 @@ func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Ha
txHashes = make([]common.Hash, genBlocks) txHashes = make([]common.Hash, genBlocks)
) )
// Set the terminal total difficulty in the config
genesis.Config.TerminalTotalDifficulty = big.NewInt(0)
genesis.Config.TerminalTotalDifficultyPassed = true
backend := newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) { backend := newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
var ( var (
tx *types.Transaction tx *types.Transaction

View file

@ -4,17 +4,17 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x0da274b315de8e4d5bf8717218ec43540464ef36378cb896469bb731e1d3f3cb", "hash": "0xeeb5c1852740ca4bbe65b0f57baf80634ed12a2b44affe30eec3fb54437c3926",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x1", "number": "0x1",
"parentHash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "parentHash": "0x98e056de84de969782b238b4509b32814627ba443ea622054a79c2bc7e4d92c7",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x26a", "size": "0x26a",
"stateRoot": "0x92c5c55a698963f5b06e3aee415630f5c48b0760e537af94917ce9c4f42a2e22", "stateRoot": "0x4acfcd1a6ab9f5e62411021ecd8a749976ae50b0590e967471264b372d7ac55b",
"timestamp": "0xa", "timestamp": "0xa",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [ "transactions": [

View file

@ -4,7 +4,7 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x0", "gasUsed": "0x0",
"hash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "hash": "0x98e056de84de969782b238b4509b32814627ba443ea622054a79c2bc7e4d92c7",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
@ -14,7 +14,7 @@
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x200", "size": "0x200",
"stateRoot": "0xfe168c5e9584a85927212e5bea5304bb7d0d8a893453b4b2c52176a72f585ae2", "stateRoot": "0xd883f48b83cc9c1e8389453beb4ad4e572462eec049ca4fffbe16ecefb3fe937",
"timestamp": "0x0", "timestamp": "0x0",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [], "transactions": [],

View file

@ -4,22 +4,22 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "hash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x9", "number": "0x9",
"parentHash": "0x5abd19c39d9f1c6e52998e135ea14e1fbc5db3fa2a108f4538e238ca5c2e68d7", "parentHash": "0xcd7d78eaa8b0ddbd2956fc37e1883c30df27b43e8cc9a982020310656736637c",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x26a", "size": "0x26a",
"stateRoot": "0xbd4aa2c2873df709151075250a8c01c9a14d2b0e2f715dbdd16e0ef8030c2cf0", "stateRoot": "0x78b2b19ef1a0276dbbc23a875dbf60ae5d10dafa0017098473c4871abd3e7b5c",
"timestamp": "0x5a", "timestamp": "0x5a",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [ "transactions": [
{ {
"blockHash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "blockHash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5",
"blockNumber": "0x9", "blockNumber": "0x9",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gas": "0x5208", "gas": "0x5208",

View file

@ -4,17 +4,17 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x97f540a3577c0f645c5dada5da86f38350e8f847e71f21124f917835003e2607", "hash": "0xa063415a5020f1569fae73ecb0d37bc5649ebe86d59e764a389eb37814bd42cb",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0xa", "number": "0xa",
"parentHash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "parentHash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x26a", "size": "0x26a",
"stateRoot": "0xbb62872e4023fa8a8b17b9cc37031f4817d9595779748d01cba408b495707a91", "stateRoot": "0x118f1433ae23c4d1c12f5bd652baddb72611c55ac1cd6af6620d209db222f9e6",
"timestamp": "0x64", "timestamp": "0x64",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [ "transactions": [

View file

@ -4,7 +4,7 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x0", "gasUsed": "0x0",
"hash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "hash": "0x98e056de84de969782b238b4509b32814627ba443ea622054a79c2bc7e4d92c7",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
@ -14,7 +14,7 @@
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x200", "size": "0x200",
"stateRoot": "0xfe168c5e9584a85927212e5bea5304bb7d0d8a893453b4b2c52176a72f585ae2", "stateRoot": "0xd883f48b83cc9c1e8389453beb4ad4e572462eec049ca4fffbe16ecefb3fe937",
"timestamp": "0x0", "timestamp": "0x0",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [], "transactions": [],

View file

@ -4,17 +4,17 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x0da274b315de8e4d5bf8717218ec43540464ef36378cb896469bb731e1d3f3cb", "hash": "0xeeb5c1852740ca4bbe65b0f57baf80634ed12a2b44affe30eec3fb54437c3926",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x1", "number": "0x1",
"parentHash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "parentHash": "0x98e056de84de969782b238b4509b32814627ba443ea622054a79c2bc7e4d92c7",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x26a", "size": "0x26a",
"stateRoot": "0x92c5c55a698963f5b06e3aee415630f5c48b0760e537af94917ce9c4f42a2e22", "stateRoot": "0x4acfcd1a6ab9f5e62411021ecd8a749976ae50b0590e967471264b372d7ac55b",
"timestamp": "0xa", "timestamp": "0xa",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [ "transactions": [

View file

@ -4,22 +4,22 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "hash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x9", "number": "0x9",
"parentHash": "0x5abd19c39d9f1c6e52998e135ea14e1fbc5db3fa2a108f4538e238ca5c2e68d7", "parentHash": "0xcd7d78eaa8b0ddbd2956fc37e1883c30df27b43e8cc9a982020310656736637c",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x26a", "size": "0x26a",
"stateRoot": "0xbd4aa2c2873df709151075250a8c01c9a14d2b0e2f715dbdd16e0ef8030c2cf0", "stateRoot": "0x78b2b19ef1a0276dbbc23a875dbf60ae5d10dafa0017098473c4871abd3e7b5c",
"timestamp": "0x5a", "timestamp": "0x5a",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [ "transactions": [
{ {
"blockHash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "blockHash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5",
"blockNumber": "0x9", "blockNumber": "0x9",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gas": "0x5208", "gas": "0x5208",

View file

@ -4,17 +4,17 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x97f540a3577c0f645c5dada5da86f38350e8f847e71f21124f917835003e2607", "hash": "0xa063415a5020f1569fae73ecb0d37bc5649ebe86d59e764a389eb37814bd42cb",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0xa", "number": "0xa",
"parentHash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "parentHash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x26a", "size": "0x26a",
"stateRoot": "0xbb62872e4023fa8a8b17b9cc37031f4817d9595779748d01cba408b495707a91", "stateRoot": "0x118f1433ae23c4d1c12f5bd652baddb72611c55ac1cd6af6620d209db222f9e6",
"timestamp": "0x64", "timestamp": "0x64",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [ "transactions": [

View file

@ -2,7 +2,7 @@
{ {
"blobGasPrice": "0x1", "blobGasPrice": "0x1",
"blobGasUsed": "0x20000", "blobGasUsed": "0x20000",
"blockHash": "0xe724dfd4349861f4dceef2bc4df086d0a3d88858214f6bee9fcf1bebd1edc2a6", "blockHash": "0xd1392771155ce83f6403c6af275efd22bed567030c21168fcc9dbad5004eb245",
"blockNumber": "0x6", "blockNumber": "0x6",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5208", "cumulativeGasUsed": "0x5208",

View file

@ -1,6 +1,6 @@
[ [
{ {
"blockHash": "0x1e7dcf3abe8bf05d32367a5dc387caa32578b15871bf8b3cbeedf2d8d530f844", "blockHash": "0x56ea26cf955d7f2e08e194ad212ca4d5f99ee8e0b19dec3c71d8faafa33b1d22",
"blockNumber": "0x2", "blockNumber": "0x2",
"contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592", "contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592",
"cumulativeGasUsed": "0xcf50", "cumulativeGasUsed": "0xcf50",

View file

@ -1,6 +1,6 @@
[ [
{ {
"blockHash": "0xffa737e6ce9a9162ffd411dd06169114b3ed5ee9fc1474a2625c92548e4455e0", "blockHash": "0xf41e7a7a716382f20464cf76c6ae1fa701e9d32f5cc550ebfd2391b9642ae6bc",
"blockNumber": "0x4", "blockNumber": "0x4",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x538d", "cumulativeGasUsed": "0x538d",

View file

@ -1,6 +1,6 @@
[ [
{ {
"blockHash": "0x173dcd9d22ce71929cd17e84ea88702a0f84d6244c6898d2a4f48722e494fe9c", "blockHash": "0xa1410af902e98b32e0bbe464f8637ff464f1d4344b585127d2ce71f9cb39cb8a",
"blockNumber": "0x3", "blockNumber": "0x3",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5e28", "cumulativeGasUsed": "0x5e28",
@ -19,7 +19,7 @@
"blockNumber": "0x3", "blockNumber": "0x3",
"transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287", "transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287",
"transactionIndex": "0x0", "transactionIndex": "0x0",
"blockHash": "0x173dcd9d22ce71929cd17e84ea88702a0f84d6244c6898d2a4f48722e494fe9c", "blockHash": "0xa1410af902e98b32e0bbe464f8637ff464f1d4344b585127d2ce71f9cb39cb8a",
"logIndex": "0x0", "logIndex": "0x0",
"removed": false "removed": false
} }

View file

@ -1,6 +1,6 @@
[ [
{ {
"blockHash": "0xa8a067b3cb3b9ddc6cfb8317bfd08b266fcf9994fc870c1f7ed394acecfadf39", "blockHash": "0x797d0c5603eccb33cc8ebd1300e977746512ec49e6b89087c7aad28ff760a26f",
"blockNumber": "0x1", "blockNumber": "0x1",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5208", "cumulativeGasUsed": "0x5208",

View file

@ -2,7 +2,7 @@
{ {
"blobGasPrice": "0x1", "blobGasPrice": "0x1",
"blobGasUsed": "0x20000", "blobGasUsed": "0x20000",
"blockHash": "0xe724dfd4349861f4dceef2bc4df086d0a3d88858214f6bee9fcf1bebd1edc2a6", "blockHash": "0xd1392771155ce83f6403c6af275efd22bed567030c21168fcc9dbad5004eb245",
"blockNumber": "0x6", "blockNumber": "0x6",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5208", "cumulativeGasUsed": "0x5208",

View file

@ -4,7 +4,7 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x0", "gasUsed": "0x0",
"hash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "hash": "0x98e056de84de969782b238b4509b32814627ba443ea622054a79c2bc7e4d92c7",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
@ -13,7 +13,7 @@
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0xfe168c5e9584a85927212e5bea5304bb7d0d8a893453b4b2c52176a72f585ae2", "stateRoot": "0xd883f48b83cc9c1e8389453beb4ad4e572462eec049ca4fffbe16ecefb3fe937",
"timestamp": "0x0", "timestamp": "0x0",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"

View file

@ -4,16 +4,16 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x0da274b315de8e4d5bf8717218ec43540464ef36378cb896469bb731e1d3f3cb", "hash": "0xeeb5c1852740ca4bbe65b0f57baf80634ed12a2b44affe30eec3fb54437c3926",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x1", "number": "0x1",
"parentHash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "parentHash": "0x98e056de84de969782b238b4509b32814627ba443ea622054a79c2bc7e4d92c7",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0x92c5c55a698963f5b06e3aee415630f5c48b0760e537af94917ce9c4f42a2e22", "stateRoot": "0x4acfcd1a6ab9f5e62411021ecd8a749976ae50b0590e967471264b372d7ac55b",
"timestamp": "0xa", "timestamp": "0xa",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0xca0ebcce920d2cdfbf9e1dbe90ed3441a1a576f344bd80e60508da814916f4e7" "transactionsRoot": "0xca0ebcce920d2cdfbf9e1dbe90ed3441a1a576f344bd80e60508da814916f4e7"

View file

@ -4,16 +4,16 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "hash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x9", "number": "0x9",
"parentHash": "0x5abd19c39d9f1c6e52998e135ea14e1fbc5db3fa2a108f4538e238ca5c2e68d7", "parentHash": "0xcd7d78eaa8b0ddbd2956fc37e1883c30df27b43e8cc9a982020310656736637c",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0xbd4aa2c2873df709151075250a8c01c9a14d2b0e2f715dbdd16e0ef8030c2cf0", "stateRoot": "0x78b2b19ef1a0276dbbc23a875dbf60ae5d10dafa0017098473c4871abd3e7b5c",
"timestamp": "0x5a", "timestamp": "0x5a",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5" "transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5"

View file

@ -4,16 +4,16 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x97f540a3577c0f645c5dada5da86f38350e8f847e71f21124f917835003e2607", "hash": "0xa063415a5020f1569fae73ecb0d37bc5649ebe86d59e764a389eb37814bd42cb",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0xa", "number": "0xa",
"parentHash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "parentHash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0xbb62872e4023fa8a8b17b9cc37031f4817d9595779748d01cba408b495707a91", "stateRoot": "0x118f1433ae23c4d1c12f5bd652baddb72611c55ac1cd6af6620d209db222f9e6",
"timestamp": "0x64", "timestamp": "0x64",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0xb0893d21a4a44dc26a962a6e91abae66df87fb61ac9c60e936aee89c76331445" "transactionsRoot": "0xb0893d21a4a44dc26a962a6e91abae66df87fb61ac9c60e936aee89c76331445"

View file

@ -4,7 +4,7 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x0", "gasUsed": "0x0",
"hash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "hash": "0x98e056de84de969782b238b4509b32814627ba443ea622054a79c2bc7e4d92c7",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
@ -13,7 +13,7 @@
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0xfe168c5e9584a85927212e5bea5304bb7d0d8a893453b4b2c52176a72f585ae2", "stateRoot": "0xd883f48b83cc9c1e8389453beb4ad4e572462eec049ca4fffbe16ecefb3fe937",
"timestamp": "0x0", "timestamp": "0x0",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"

View file

@ -4,16 +4,16 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x0da274b315de8e4d5bf8717218ec43540464ef36378cb896469bb731e1d3f3cb", "hash": "0xeeb5c1852740ca4bbe65b0f57baf80634ed12a2b44affe30eec3fb54437c3926",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x1", "number": "0x1",
"parentHash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "parentHash": "0x98e056de84de969782b238b4509b32814627ba443ea622054a79c2bc7e4d92c7",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0x92c5c55a698963f5b06e3aee415630f5c48b0760e537af94917ce9c4f42a2e22", "stateRoot": "0x4acfcd1a6ab9f5e62411021ecd8a749976ae50b0590e967471264b372d7ac55b",
"timestamp": "0xa", "timestamp": "0xa",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0xca0ebcce920d2cdfbf9e1dbe90ed3441a1a576f344bd80e60508da814916f4e7" "transactionsRoot": "0xca0ebcce920d2cdfbf9e1dbe90ed3441a1a576f344bd80e60508da814916f4e7"

View file

@ -4,16 +4,16 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "hash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x9", "number": "0x9",
"parentHash": "0x5abd19c39d9f1c6e52998e135ea14e1fbc5db3fa2a108f4538e238ca5c2e68d7", "parentHash": "0xcd7d78eaa8b0ddbd2956fc37e1883c30df27b43e8cc9a982020310656736637c",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0xbd4aa2c2873df709151075250a8c01c9a14d2b0e2f715dbdd16e0ef8030c2cf0", "stateRoot": "0x78b2b19ef1a0276dbbc23a875dbf60ae5d10dafa0017098473c4871abd3e7b5c",
"timestamp": "0x5a", "timestamp": "0x5a",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5" "transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5"

View file

@ -4,16 +4,16 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x97f540a3577c0f645c5dada5da86f38350e8f847e71f21124f917835003e2607", "hash": "0xa063415a5020f1569fae73ecb0d37bc5649ebe86d59e764a389eb37814bd42cb",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0xa", "number": "0xa",
"parentHash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "parentHash": "0xedb9ccf3a85f67c095ad48abfb0fa09d47179bb0f902078d289042d12428aca5",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0xbb62872e4023fa8a8b17b9cc37031f4817d9595779748d01cba408b495707a91", "stateRoot": "0x118f1433ae23c4d1c12f5bd652baddb72611c55ac1cd6af6620d209db222f9e6",
"timestamp": "0x64", "timestamp": "0x64",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0xb0893d21a4a44dc26a962a6e91abae66df87fb61ac9c60e936aee89c76331445" "transactionsRoot": "0xb0893d21a4a44dc26a962a6e91abae66df87fb61ac9c60e936aee89c76331445"

View file

@ -1,7 +1,7 @@
{ {
"blobGasPrice": "0x1", "blobGasPrice": "0x1",
"blobGasUsed": "0x20000", "blobGasUsed": "0x20000",
"blockHash": "0xe724dfd4349861f4dceef2bc4df086d0a3d88858214f6bee9fcf1bebd1edc2a6", "blockHash": "0xd1392771155ce83f6403c6af275efd22bed567030c21168fcc9dbad5004eb245",
"blockNumber": "0x6", "blockNumber": "0x6",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5208", "cumulativeGasUsed": "0x5208",

View file

@ -1,5 +1,5 @@
{ {
"blockHash": "0x1e7dcf3abe8bf05d32367a5dc387caa32578b15871bf8b3cbeedf2d8d530f844", "blockHash": "0x56ea26cf955d7f2e08e194ad212ca4d5f99ee8e0b19dec3c71d8faafa33b1d22",
"blockNumber": "0x2", "blockNumber": "0x2",
"contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592", "contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592",
"cumulativeGasUsed": "0xcf50", "cumulativeGasUsed": "0xcf50",

View file

@ -1,5 +1,5 @@
{ {
"blockHash": "0x3fadc5bc916018a326732be829a2565b3acb960a8406f0f151a5e1fa971ea7dd", "blockHash": "0x69bf6ba924d95b6c50b0357768e5c892bd1b00cdf2f97e2e81fc06a76dfa57e3",
"blockNumber": "0x5", "blockNumber": "0x5",
"contractAddress": "0xfdaa97661a584d977b4d3abb5370766ff5b86a18", "contractAddress": "0xfdaa97661a584d977b4d3abb5370766ff5b86a18",
"cumulativeGasUsed": "0xe01c", "cumulativeGasUsed": "0xe01c",

View file

@ -1,5 +1,5 @@
{ {
"blockHash": "0xffa737e6ce9a9162ffd411dd06169114b3ed5ee9fc1474a2625c92548e4455e0", "blockHash": "0xf41e7a7a716382f20464cf76c6ae1fa701e9d32f5cc550ebfd2391b9642ae6bc",
"blockNumber": "0x4", "blockNumber": "0x4",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x538d", "cumulativeGasUsed": "0x538d",

View file

@ -1,5 +1,5 @@
{ {
"blockHash": "0xa8a067b3cb3b9ddc6cfb8317bfd08b266fcf9994fc870c1f7ed394acecfadf39", "blockHash": "0x797d0c5603eccb33cc8ebd1300e977746512ec49e6b89087c7aad28ff760a26f",
"blockNumber": "0x1", "blockNumber": "0x1",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5208", "cumulativeGasUsed": "0x5208",

View file

@ -1,5 +1,5 @@
{ {
"blockHash": "0x173dcd9d22ce71929cd17e84ea88702a0f84d6244c6898d2a4f48722e494fe9c", "blockHash": "0xa1410af902e98b32e0bbe464f8637ff464f1d4344b585127d2ce71f9cb39cb8a",
"blockNumber": "0x3", "blockNumber": "0x3",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5e28", "cumulativeGasUsed": "0x5e28",
@ -18,7 +18,7 @@
"blockNumber": "0x3", "blockNumber": "0x3",
"transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287", "transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287",
"transactionIndex": "0x0", "transactionIndex": "0x0",
"blockHash": "0x173dcd9d22ce71929cd17e84ea88702a0f84d6244c6898d2a4f48722e494fe9c", "blockHash": "0xa1410af902e98b32e0bbe464f8637ff464f1d4344b585127d2ce71f9cb39cb8a",
"logIndex": "0x0", "logIndex": "0x0",
"removed": false "removed": false
} }

View file

@ -26,10 +26,12 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/holiman/uint256"
) )
// TransactionArgs represents the arguments to construct a new transaction // TransactionArgs represents the arguments to construct a new transaction
@ -53,6 +55,10 @@ type TransactionArgs struct {
// Introduced by AccessListTxType transaction. // Introduced by AccessListTxType transaction.
AccessList *types.AccessList `json:"accessList,omitempty"` AccessList *types.AccessList `json:"accessList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"` ChainID *hexutil.Big `json:"chainId,omitempty"`
// Introduced by EIP-4844.
BlobFeeCap *hexutil.Big `json:"maxFeePerBlobGas"`
BlobHashes []common.Hash `json:"blobVersionedHashes,omitempty"`
} }
// from retrieves the transaction sender address. // from retrieves the transaction sender address.
@ -92,6 +98,12 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`) return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`)
} }
if args.BlobHashes != nil && args.To == nil {
return errors.New(`blob transactions cannot have the form of a create transaction`)
}
if args.BlobHashes != nil && len(args.BlobHashes) == 0 {
return errors.New(`need at least 1 blob for a blob transaction`)
}
if args.To == nil && len(args.data()) == 0 { if args.To == nil && len(args.data()) == 0 {
return errors.New(`contract creation without any data provided`) return errors.New(`contract creation without any data provided`)
} }
@ -110,8 +122,8 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
Data: (*hexutil.Bytes)(&data), Data: (*hexutil.Bytes)(&data),
AccessList: args.AccessList, AccessList: args.AccessList,
} }
pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, nil, b.RPCGasCap()) estimated, err := DoEstimateGas(ctx, b, callArgs, latestBlockNr, nil, b.RPCGasCap())
if err != nil { if err != nil {
return err return err
} }
@ -153,6 +165,10 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) erro
} }
return nil // No need to set anything, user already set MaxFeePerGas and MaxPriorityFeePerGas return nil // No need to set anything, user already set MaxFeePerGas and MaxPriorityFeePerGas
} }
// Sanity check the EIP-4844 fee parameters.
if args.BlobFeeCap != nil && args.BlobFeeCap.ToInt().Sign() == 0 {
return errors.New("maxFeePerBlobGas must be non-zero")
}
// Sanity check the non-EIP-1559 fee parameters. // Sanity check the non-EIP-1559 fee parameters.
head := b.CurrentHeader() head := b.CurrentHeader()
isLondon := b.ChainConfig().IsLondon(head.Number) isLondon := b.ChainConfig().IsLondon(head.Number)
@ -165,14 +181,21 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) erro
} }
// Now attempt to fill in default value depending on whether London is active or not. // Now attempt to fill in default value depending on whether London is active or not.
if isLondon { if b.ChainConfig().IsCancun(head.Number, head.Time) {
if err := args.setCancunFeeDefaults(ctx, head, b); err != nil {
return err
}
} else if isLondon {
if args.BlobFeeCap != nil {
return errors.New("maxFeePerBlobGas is not valid before Cancun is active")
}
// London is active, set maxPriorityFeePerGas and maxFeePerGas. // London is active, set maxPriorityFeePerGas and maxFeePerGas.
if err := args.setLondonFeeDefaults(ctx, head, b); err != nil { if err := args.setLondonFeeDefaults(ctx, head, b); err != nil {
return err return err
} }
} else { } else {
if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil { if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil || args.BlobFeeCap != nil {
return errors.New("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active") return errors.New("maxFeePerGas and maxPriorityFeePerGas and maxFeePerBlobGas are not valid before London is active")
} }
// London not active, set gas price. // London not active, set gas price.
price, err := b.SuggestGasTipCap(ctx) price, err := b.SuggestGasTipCap(ctx)
@ -184,6 +207,21 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) erro
return nil return nil
} }
// setCancunFeeDefaults fills in reasonable default fee values for unspecified fields.
func (args *TransactionArgs) setCancunFeeDefaults(ctx context.Context, head *types.Header, b Backend) error {
// Set maxFeePerBlobGas if it is missing.
if args.BlobHashes != nil && args.BlobFeeCap == nil {
// ExcessBlobGas must be set for a Cancun block.
blobBaseFee := eip4844.CalcBlobFee(*head.ExcessBlobGas)
// Set the max fee to be 2 times larger than the previous block's blob base fee.
// The additional slack allows the tx to not become invalidated if the base
// fee is rising.
val := new(big.Int).Mul(blobBaseFee, big.NewInt(2))
args.BlobFeeCap = (*hexutil.Big)(val)
}
return args.setLondonFeeDefaults(ctx, head, b)
}
// setLondonFeeDefaults fills in reasonable default fee values for unspecified fields. // setLondonFeeDefaults fills in reasonable default fee values for unspecified fields.
func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *types.Header, b Backend) error { func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *types.Header, b Backend) error {
// Set maxPriorityFeePerGas if it is missing. // Set maxPriorityFeePerGas if it is missing.
@ -236,9 +274,10 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*
gas = globalGasCap gas = globalGasCap
} }
var ( var (
gasPrice *big.Int gasPrice *big.Int
gasFeeCap *big.Int gasFeeCap *big.Int
gasTipCap *big.Int gasTipCap *big.Int
blobFeeCap *big.Int
) )
if baseFee == nil { if baseFee == nil {
// If there's no basefee, then it must be a non-1559 execution // If there's no basefee, then it must be a non-1559 execution
@ -270,6 +309,11 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*
} }
} }
} }
if args.BlobFeeCap != nil {
blobFeeCap = args.BlobFeeCap.ToInt()
} else if args.BlobHashes != nil {
blobFeeCap = new(big.Int)
}
value := new(big.Int) value := new(big.Int)
if args.Value != nil { if args.Value != nil {
value = args.Value.ToInt() value = args.Value.ToInt()
@ -289,6 +333,8 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*
GasTipCap: gasTipCap, GasTipCap: gasTipCap,
Data: data, Data: data,
AccessList: accessList, AccessList: accessList,
BlobGasFeeCap: blobFeeCap,
BlobHashes: args.BlobHashes,
SkipAccountChecks: true, SkipAccountChecks: true,
} }
return msg, nil return msg, nil
@ -299,6 +345,24 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*
func (args *TransactionArgs) toTransaction() *types.Transaction { func (args *TransactionArgs) toTransaction() *types.Transaction {
var data types.TxData var data types.TxData
switch { switch {
case args.BlobHashes != nil:
al := types.AccessList{}
if args.AccessList != nil {
al = *args.AccessList
}
data = &types.BlobTx{
To: *args.To,
ChainID: uint256.MustFromBig((*big.Int)(args.ChainID)),
Nonce: uint64(*args.Nonce),
Gas: uint64(*args.Gas),
GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)),
GasTipCap: uint256.MustFromBig((*big.Int)(args.MaxPriorityFeePerGas)),
Value: uint256.MustFromBig((*big.Int)(args.Value)),
Data: args.data(),
AccessList: al,
BlobHashes: args.BlobHashes,
BlobFeeCap: uint256.MustFromBig((*big.Int)(args.BlobFeeCap)),
}
case args.MaxFeePerGas != nil: case args.MaxFeePerGas != nil:
al := types.AccessList{} al := types.AccessList{}
if args.AccessList != nil { if args.AccessList != nil {
@ -344,3 +408,8 @@ func (args *TransactionArgs) toTransaction() *types.Transaction {
func (args *TransactionArgs) ToTransaction() *types.Transaction { func (args *TransactionArgs) ToTransaction() *types.Transaction {
return args.toTransaction() return args.toTransaction()
} }
// IsEIP4844 returns an indicator if the args contains EIP4844 fields.
func (args *TransactionArgs) IsEIP4844() bool {
return args.BlobHashes != nil || args.BlobFeeCap != nil
}

View file

@ -43,11 +43,11 @@ import (
// TestSetFeeDefaults tests the logic for filling in default fee values works as expected. // TestSetFeeDefaults tests the logic for filling in default fee values works as expected.
func TestSetFeeDefaults(t *testing.T) { func TestSetFeeDefaults(t *testing.T) {
type test struct { type test struct {
name string name string
isLondon bool fork string // options: legacy, london, cancun
in *TransactionArgs in *TransactionArgs
want *TransactionArgs want *TransactionArgs
err error err error
} }
var ( var (
@ -62,28 +62,28 @@ func TestSetFeeDefaults(t *testing.T) {
// Legacy txs // Legacy txs
{ {
"legacy tx pre-London", "legacy tx pre-London",
false, "legacy",
&TransactionArgs{}, &TransactionArgs{},
&TransactionArgs{GasPrice: fortytwo}, &TransactionArgs{GasPrice: fortytwo},
nil, nil,
}, },
{ {
"legacy tx pre-London with zero price", "legacy tx pre-London with zero price",
false, "legacy",
&TransactionArgs{GasPrice: zero}, &TransactionArgs{GasPrice: zero},
&TransactionArgs{GasPrice: zero}, &TransactionArgs{GasPrice: zero},
nil, nil,
}, },
{ {
"legacy tx post-London, explicit gas price", "legacy tx post-London, explicit gas price",
true, "london",
&TransactionArgs{GasPrice: fortytwo}, &TransactionArgs{GasPrice: fortytwo},
&TransactionArgs{GasPrice: fortytwo}, &TransactionArgs{GasPrice: fortytwo},
nil, nil,
}, },
{ {
"legacy tx post-London with zero price", "legacy tx post-London with zero price",
true, "london",
&TransactionArgs{GasPrice: zero}, &TransactionArgs{GasPrice: zero},
nil, nil,
errors.New("gasPrice must be non-zero after london fork"), errors.New("gasPrice must be non-zero after london fork"),
@ -92,35 +92,35 @@ func TestSetFeeDefaults(t *testing.T) {
// Access list txs // Access list txs
{ {
"access list tx pre-London", "access list tx pre-London",
false, "legacy",
&TransactionArgs{AccessList: al}, &TransactionArgs{AccessList: al},
&TransactionArgs{AccessList: al, GasPrice: fortytwo}, &TransactionArgs{AccessList: al, GasPrice: fortytwo},
nil, nil,
}, },
{ {
"access list tx post-London, explicit gas price", "access list tx post-London, explicit gas price",
false, "legacy",
&TransactionArgs{AccessList: al, GasPrice: fortytwo}, &TransactionArgs{AccessList: al, GasPrice: fortytwo},
&TransactionArgs{AccessList: al, GasPrice: fortytwo}, &TransactionArgs{AccessList: al, GasPrice: fortytwo},
nil, nil,
}, },
{ {
"access list tx post-London", "access list tx post-London",
true, "london",
&TransactionArgs{AccessList: al}, &TransactionArgs{AccessList: al},
&TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
nil, nil,
}, },
{ {
"access list tx post-London, only max fee", "access list tx post-London, only max fee",
true, "london",
&TransactionArgs{AccessList: al, MaxFeePerGas: maxFee}, &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee},
&TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
nil, nil,
}, },
{ {
"access list tx post-London, only priority fee", "access list tx post-London, only priority fee",
true, "london",
&TransactionArgs{AccessList: al, MaxFeePerGas: maxFee}, &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee},
&TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
nil, nil,
@ -129,56 +129,56 @@ func TestSetFeeDefaults(t *testing.T) {
// Dynamic fee txs // Dynamic fee txs
{ {
"dynamic tx post-London", "dynamic tx post-London",
true, "london",
&TransactionArgs{}, &TransactionArgs{},
&TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
nil, nil,
}, },
{ {
"dynamic tx post-London, only max fee", "dynamic tx post-London, only max fee",
true, "london",
&TransactionArgs{MaxFeePerGas: maxFee}, &TransactionArgs{MaxFeePerGas: maxFee},
&TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
nil, nil,
}, },
{ {
"dynamic tx post-London, only priority fee", "dynamic tx post-London, only priority fee",
true, "london",
&TransactionArgs{MaxFeePerGas: maxFee}, &TransactionArgs{MaxFeePerGas: maxFee},
&TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
nil, nil,
}, },
{ {
"dynamic fee tx pre-London, maxFee set", "dynamic fee tx pre-London, maxFee set",
false, "legacy",
&TransactionArgs{MaxFeePerGas: maxFee}, &TransactionArgs{MaxFeePerGas: maxFee},
nil, nil,
errors.New("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active"), errors.New("maxFeePerGas and maxPriorityFeePerGas and maxFeePerBlobGas are not valid before London is active"),
}, },
{ {
"dynamic fee tx pre-London, priorityFee set", "dynamic fee tx pre-London, priorityFee set",
false, "legacy",
&TransactionArgs{MaxPriorityFeePerGas: fortytwo}, &TransactionArgs{MaxPriorityFeePerGas: fortytwo},
nil, nil,
errors.New("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active"), errors.New("maxFeePerGas and maxPriorityFeePerGas and maxFeePerBlobGas are not valid before London is active"),
}, },
{ {
"dynamic fee tx, maxFee < priorityFee", "dynamic fee tx, maxFee < priorityFee",
true, "london",
&TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: (*hexutil.Big)(big.NewInt(1000))}, &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: (*hexutil.Big)(big.NewInt(1000))},
nil, nil,
errors.New("maxFeePerGas (0x3e) < maxPriorityFeePerGas (0x3e8)"), errors.New("maxFeePerGas (0x3e) < maxPriorityFeePerGas (0x3e8)"),
}, },
{ {
"dynamic fee tx, maxFee < priorityFee while setting default", "dynamic fee tx, maxFee < priorityFee while setting default",
true, "london",
&TransactionArgs{MaxFeePerGas: (*hexutil.Big)(big.NewInt(7))}, &TransactionArgs{MaxFeePerGas: (*hexutil.Big)(big.NewInt(7))},
nil, nil,
errors.New("maxFeePerGas (0x7) < maxPriorityFeePerGas (0x2a)"), errors.New("maxFeePerGas (0x7) < maxPriorityFeePerGas (0x2a)"),
}, },
{ {
"dynamic fee tx post-London, explicit gas price", "dynamic fee tx post-London, explicit gas price",
true, "london",
&TransactionArgs{MaxFeePerGas: zero, MaxPriorityFeePerGas: zero}, &TransactionArgs{MaxFeePerGas: zero, MaxPriorityFeePerGas: zero},
nil, nil,
errors.New("maxFeePerGas must be non-zero"), errors.New("maxFeePerGas must be non-zero"),
@ -187,33 +187,60 @@ func TestSetFeeDefaults(t *testing.T) {
// Misc // Misc
{ {
"set all fee parameters", "set all fee parameters",
false, "legacy",
&TransactionArgs{GasPrice: fortytwo, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, &TransactionArgs{GasPrice: fortytwo, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
nil, nil,
errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"), errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"),
}, },
{ {
"set gas price and maxPriorityFee", "set gas price and maxPriorityFee",
false, "legacy",
&TransactionArgs{GasPrice: fortytwo, MaxPriorityFeePerGas: fortytwo}, &TransactionArgs{GasPrice: fortytwo, MaxPriorityFeePerGas: fortytwo},
nil, nil,
errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"), errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"),
}, },
{ {
"set gas price and maxFee", "set gas price and maxFee",
true, "london",
&TransactionArgs{GasPrice: fortytwo, MaxFeePerGas: maxFee}, &TransactionArgs{GasPrice: fortytwo, MaxFeePerGas: maxFee},
nil, nil,
errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"), errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"),
}, },
// EIP-4844
{
"set maxFeePerBlobGas pre cancun",
"london",
&TransactionArgs{BlobFeeCap: fortytwo},
nil,
errors.New("maxFeePerBlobGas is not valid before Cancun is active"),
},
{
"set maxFeePerBlobGas pre london",
"legacy",
&TransactionArgs{BlobFeeCap: fortytwo},
nil,
errors.New("maxFeePerGas and maxPriorityFeePerGas and maxFeePerBlobGas are not valid before London is active"),
},
{
"set gas price and maxFee for blob transaction",
"cancun",
&TransactionArgs{GasPrice: fortytwo, MaxFeePerGas: maxFee, BlobHashes: []common.Hash{}},
nil,
errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"),
},
{
"fill maxFeePerBlobGas",
"cancun",
&TransactionArgs{BlobHashes: []common.Hash{}},
&TransactionArgs{BlobHashes: []common.Hash{}, BlobFeeCap: (*hexutil.Big)(big.NewInt(4)), MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
nil,
},
} }
ctx := context.Background() ctx := context.Background()
for i, test := range tests { for i, test := range tests {
if test.isLondon { if err := b.setFork(test.fork); err != nil {
b.activateLondon() t.Fatalf("failed to set fork: %v", err)
} else {
b.deactivateLondon()
} }
got := test.in got := test.in
err := got.setFeeDefaults(ctx, b) err := got.setFeeDefaults(ctx, b)
@ -235,6 +262,7 @@ type backendMock struct {
} }
func newBackendMock() *backendMock { func newBackendMock() *backendMock {
var cancunTime uint64 = 600
config := &params.ChainConfig{ config := &params.ChainConfig{
ChainID: big.NewInt(42), ChainID: big.NewInt(42),
HomesteadBlock: big.NewInt(0), HomesteadBlock: big.NewInt(0),
@ -250,6 +278,7 @@ func newBackendMock() *backendMock {
MuirGlacierBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0), BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(1000), LondonBlock: big.NewInt(1000),
CancunTime: &cancunTime,
} }
return &backendMock{ return &backendMock{
current: &types.Header{ current: &types.Header{
@ -265,13 +294,25 @@ func newBackendMock() *backendMock {
} }
} }
func (b *backendMock) activateLondon() { func (b *backendMock) setFork(fork string) error {
b.current.Number = big.NewInt(1100) if fork == "legacy" {
b.current.Number = big.NewInt(900)
b.current.Time = 555
} else if fork == "london" {
b.current.Number = big.NewInt(1100)
b.current.Time = 555
} else if fork == "cancun" {
b.current.Number = big.NewInt(1100)
b.current.Time = 700
// Blob base fee will be 2
excess := uint64(2314058)
b.current.ExcessBlobGas = &excess
} else {
return errors.New("invalid fork")
}
return nil
} }
func (b *backendMock) deactivateLondon() {
b.current.Number = big.NewInt(900)
}
func (b *backendMock) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { func (b *backendMock) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
return big.NewInt(42), nil return big.NewInt(42), nil
} }

View file

@ -41,7 +41,7 @@ func NewApp(usage string) *cli.App {
app.EnableBashCompletion = true app.EnableBashCompletion = true
app.Version = params.VersionWithCommit(git.Commit, git.Date) app.Version = params.VersionWithCommit(git.Commit, git.Date)
app.Usage = usage app.Usage = usage
app.Copyright = "Copyright 2013-2023 The go-ethereum Authors" app.Copyright = "Copyright 2013-2024 The go-ethereum Authors"
app.Before = func(ctx *cli.Context) error { app.Before = func(ctx *cli.Context) error {
MigrateGlobalFlags(ctx) MigrateGlobalFlags(ctx)
return nil return nil

View file

@ -35,6 +35,7 @@ import (
type Test struct { type Test struct {
Name string Name string
Fn func(*T) Fn func(*T)
Slow bool
} }
// Result is the result of a test execution. // Result is the result of a test execution.

View file

@ -83,7 +83,7 @@ func LevelAlignedString(l slog.Level) string {
} }
} }
// LevelString returns a 5-character string containing the name of a Lvl. // LevelString returns a string containing the name of a Lvl.
func LevelString(l slog.Level) string { func LevelString(l slog.Level) string {
switch l { switch l {
case LevelTrace: case LevelTrace:
@ -95,7 +95,7 @@ func LevelString(l slog.Level) string {
case slog.LevelWarn: case slog.LevelWarn:
return "warn" return "warn"
case slog.LevelError: case slog.LevelError:
return "eror" return "error"
case LevelCrit: case LevelCrit:
return "crit" return "crit"
default: default:

View file

@ -52,19 +52,19 @@ func TestBuildPayload(t *testing.T) {
verify := func(outer *engine.ExecutionPayloadEnvelope, txs int) { verify := func(outer *engine.ExecutionPayloadEnvelope, txs int) {
payload := outer.ExecutionPayload payload := outer.ExecutionPayload
if payload.ParentHash != b.chain.CurrentBlock().Hash() { if payload.ParentHash != b.chain.CurrentBlock().Hash() {
t.Fatal("Unexpect parent hash") t.Fatal("Unexpected parent hash")
} }
if payload.Random != (common.Hash{}) { if payload.Random != (common.Hash{}) {
t.Fatal("Unexpect random value") t.Fatal("Unexpected random value")
} }
if payload.Timestamp != timestamp { if payload.Timestamp != timestamp {
t.Fatal("Unexpect timestamp") t.Fatal("Unexpected timestamp")
} }
if payload.FeeRecipient != recipient { if payload.FeeRecipient != recipient {
t.Fatal("Unexpect fee recipient") t.Fatal("Unexpected fee recipient")
} }
if len(payload.Transactions) != txs { if len(payload.Transactions) != txs {
t.Fatal("Unexpect transaction set") t.Fatal("Unexpected transaction set")
} }
} }
empty := payload.ResolveEmpty() empty := payload.ResolveEmpty()

View file

@ -344,11 +344,11 @@ func parseLink(e string) (*linkEntry, error) {
return nil, fmt.Errorf("wrong/missing scheme 'enrtree' in URL") return nil, fmt.Errorf("wrong/missing scheme 'enrtree' in URL")
} }
e = e[len(linkPrefix):] e = e[len(linkPrefix):]
pos := strings.IndexByte(e, '@')
if pos == -1 { keystring, domain, found := strings.Cut(e, "@")
if !found {
return nil, entryError{"link", errNoPubkey} return nil, entryError{"link", errNoPubkey}
} }
keystring, domain := e[:pos], e[pos+1:]
keybytes, err := b32format.DecodeString(keystring) keybytes, err := b32format.DecodeString(keystring)
if err != nil { if err != nil {
return nil, entryError{"link", errBadPubkey} return nil, entryError{"link", errBadPubkey}

View file

@ -127,6 +127,7 @@ var (
TerminalTotalDifficulty: big.NewInt(10_790_000), TerminalTotalDifficulty: big.NewInt(10_790_000),
TerminalTotalDifficultyPassed: true, TerminalTotalDifficultyPassed: true,
ShanghaiTime: newUint64(1678832736), ShanghaiTime: newUint64(1678832736),
CancunTime: newUint64(1705473120),
Clique: &CliqueConfig{ Clique: &CliqueConfig{
Period: 15, Period: 15,
Epoch: 30000, Epoch: 30000,
@ -242,6 +243,36 @@ var (
Clique: nil, Clique: nil,
} }
// MergedTestChainConfig contains every protocol change (EIPs) introduced
// and accepted by the Ethereum core developers for testing purposes.
MergedTestChainConfig = &ChainConfig{
ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: false,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
ArrowGlacierBlock: big.NewInt(0),
GrayGlacierBlock: big.NewInt(0),
MergeNetsplitBlock: big.NewInt(0),
ShanghaiTime: newUint64(0),
CancunTime: newUint64(0),
PragueTime: nil,
VerkleTime: nil,
TerminalTotalDifficulty: big.NewInt(0),
TerminalTotalDifficultyPassed: true,
Ethash: new(EthashConfig),
Clique: nil,
}
// NonActivatedConfig defines the chain configuration without activating // NonActivatedConfig defines the chain configuration without activating
// any protocol change (EIPs). // any protocol change (EIPs).
NonActivatedConfig = &ChainConfig{ NonActivatedConfig = &ChainConfig{

View file

@ -23,7 +23,7 @@ import (
const ( const (
VersionMajor = 1 // Major version component of the current release VersionMajor = 1 // Major version component of the current release
VersionMinor = 13 // Minor version component of the current release VersionMinor = 13 // Minor version component of the current release
VersionPatch = 9 // Patch version component of the current release VersionPatch = 11 // Patch version component of the current release
VersionMeta = "unstable" // Version metadata to append to the version string VersionMeta = "unstable" // Version metadata to append to the version string
) )

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/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
@ -224,6 +225,7 @@ func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error)
cb, err := b.decode() cb, err := b.decode()
if err != nil { if err != nil {
if b.BlockHeader == nil { if b.BlockHeader == nil {
log.Info("Block decoding failed", "index", bi, "err", err)
continue // OK - block is supposed to be invalid, continue with next block continue // OK - block is supposed to be invalid, continue with next block
} else { } else {
return nil, fmt.Errorf("block RLP decoding failed when expected to succeed: %v", err) return nil, fmt.Errorf("block RLP decoding failed when expected to succeed: %v", err)

View file

@ -62,14 +62,6 @@ func TestState(t *testing.T) {
// EOF is not part of cancun // EOF is not part of cancun
st.skipLoad(`^stEOF/`) st.skipLoad(`^stEOF/`)
// EIP-4844 tests need to be regenerated due to the data-to-blob rename
st.skipLoad(`^stEIP4844-blobtransactions/`)
// Expected failures:
// These EIP-4844 tests need to be regenerated.
st.fails(`stEIP4844-blobtransactions/opcodeBlobhashOutOfRange.json`, "test has incorrect state root")
st.fails(`stEIP4844-blobtransactions/opcodeBlobhBounds.json`, "test has incorrect state root")
// For Istanbul, older tests were moved into LegacyTests // For Istanbul, older tests were moved into LegacyTests
for _, dir := range []string{ for _, dir := range []string{
filepath.Join(baseDir, "EIPTests", "StateTests"), filepath.Join(baseDir, "EIPTests", "StateTests"),

View file

@ -291,6 +291,17 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
} }
evm := vm.NewEVM(context, txContext, statedb, config, vmconfig) evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
{ // Blob transactions may be present after the Cancun fork.
// In production,
// - the header is verified against the max in eip4844.go:VerifyEIP4844Header
// - the block body is verified against the header in block_validator.go:ValidateBody
// Here, we just do this shortcut smaller fix, since state tests do not
// utilize those codepaths
if len(msg.BlobHashes)*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock {
return nil, nil, nil, common.Hash{}, errors.New("blob gas exceeds maximum")
}
}
// Execute the message. // Execute the message.
snapshot := statedb.Snapshot() snapshot := statedb.Snapshot()
gaspool := new(core.GasPool) gaspool := new(core.GasPool)

@ -1 +1 @@
Subproject commit ee3fa4c86d05f99f2717f83a6ad08008490ddf07 Subproject commit fa51c5c164f79140730ccb8fe26a46c3d3994338