Skip to content

Commit a029736

Browse files
committed
migrate sentio tracer to geth
migrate override and gas changes (OffchainLabs#1) migrate memory compression (OffchainLabs#2) add more information for root trace (OffchainLabs#3) correct handle call with value (OffchainLabs#4) * correct handle call with value * set transfer value to zero if can't transfer Add Mapping keys to post account (OffchainLabs#5) fix when tracer failed before start (OffchainLabs#6) unlimited gas for debug_traceCallMany (OffchainLabs#7) support multiple txs in tracecallmany rpc client should keep result while return error be able to return partial results migrate tracer changes (OffchainLabs#8) export meq field (OffchainLabs#9) ignore init code size limit (OffchainLabs#10) code address field (OffchainLabs#11) minor fix (OffchainLabs#12) fix type compat (OffchainLabs#13) fix compability with arb fix storagerangeat emit output for revert (OffchainLabs#14)
1 parent b466858 commit a029736

File tree

13 files changed

+1337
-29
lines changed

13 files changed

+1337
-29
lines changed

cmd/geth/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import (
4444
// Force-load the tracer engines to trigger registration
4545
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
4646
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
47+
_ "github.com/ethereum/go-ethereum/eth/tracers/sentio"
4748

4849
"github.com/urfave/cli/v2"
4950
)

core/state_transition.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -452,14 +452,16 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
452452
)
453453

454454
// Check clauses 4-5, subtract intrinsic gas if everything is correct
455-
gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
456-
if err != nil {
457-
return nil, err
458-
}
459-
if st.gasRemaining < gas {
460-
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
455+
if !st.evm.Config.IgnoreGas {
456+
gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
457+
if err != nil {
458+
return nil, err
459+
}
460+
if st.gasRemaining < gas {
461+
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
462+
}
463+
st.gasRemaining -= gas
461464
}
462-
st.gasRemaining -= gas
463465

464466
tipAmount := big.NewInt(0)
465467
tipReceipient, err := st.evm.ProcessingHook.GasChargingHook(&st.gasRemaining)
@@ -477,7 +479,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
477479
}
478480

479481
// Check whether the init code size has been exceeded.
480-
if rules.IsShanghai && contractCreation && len(msg.Data) > int(st.evm.ChainConfig().MaxInitCodeSize()) {
482+
if !st.evm.Config.IgnoreCodeSizeLimit && rules.IsShanghai && contractCreation && len(msg.Data) > int(st.evm.ChainConfig().MaxInitCodeSize()) {
481483
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), int(st.evm.ChainConfig().MaxInitCodeSize()))
482484
}
483485

core/vm/evm.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,16 @@ func (c *codeAndHash) Hash() common.Hash {
476476
func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *uint256.Int, address common.Address, typ OpCode) ([]byte, common.Address, uint64, error) {
477477
// Depth check execution. Fail if we're trying to execute above the
478478
// limit.
479+
if evm.Config.CreateAddressOverride != nil {
480+
address = *evm.Config.CreateAddressOverride
481+
}
482+
if evm.Config.CreationCodeOverrides != nil {
483+
if code, ok := evm.Config.CreationCodeOverrides[address]; ok {
484+
codeAndHash.code = code
485+
codeAndHash.hash = common.Hash{}
486+
_ = codeAndHash.Hash()
487+
}
488+
}
479489
if evm.depth > int(params.CallCreateDepth) {
480490
return nil, common.Address{}, gas, ErrDepth
481491
}
@@ -492,10 +502,12 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
492502
if evm.chainRules.IsBerlin {
493503
evm.StateDB.AddAddressToAccessList(address)
494504
}
495-
// Ensure there's no existing contract already at the designated address
496-
contractHash := evm.StateDB.GetCodeHash(address)
497-
if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) {
498-
return nil, common.Address{}, 0, ErrContractAddressCollision
505+
if evm.Config.CreateAddressOverride == nil {
506+
// Ensure there's no existing contract already at the designated address
507+
contractHash := evm.StateDB.GetCodeHash(address)
508+
if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) {
509+
return nil, common.Address{}, 0, ErrContractAddressCollision
510+
}
499511
}
500512
// Create a new account on the state
501513
snapshot := evm.StateDB.Snapshot()
@@ -521,7 +533,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
521533
ret, err := evm.interpreter.Run(contract, nil, false)
522534

