Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/v0.13.1 #1

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,22 +401,24 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
)

// Check clauses 4-5, subtract intrinsic gas if everything is correct
gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules)
if err != nil {
return nil, err
}
if st.gasRemaining < gas {
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
if !st.evm.Config.IgnoreGas {
gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules)
if err != nil {
return nil, err
}
if st.gasRemaining < gas {
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
}
st.gasRemaining -= gas
}
st.gasRemaining -= gas

// Check clause 6
if msg.Value.Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From, msg.Value) {
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())
}

// Check whether the init code size has been exceeded.
if rules.IsDurango && contractCreation && len(msg.Data) > params.MaxInitCodeSize {
if !st.evm.Config.IgnoreCodeSizeLimit && rules.IsDurango && contractCreation && len(msg.Data) > params.MaxInitCodeSize {
return nil, fmt.Errorf("%w: code size %v limit %v", vmerrs.ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize)
}

Expand Down
26 changes: 21 additions & 5 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,16 @@ func (c *codeAndHash) Hash() common.Hash {
func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address, typ OpCode) ([]byte, common.Address, uint64, error) {
// Depth check execution. Fail if we're trying to execute above the
// limit.
if evm.Config.CreateAddressOverride != nil {
address = *evm.Config.CreateAddressOverride
}
if evm.Config.CreationCodeOverrides != nil {
if code, ok := evm.Config.CreationCodeOverrides[address]; ok {
codeAndHash.code = code
codeAndHash.hash = common.Hash{}
_ = codeAndHash.Hash()
}
}
if evm.depth > int(params.CallCreateDepth) {
return nil, common.Address{}, gas, vmerrs.ErrDepth
}
Expand All @@ -614,10 +624,13 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
if evm.chainRules.IsApricotPhase2 {
evm.StateDB.AddAddressToAccessList(address)
}
// Ensure there's no existing contract already at the designated address
contractHash := evm.StateDB.GetCodeHash(address)
if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) {
return nil, common.Address{}, 0, vmerrs.ErrContractAddressCollision

if evm.Config.CreateAddressOverride == nil {
// Ensure there's no existing contract already at the designated address
contractHash := evm.StateDB.GetCodeHash(address)
if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) {
return nil, common.Address{}, 0, vmerrs.ErrContractAddressCollision
}
}
// Create a new account on the state
snapshot := evm.StateDB.Snapshot()
Expand All @@ -643,7 +656,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
ret, err := evm.interpreter.Run(contract, nil, false)

// Check whether the max code size has been exceeded, assign err if the case.
if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
if err == nil && !evm.Config.IgnoreCodeSizeLimit && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
err = vmerrs.ErrMaxCodeSizeExceeded
}

Expand All @@ -658,6 +671,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// by the error checking condition below.
if err == nil {
createDataGas := uint64(len(ret)) * params.CreateDataGas
if evm.Config.IgnoreGas {
createDataGas = 0
}
if contract.UseGas(createDataGas) {
evm.StateDB.SetCode(address, ret)
} else {
Expand Down
6 changes: 4 additions & 2 deletions core/vm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
gas = scope.Contract.Gas
)
if interpreter.evm.chainRules.IsEIP150 {
if !interpreter.evm.Config.IgnoreGas && interpreter.evm.chainRules.IsEIP150 {
gas -= gas / 64
}
// reuse size int for stackvalue
Expand Down Expand Up @@ -648,7 +648,9 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
gas = scope.Contract.Gas
)
// Apply EIP150
gas -= gas / 64
if !interpreter.evm.Config.IgnoreGas {
gas -= gas / 64
}
scope.Contract.UseGas(gas)
// reuse size int for stackvalue
stackvalue := size
Expand Down
22 changes: 22 additions & 0 deletions core/vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ package vm
import (
"github.com/ava-labs/coreth/vmerrs"
"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/crypto"
"github.com/ethereum/go-ethereum/log"
Expand All @@ -45,6 +46,11 @@ type Config struct {
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
ExtraEips []int // Additional EIPS that are to be enabled

CreationCodeOverrides map[common.Address]hexutil.Bytes
CreateAddressOverride *common.Address
IgnoreGas bool
IgnoreCodeSizeLimit bool
}

// ScopeContext contains the things that are per-call, such as stack and memory,
Expand Down Expand Up @@ -109,6 +115,22 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
}
}
evm.Config.ExtraEips = extraEips
if evm.Config.IgnoreGas {
table = copyJumpTable(table)
for i, op := range table {
opCode := OpCode(i)
// retain call costs to prevent call stack from going too deep
// some contracts use a loop to burn gas
// if all codes in the loop have zero cost, it will run forever
if opCode == CALL || opCode == STATICCALL || opCode == CALLCODE || opCode == DELEGATECALL || opCode == GAS {
continue
}
op.constantGas = 0
op.dynamicGas = func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) {
return 0, nil
}
}
}
return &EVMInterpreter{evm: evm, table: table}
}

Expand Down
142 changes: 140 additions & 2 deletions eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,18 @@ type TraceConfig struct {
// Config specific to given tracer. Note struct logger
// config are historically embedded in main object.
TracerConfig json.RawMessage

StateOverrides *ethapi.StateOverride
IgnoreGas *bool
IgnoreCodeSizeLimit *bool
CreationCodeOverrides map[common.Address]hexutil.Bytes
CreateAddressOverride *common.Address
}

