diff --git a/core/state_transition.go b/core/state_transition.go index 8c01b2c285..ff3b7ba023 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -310,7 +310,7 @@ func (st *StateTransition) buyGas() error { // Arbitrum: record fee payment if tracer := st.evm.Config.Tracer; tracer != nil && tracer.CaptureArbitrumTransfer != nil { - tracer.CaptureArbitrumTransfer(&st.msg.From, nil, mgval, true, "feePayment") + tracer.CaptureArbitrumTransfer(&st.msg.From, nil, mgval, true, tracing.BalanceDecreaseGasBuy) } return nil @@ -529,7 +529,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { // Arbitrum: record the tip if tracer := st.evm.Config.Tracer; tracer != nil && !st.evm.ProcessingHook.DropTip() && tracer.CaptureArbitrumTransfer != nil { - tracer.CaptureArbitrumTransfer(nil, &tipReceipient, tipAmount, false, "tip") + tracer.CaptureArbitrumTransfer(nil, &tipReceipient, tipAmount, false, tracing.BalanceIncreaseRewardTransactionFee) } st.evm.ProcessingHook.EndTxHook(st.gasRemaining, vmerr == nil) @@ -539,7 +539,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { suicides := st.evm.StateDB.GetSelfDestructs() for i, address := range suicides { balance := st.evm.StateDB.GetBalance(address) - tracer.CaptureArbitrumTransfer(&suicides[i], nil, balance.ToBig(), false, "selfDestruct") + tracer.CaptureArbitrumTransfer(&suicides[i], nil, balance.ToBig(), false, tracing.BalanceDecreaseSelfdestruct) } } @@ -583,7 +583,7 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { // Arbitrum: record the gas refund if tracer := st.evm.Config.Tracer; tracer != nil && tracer.CaptureArbitrumTransfer != nil { - tracer.CaptureArbitrumTransfer(nil, &st.msg.From, remaining.ToBig(), false, "gasRefund") + tracer.CaptureArbitrumTransfer(nil, &st.msg.From, remaining.ToBig(), false, tracing.BalanceIncreaseGasReturn) } // Also return remaining gas to the block gas counter so it is diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index f95de98b94..6af11631f3 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -171,7 +171,7 @@ type ( // LogHook is called when a log is emitted. LogHook = func(log *types.Log) - CaptureArbitrumTransferHook = func(from, to *common.Address, value *big.Int, before bool, purpose string) + CaptureArbitrumTransferHook = func(from, to *common.Address, value *big.Int, before bool, reason BalanceChangeReason) CaptureArbitrumStorageGetHook = func(key common.Hash, depth int, before bool) CaptureArbitrumStorageSetHook = func(key, value common.Hash, depth int, before bool) @@ -260,6 +260,69 @@ const ( BalanceDecreaseSelfdestructBurn BalanceChangeReason = 14 ) +// Arbitrum specific +const ( + BalanceChangeDuringEVMExecution BalanceChangeReason = 128 + iota + BalanceIncreaseDeposit + BalanceDecreaseWithdrawToL1 + BalanceIncreaseL1PosterFee + BalanceIncreaseInfraFee + BalanceIncreaseNetworkFee + BalanceChangeTransferInfraRefund + BalanceChangeTransferNetworkRefund + BalanceIncreasePrepaid + BalanceDecreaseUndoRefund + BalanceChangeEscrowTransfer + BalanceChangeTransferBatchposterReward + BalanceChangeTransferBatchposterRefund + // Stylus + BalanceChangeTransferActivationFee + BalanceChangeTransferActivationReimburse +) + +func (b BalanceChangeReason) String() string { + switch b { + case BalanceIncreaseRewardTransactionFee: + return "tip" + case BalanceDecreaseGasBuy: + return "feePayment" + case BalanceIncreaseGasReturn: + return "gasRefund" + case BalanceChangeTransfer: + return "transfer via a call" + case BalanceDecreaseSelfdestruct: + return "selfDestruct" + case BalanceChangeDuringEVMExecution: + return "during evm execution" + case BalanceIncreaseDeposit: + return "deposit" + case BalanceDecreaseWithdrawToL1: + return "withdraw" + case BalanceIncreaseL1PosterFee, BalanceIncreaseInfraFee, BalanceIncreaseNetworkFee: + return "feeCollection" + case BalanceIncreasePrepaid: + return "prepaid" + case BalanceDecreaseUndoRefund: + return "undoRefund" + case BalanceChangeEscrowTransfer: + return "escrow" + case BalanceChangeTransferInfraRefund, BalanceChangeTransferNetworkRefund: + return "refund" + // Batchposter + case BalanceChangeTransferBatchposterReward: + return "batchPosterReward" + case BalanceChangeTransferBatchposterRefund: + return "batchPosterRefund" + // Stylus + case BalanceChangeTransferActivationFee: + return "activate" + case BalanceChangeTransferActivationReimburse: + return "reimburse" + default: + return "unspecified" + } +} + // GasChangeReason is used to indicate the reason for a gas change, useful // for tracing and reporting. // diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 8a0765c27e..fab4ac5e78 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -230,6 +230,7 @@ func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (*trace OnExit: t.OnExit, OnOpcode: t.OnOpcode, OnFault: t.OnFault, + OnBalanceChange: t.OnBalanceChange, CaptureArbitrumTransfer: t.CaptureArbitrumTransfer, CaptureStylusHostio: t.CaptureStylusHostio, }, diff --git a/eth/tracers/js/tracer_arbitrum.go b/eth/tracers/js/tracer_arbitrum.go index db59809ac6..8d0a70e848 100644 --- a/eth/tracers/js/tracer_arbitrum.go +++ b/eth/tracers/js/tracer_arbitrum.go @@ -21,10 +21,11 @@ import ( "github.com/dop251/goja" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" ) func (jst *jsTracer) CaptureArbitrumTransfer( - from, to *common.Address, value *big.Int, before bool, purpose string, + from, to *common.Address, value *big.Int, before bool, reason tracing.BalanceChangeReason, ) { traceTransfer, ok := goja.AssertFunction(jst.obj.Get("captureArbitrumTransfer")) if !ok { @@ -45,7 +46,7 @@ func (jst *jsTracer) CaptureArbitrumTransfer( transfer.Set("value", value) transfer.Set("before", before) - transfer.Set("purpose", purpose) + transfer.Set("purpose", reason.String()) if _, err := traceTransfer(transfer); err != nil { jst.err = wrapError("captureArbitrumTransfer", err) @@ -69,3 +70,20 @@ func (jst *jsTracer) CaptureStylusHostio(name string, args, outs []byte, startIn jst.err = wrapError("hostio", err) } } + +func (jst *jsTracer) OnBalanceChange(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { + traceBalanceChange, ok := goja.AssertFunction(jst.obj.Get("onBalanceChange")) + if !ok { + return + } + + balanceChange := jst.vm.NewObject() + balanceChange.Set("addr", addr.String()) + balanceChange.Set("prev", prev) + balanceChange.Set("new", new) + balanceChange.Set("reason", reason.String()) + + if _, err := traceBalanceChange(jst.obj, balanceChange); err != nil { + jst.err = wrapError("onBalanceChange", err) + } +} diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 2a3a7dcdd0..4a66d05be7 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -193,10 +193,10 @@ func (t *muxTracer) CaptureArbitrumStorageSet(key, value common.Hash, depth int, } } -func (t *muxTracer) CaptureArbitrumTransfer(from, to *common.Address, value *big.Int, before bool, purpose string) { +func (t *muxTracer) CaptureArbitrumTransfer(from, to *common.Address, value *big.Int, before bool, reason tracing.BalanceChangeReason) { for _, t := range t.tracers { if t.CaptureArbitrumTransfer != nil { - t.CaptureArbitrumTransfer(from, to, value, before, purpose) + t.CaptureArbitrumTransfer(from, to, value, before, reason) } } } diff --git a/eth/tracers/native/tracer_arbitrum.go b/eth/tracers/native/tracer_arbitrum.go index 5134b5f099..a858dfe732 100644 --- a/eth/tracers/native/tracer_arbitrum.go +++ b/eth/tracers/native/tracer_arbitrum.go @@ -20,6 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" ) type arbitrumTransfer struct { @@ -29,11 +30,9 @@ type arbitrumTransfer struct { Value string `json:"value"` } -func (t *callTracer) CaptureArbitrumTransfer( - from, to *common.Address, value *big.Int, before bool, purpose string, -) { +func (t *callTracer) CaptureArbitrumTransfer(from, to *common.Address, value *big.Int, before bool, reason tracing.BalanceChangeReason) { transfer := arbitrumTransfer{ - Purpose: purpose, + Purpose: reason.String(), Value: bigToHex(value), } if from != nil { @@ -51,12 +50,12 @@ func (t *callTracer) CaptureArbitrumTransfer( } } -func (t *flatCallTracer) CaptureArbitrumTransfer(from, to *common.Address, value *big.Int, before bool, purpose string) { +func (t *flatCallTracer) CaptureArbitrumTransfer(from, to *common.Address, value *big.Int, before bool, reason tracing.BalanceChangeReason) { if t.interrupt.Load() { return } transfer := arbitrumTransfer{ - Purpose: purpose, + Purpose: reason.String(), Value: bigToHex(value), } if from != nil {