523535
// Check whether the max code size has been exceeded, assign err if the case.
524-
if err == nil && evm.chainRules.IsEIP158 && len(ret) > int(evm.chainConfig.MaxCodeSize()) {
536+
if err == nil && !evm.Config.IgnoreCodeSizeLimit && evm.chainRules.IsEIP158 && len(ret) > int(evm.chainConfig.MaxCodeSize()) {
525537
err = ErrMaxCodeSizeExceeded
526538
}
527539

@@ -541,6 +553,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
541553
// by the error checking condition below.
542554
if err == nil {
543555
createDataGas := uint64(len(ret)) * params.CreateDataGas
556+
if evm.Config.IgnoreGas {
557+
createDataGas = 0
558+
}
544559
if contract.UseGas(createDataGas) {
545560
evm.StateDB.SetCode(address, ret)
546561
} else {

core/vm/instructions.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
599599
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
600600
gas = scope.Contract.Gas
601601
)
602-
if interpreter.evm.chainRules.IsEIP150 {
602+
if !interpreter.evm.Config.IgnoreGas && interpreter.evm.chainRules.IsEIP150 {
603603
gas -= gas / 64
604604
}
605605
// reuse size int for stackvalue
@@ -642,7 +642,9 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
642642
gas = scope.Contract.Gas
643643
)
644644
// Apply EIP150
645-
gas -= gas / 64
645+
if !interpreter.evm.Config.IgnoreGas {
646+
gas -= gas / 64
647+
}
646648
scope.Contract.UseGas(gas)
647649
// reuse size int for stackvalue
648650
stackvalue := size

core/vm/interpreter.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package vm
1818

1919
import (
2020
"github.com/ethereum/go-ethereum/common"
21+
"github.com/ethereum/go-ethereum/common/hexutil"
2122
"github.com/ethereum/go-ethereum/common/math"
2223
"github.com/ethereum/go-ethereum/core/state"
2324
"github.com/ethereum/go-ethereum/crypto"
@@ -30,6 +31,11 @@ type Config struct {
3031
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
3132
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
3233
ExtraEips []int // Additional EIPS that are to be enabled
34+
35+
CreationCodeOverrides map[common.Address]hexutil.Bytes
36+
CreateAddressOverride *common.Address
37+
IgnoreGas bool
38+
IgnoreCodeSizeLimit bool
3339
}
3440

3541
// ScopeContext contains the things that are per-call, such as stack and memory,
@@ -96,6 +102,22 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
96102
}
97103
}
98104
evm.Config.ExtraEips = extraEips
105+
if evm.Config.IgnoreGas {
106+
table = copyJumpTable(table)
107+
for i, op := range table {
108+
opCode := OpCode(i)
109+
// retain call costs to prevent call stack from going too deep
110+
// some contracts use a loop to burn gas
111+
// if all codes in the loop have zero cost, it will run forever
112+
if opCode == CALL || opCode == STATICCALL || opCode == CALLCODE || opCode == DELEGATECALL || opCode == GAS {
113+
continue
114+
}
115+
op.constantGas = 0
116+
op.dynamicGas = func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) {
117+
return 0, nil
118+
}
119+
}
120+
}
99121
return &EVMInterpreter{evm: evm, table: table}
100122
}
101123

eth/api_debug.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,12 +221,8 @@ type storageEntry struct {
221221

222222
// StorageRangeAt returns the storage at the given block height and transaction index.
223223
func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
224-
var block *types.Block
224+
block := api.eth.blockchain.GetBlockByHash(*blockNrOrHash.BlockHash)
225225

226-
block, err := api.eth.APIBackend.BlockByNumberOrHash(ctx, blockNrOrHash)
227-
if err != nil {
228-
return StorageRangeResult{}, err
229-
}
230226
if block == nil {
231227
return StorageRangeResult{}, fmt.Errorf("block %v not found", blockNrOrHash)
232228
}

eth/tracers/api.go

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,13 +160,18 @@ type TraceConfig struct {
160160
// Config specific to given tracer. Note struct logger
161161
// config are historically embedded in main object.
162162
TracerConfig json.RawMessage
163+
164+
StateOverrides *ethapi.StateOverride
165+
IgnoreGas *bool
166+
IgnoreCodeSizeLimit *bool
167+
CreationCodeOverrides map[common.Address]hexutil.Bytes
168+
CreateAddressOverride *common.Address
163169
}
164170

165171
// TraceCallConfig is the config for traceCall API. It holds one more
166172
// field to override the state for tracing.
167173
type TraceCallConfig struct {
168174
TraceConfig
169-
StateOverrides *ethapi.StateOverride
170175
BlockOverrides *ethapi.BlockOverrides
171176
TxIndex *hexutil.Uint
172177
}
@@ -862,6 +867,12 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
862867
TxIndex: int(index),
863868
TxHash: hash,
864869
}
870+
871+
if config != nil {
872+
if err := config.StateOverrides.Apply(statedb); err != nil {
873+
return nil, err
874+
}
875+
}
865876
return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
866877
}
867878

@@ -956,7 +967,21 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Conte
956967
return nil, err
957968
}
958969
}
959-
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true})
970+
vmConfig := vm.Config{
971+
Tracer: tracer,
972+
NoBaseFee: true,
973+
}
974+
if config != nil {
975+
vmConfig.CreateAddressOverride = config.CreateAddressOverride
976+
vmConfig.CreationCodeOverrides = config.CreationCodeOverrides
977+
if config.IgnoreCodeSizeLimit != nil {
978+
vmConfig.IgnoreCodeSizeLimit = *config.IgnoreCodeSizeLimit
979+
}
980+
if config.IgnoreGas != nil {
981+
vmConfig.IgnoreGas = *config.IgnoreGas
982+
}
983+
}
984+
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vmConfig)
960985