// TraceCallConfig is the config for traceCall API. It holds one more
// field to override the state for tracing.
type TraceCallConfig struct {
TraceConfig
StateOverrides *ethapi.StateOverride
BlockOverrides *ethapi.BlockOverrides
}

Expand Down Expand Up @@ -906,6 +911,12 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
TxIndex: int(index),
TxHash: hash,
}

if config != nil {
if err := config.StateOverrides.Apply(statedb); err != nil {
return nil, err
}
}
return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
}

Expand Down Expand Up @@ -997,7 +1008,21 @@ func (api *baseAPI) traceTx(ctx context.Context, message *core.Message, txctx *C
return nil, err
}
}
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true})
vmConfig := vm.Config{
Tracer: tracer,
NoBaseFee: true,
}
if config != nil {
vmConfig.CreateAddressOverride = config.CreateAddressOverride
vmConfig.CreationCodeOverrides = config.CreationCodeOverrides
if config.IgnoreCodeSizeLimit != nil {
vmConfig.IgnoreCodeSizeLimit = *config.IgnoreCodeSizeLimit
}
if config.IgnoreGas != nil {
vmConfig.IgnoreGas = *config.IgnoreGas
}
}
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vmConfig)

// Define a meaningful timeout of a single transaction trace
if config.Timeout != nil {
Expand Down Expand Up @@ -1097,3 +1122,116 @@ func overrideConfig(original *params.ChainConfig, override *params.ChainConfig)

return copy, canon
}

type Bundle struct {
Transactions []*ethapi.TransactionArgs `json:"transactions"`
BlockOverride ethapi.BlockOverrides `json:"blockOverride"`
}

type StateContext struct {
BlockNumber *rpc.BlockNumberOrHash `json:"blockNumber"`
TransactionIndex int `json:"transactionIndex"`
}

type FailedTrace struct {
Failed string `json:"failed,omitempty"`
}

func (api *API) TraceCallMany(ctx context.Context, bundles []*Bundle, simulateContext *StateContext, config *TraceCallConfig) (interface{}, error) {
if len(bundles) == 0 {
return nil, errors.New("empty bundles")
}
var result []interface{}
for _, bundle := range bundles {
r, err := api.traceBundle(ctx, bundle, simulateContext, config)
if err != nil {
if r != nil {
// return partial results
r = append(r, &FailedTrace{Failed: err.Error()})
result = append(result, r)
return result, nil
}
return nil, err
}
result = append(result, r)
}
return result, nil
}

func (api *API) traceBundle(ctx context.Context, bundle *Bundle, simulateContext *StateContext, config *TraceCallConfig) ([]interface{}, error) {
var result []interface{}
// Try to retrieve the specified block
var (
err error
block *types.Block
)
if hash, ok := simulateContext.BlockNumber.Hash(); ok {
block, err = api.blockByHash(ctx, hash)
} else if number, ok := simulateContext.BlockNumber.Number(); ok {
if number == rpc.PendingBlockNumber {
// We don't have access to the miner here. For tracing 'future' transactions,
// it can be done with block- and state-overrides instead, which offers
// more flexibility and stability than trying to trace on 'pending', since
// the contents of 'pending' is unstable and probably not a true representation
// of what the next actual block is likely to contain.
return nil, errors.New("tracing on top of pending is not supported")
}
block, err = api.blockByNumber(ctx, number)
} else {
return nil, errors.New("invalid arguments; neither block nor hash specified")
}
if err != nil {
return nil, err
}
// try to recompute the state
reexec := defaultTraceReexec
if config != nil && config.Reexec != nil {
reexec = *config.Reexec
}
is158 := api.backend.ChainConfig().IsEIP158(block.Number())

if err != nil {
return nil, err
}
_, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, simulateContext.TransactionIndex, reexec)
if err != nil {
return nil, err
}
defer release()

// Apply the customization rules if required.
if config != nil {
if err := config.StateOverrides.Apply(statedb); err != nil {
return nil, err
}
config.BlockOverrides.Apply(&vmctx)
}
// Execute the trace
for idx, args := range bundle.Transactions {
if args.Gas == nil {
gasCap := api.backend.RPCGasCap()
args.Gas = (*hexutil.Uint64)(&gasCap)
}
msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee())
if err != nil {
return result, err
}

var traceConfig *TraceConfig
if config != nil {
traceConfig = &config.TraceConfig
}
txctx := &Context{
BlockHash: block.Hash(),
BlockNumber: block.Number(),
TxIndex: simulateContext.TransactionIndex + idx,
}
r, err := api.traceTx(ctx, msg, txctx, vmctx, statedb, traceConfig)
if err != nil {
return result, err
}
result = append(result, r)
statedb.Finalise(is158)
}
return result, nil
}
1 change: 1 addition & 0 deletions eth/tracers/internal/tracetest/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
// Force-load native and js packages, to trigger registration
_ "github.com/ava-labs/coreth/eth/tracers/js"
_ "github.com/ava-labs/coreth/eth/tracers/native"
_ "github.com/ava-labs/coreth/eth/tracers/sentio"
)

// To generate a new callTracer test, copy paste the makeTest method below into
Expand Down
6 changes: 6 additions & 0 deletions eth/tracers/logger/gen_structlog.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading