diff --git a/consensus/consortium/main.go b/consensus/consortium/main.go index cd2ceb5547..0d0cee3561 100644 --- a/consensus/consortium/main.go +++ b/consensus/consortium/main.go @@ -202,22 +202,26 @@ func (c *Consortium) GetBestParentBlock(chain *core.BlockChain) (*types.Block, b return c.v2.GetBestParentBlock(chain) } -// HandleSubmitBlockReward determines if the transaction is submitBlockReward -// transaction with non-zero msg.value and fixes up the statedb. -// This function bases on the fact that submitBlockReward is the only system -// transaction that may have non-zero msg.value -func HandleSubmitBlockReward(engine consensus.Engine, statedb *state.StateDB, msg core.Message, block *types.Block) { +// HandleSystemTransaction fixes up the statedb when system transaction +// goes through ApplyMessage when tracing/debugging +func HandleSystemTransaction(engine consensus.Engine, statedb *state.StateDB, msg core.Message, block *types.Block) bool { consortium, ok := engine.(*Consortium) if !ok { - return + return false } if consortium.chainConfig.IsConsortiumV2(new(big.Int).Add(block.Number(), common.Big1)) { isSystemMsg := consortium.v2.IsSystemMessage(msg, block.Header()) - if isSystemMsg && msg.Value().Cmp(common.Big0) > 0 { - balance := statedb.GetBalance(consensus.SystemAddress) - statedb.SetBalance(consensus.SystemAddress, big.NewInt(0)) - statedb.AddBalance(block.Coinbase(), balance) + if isSystemMsg { + if msg.Value().Cmp(common.Big0) > 0 { + balance := statedb.GetBalance(consensus.SystemAddress) + statedb.SetBalance(consensus.SystemAddress, big.NewInt(0)) + statedb.AddBalance(block.Coinbase(), balance) + } + + return true } } + + return false } diff --git a/core/state_transition.go b/core/state_transition.go index 15f72fddc4..cc73d2f2d6 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -304,14 +304,16 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { contractCreation := msg.To() == nil // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul) - if err != nil { - return nil, err - } - if st.gas < gas { - return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas) + if !st.evm.Config.IsSystemTransaction { + gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul) + if err != nil { + return nil, err + } + if st.gas < gas { + return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas) + } + st.gas -= gas } - st.gas -= gas // Check clause 6 if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) { @@ -334,12 +336,14 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value) } - if !london { - // Before EIP-3529: refunds were capped to gasUsed / 2 - st.refundGas(params.RefundQuotient) - } else { - // After EIP-3529: refunds are capped to gasUsed / 5 - st.refundGas(params.RefundQuotientEIP3529) + if !st.evm.Config.IsSystemTransaction { + if !london { + // Before EIP-3529: refunds were capped to gasUsed / 2 + st.refundGas(params.RefundQuotient) + } else { + // After EIP-3529: refunds are capped to gasUsed / 5 + st.refundGas(params.RefundQuotientEIP3529) + } } effectiveTip := st.gasPrice diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 5a2fd64769..49bad71e04 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -36,6 +36,8 @@ type Config struct { JumpTable [256]*operation // EVM instruction table, automatically populated if unset ExtraEips []int // Additional EIPS that are to be enabled + + IsSystemTransaction bool // Used by tracer to specially handle system transaction } // ScopeContext contains the things that are per-call, such as stack and memory, diff --git a/eth/state_accessor.go b/eth/state_accessor.go index d095eea03e..8e3e10409d 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -213,7 +213,9 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{}) statedb.Prepare(tx.Hash(), idx) - consortium.HandleSubmitBlockReward(eth.engine, statedb, msg, block) + if consortium.HandleSystemTransaction(eth.engine, statedb, msg, block) { + vmenv.Config.IsSystemTransaction = true + } if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 8f49f35bad..4719f56d51 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -585,7 +585,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{}) ) statedb.Prepare(tx.Hash(), i) - consortium.HandleSubmitBlockReward(api.backend.Engine(), statedb, msg, block) + if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, msg, block) { + vmenv.Config.IsSystemTransaction = true + } if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) // We intentionally don't return the error here: if we do, then the RPC server will not @@ -731,8 +733,10 @@ txloop: // Generate the next state snapshot fast without tracing msg, _ := tx.AsMessage(signer, block.BaseFee()) statedb.Prepare(tx.Hash(), i) - consortium.HandleSubmitBlockReward(api.backend.Engine(), statedb, msg, block) vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{}) + if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, msg, block) { + vmenv.Config.IsSystemTransaction = true + } if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { failed = err break txloop @@ -827,8 +831,10 @@ txloop: // Generate the next state snapshot fast without tracing msg, _ := tx.AsMessage(signer, block.BaseFee()) statedb.Prepare(tx.Hash(), i) - consortium.HandleSubmitBlockReward(api.backend.Engine(), statedb, msg, block) vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{}) + if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, msg, block) { + vmenv.Config.IsSystemTransaction = true + } if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { failed = err break txloop @@ -948,7 +954,9 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Execute the transaction and flush any traces to disk vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) statedb.Prepare(tx.Hash(), i) - consortium.HandleSubmitBlockReward(api.backend.Engine(), statedb, msg, block) + if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, msg, block) { + vmenv.Config.IsSystemTransaction = true + } _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())) if writer != nil { writer.Flush() @@ -1134,7 +1142,9 @@ func (api *API) traceTx( // Call Prepare to clear out the statedb access list statedb.Prepare(txctx.TxHash, txctx.TxIndex) - consortium.HandleSubmitBlockReward(api.backend.Engine(), statedb, message, block) + if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, message, block) { + vmenv.Config.IsSystemTransaction = true + } _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) if err != nil { return nil, fmt.Errorf("tracing failed: %w", err) diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple_onlytop.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple_onlytop.json new file mode 100644 index 0000000000..5fbdf55d22 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple_onlytop.json @@ -0,0 +1,100 @@ +{ + "context": { + "difficulty": "3502894804", + "gasLimit": "4722976", + "miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724", + "number": "2289806", + "timestamp": "1513601314" + }, + "genesis": { + "alloc": { + "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": { + "balance": "0x0", + "code": "0x", + "nonce": "22", + "storage": {} + }, + "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { + "balance": "0x4d87094125a369d9bd5", + "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" + } + }, + "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { + "balance": "0x1780d77678137ac1b775", + "code": "0x", + "nonce": "29072", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3509749784", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "4727564", + "hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada", + "nonce": "0x4eb12e19c16d43da", + "number": "2289805", + "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", + "timestamp": "1513601261", + "totalDifficulty": "7143276353481064" + }, + "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", + "tracerConfig": { + "onlyTopCall": true + }, + "result": [ + { + "action": { + "callType": "call", + "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", + "gas": "0x15f90", + "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", + "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "value": "0x0" + }, + "blockNumber": 2289806, + "result": { + "gasUsed": "0x9751", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "gas": "0x6d05", + "input": "0x", + "to": "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", + "value": "0x6f05b59d3b20000" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x0", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [0], + "type": "call" + } + ] +} diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 36aa667112..3e1b319dab 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -129,7 +129,9 @@ func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Trace } } - tracer, err := tracers.DefaultDirectory.New("callTracer", ctx, cfg) + // Create inner call tracer with default configuration, don't forward + // the OnlyTopCall or WithLog to inner for now + tracer, err := tracers.DefaultDirectory.New("callTracer", ctx, nil) if err != nil { return nil, err } diff --git a/les/state_accessor.go b/les/state_accessor.go index eec8a557d2..68dbaf1fd4 100644 --- a/les/state_accessor.go +++ b/les/state_accessor.go @@ -70,7 +70,9 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types. } // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(context, txContext, statedb, leth.blockchain.Config(), vm.Config{}) - consortium.HandleSubmitBlockReward(leth.engine, statedb, msg, block) + if consortium.HandleSystemTransaction(leth.engine, statedb, msg, block) { + vmenv.Config.IsSystemTransaction = true + } if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) }