961986
// Define a meaningful timeout of a single transaction trace
962987
if config.Timeout != nil {
@@ -1042,3 +1067,116 @@ func overrideConfig(original *params.ChainConfig, override *params.ChainConfig)
10421067

10431068
return copy, canon
10441069
}
1070+
1071+
type Bundle struct {
1072+
Transactions []*ethapi.TransactionArgs `json:"transactions"`
1073+
BlockOverride ethapi.BlockOverrides `json:"blockOverride"`
1074+
}
1075+
1076+
type StateContext struct {
1077+
BlockNumber *rpc.BlockNumberOrHash `json:"blockNumber"`
1078+
TransactionIndex int `json:"transactionIndex"`
1079+
}
1080+
1081+
type FailedTrace struct {
1082+
Failed string `json:"failed,omitempty"`
1083+
}
1084+
1085+
func (api *API) TraceCallMany(ctx context.Context, bundles []*Bundle, simulateContext *StateContext, config *TraceCallConfig) (interface{}, error) {
1086+
if len(bundles) == 0 {
1087+
return nil, errors.New("empty bundles")
1088+
}
1089+
var result []interface{}
1090+
for _, bundle := range bundles {
1091+
r, err := api.traceBundle(ctx, bundle, simulateContext, config)
1092+
if err != nil {
1093+
if r != nil {
1094+
// return partial results
1095+
r = append(r, &FailedTrace{Failed: err.Error()})
1096+
result = append(result, r)
1097+
return result, nil
1098+
}
1099+
return nil, err
1100+
}
1101+
result = append(result, r)
1102+
}
1103+
return result, nil
1104+
}
1105+
1106+
func (api *API) traceBundle(ctx context.Context, bundle *Bundle, simulateContext *StateContext, config *TraceCallConfig) ([]interface{}, error) {
1107+
var result []interface{}
1108+
// Try to retrieve the specified block
1109+
var (
1110+
err error
1111+
block *types.Block
1112+
)
1113+
if hash, ok := simulateContext.BlockNumber.Hash(); ok {
1114+
block, err = api.blockByHash(ctx, hash)
1115+
} else if number, ok := simulateContext.BlockNumber.Number(); ok {
1116+
if number == rpc.PendingBlockNumber {
1117+
// We don't have access to the miner here. For tracing 'future' transactions,
1118+
// it can be done with block- and state-overrides instead, which offers
1119+
// more flexibility and stability than trying to trace on 'pending', since
1120+
// the contents of 'pending' is unstable and probably not a true representation
1121+
// of what the next actual block is likely to contain.
1122+
return nil, errors.New("tracing on top of pending is not supported")
1123+
}
1124+
block, err = api.blockByNumber(ctx, number)
1125+
} else {
1126+
return nil, errors.New("invalid arguments; neither block nor hash specified")
1127+
}
1128+
if err != nil {
1129+
return nil, err
1130+
}
1131+
// try to recompute the state
1132+
reexec := defaultTraceReexec
1133+
if config != nil && config.Reexec != nil {
1134+
reexec = *config.Reexec
1135+
}
1136+
is158 := api.backend.ChainConfig().IsEIP158(block.Number())
1137+
1138+
if err != nil {
1139+
return nil, err
1140+
}
1141+
_, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, simulateContext.TransactionIndex, reexec)
1142+
if err != nil {
1143+
return nil, err
1144+
}
1145+
defer release()
1146+
1147+
// Apply the customization rules if required.
1148+
if config != nil {
1149+
if err := config.StateOverrides.Apply(statedb); err != nil {
1150+
return nil, err
1151+
}
1152+
config.BlockOverrides.Apply(&vmctx)
1153+
}
1154+
// Execute the trace
1155+
for idx, args := range bundle.Transactions {
1156+
if args.Gas == nil {
1157+
gasCap := api.backend.RPCGasCap()
1158+
args.Gas = (*hexutil.Uint64)(&gasCap)
1159+
}
1160+
msg, err := args.ToMessage(api.backend.RPCGasCap(), block.Header(), statedb, core.MessageEthcallMode)
1161+
if err != nil {
1162+
return result, err
1163+
}
1164+
1165+
var traceConfig *TraceConfig
1166+
if config != nil {
1167+
traceConfig = &config.TraceConfig
1168+
}
1169+
txctx := &Context{
1170+
BlockHash: block.Hash(),
1171+
BlockNumber: block.Number(),
1172+
TxIndex: simulateContext.TransactionIndex + idx,
1173+
}
1174+
r, err := api.traceTx(ctx, msg, txctx, vmctx, statedb, traceConfig)
1175+
if err != nil {
1176+
return result, err
1177+
}
1178+
result = append(result, r)
1179+
statedb.Finalise(is158)
1180+
}
1181+
return result, nil
1182+
}

eth/tracers/logger/gen_structlog.go

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)