diff --git a/arbnode/sequencer_inbox.go b/arbnode/sequencer_inbox.go index 46e1edb78b..73e52ded53 100644 --- a/arbnode/sequencer_inbox.go +++ b/arbnode/sequencer_inbox.go @@ -232,7 +232,7 @@ func (i *SequencerInbox) LookupBatchesInRange(ctx context.Context, from, to *big seqNum := parsedLog.BatchSequenceNumber.Uint64() if lastSeqNum != nil { if seqNum != *lastSeqNum+1 { - return nil, fmt.Errorf("sequencer batches out of order; after batch %v got batch %v", lastSeqNum, seqNum) + return nil, fmt.Errorf("sequencer batches out of order; after batch %v got batch %v", *lastSeqNum, seqNum) } } lastSeqNum = &seqNum diff --git a/arbos/programs/api.go b/arbos/programs/api.go index 65a58a47c2..0519cd9f01 100644 --- a/arbos/programs/api.go +++ b/arbos/programs/api.go @@ -137,16 +137,31 @@ func newApiClosures( startGas := am.SaturatingUSub(gasLeft, baseCost) * 63 / 64 gas := am.MinInt(startGas, gasReq) - // Tracing: emit the call (value transfer is done later in evm.Call) - if tracingInfo != nil { - tracingInfo.Tracer.CaptureState(0, opcode, startGas, baseCost+gas, scope, []byte{}, depth, nil) - } - // EVM rule: calls that pay get a stipend (opCall) if value.Sign() != 0 { gas = am.SaturatingUAdd(gas, params.CallStipend) } + // Tracing: emit the call (value transfer is done later in evm.Call) + if tracingInfo != nil { + var args []uint256.Int + args = append(args, *uint256.NewInt(gas)) // gas + args = append(args, *uint256.NewInt(0).SetBytes(contract.Bytes())) // to address + if opcode == vm.CALL { + args = append(args, *uint256.NewInt(0).SetBytes(value.Bytes())) // call value + } + args = append(args, *uint256.NewInt(0)) // memory offset + args = append(args, *uint256.NewInt(uint64(len(input)))) // memory length + args = append(args, *uint256.NewInt(0)) // return offset + args = append(args, *uint256.NewInt(0)) // return size + s := &vm.ScopeContext{ + Memory: util.TracingMemoryFromBytes(input), + Stack: util.TracingStackFromArgs(args...), + Contract: scope.Contract, + } + tracingInfo.Tracer.CaptureState(0, opcode, startGas, baseCost+gas, s, []byte{}, depth, nil) + } + var ret []byte var returnGas uint64 diff --git a/arbos/util/tracing.go b/arbos/util/tracing.go index f0f101bc20..f3564143c5 100644 --- a/arbos/util/tracing.go +++ b/arbos/util/tracing.go @@ -56,11 +56,8 @@ func (info *TracingInfo) RecordEmitLog(topics []common.Hash, data []byte) { for _, topic := range topics { args = append(args, HashToUint256(topic)) // topic: 32-byte value. Max topics count is 4 } - memory := vm.NewMemory() - memory.Resize(size) - memory.Set(0, size, data) scope := &vm.ScopeContext{ - Memory: memory, + Memory: TracingMemoryFromBytes(data), Stack: TracingStackFromArgs(args...), Contract: info.Contract, } diff --git a/system_tests/retryable_test.go b/system_tests/retryable_test.go index 1abf9f2162..268d59ac98 100644 --- a/system_tests/retryable_test.go +++ b/system_tests/retryable_test.go @@ -131,6 +131,38 @@ func TestRetryableNoExist(t *testing.T) { } } +func TestEstimateRetryableTicketWithNoFundsAndZeroGasPrice(t *testing.T) { + t.Parallel() + builder, _, _, ctx, teardown := retryableSetup(t) + defer teardown() + + user2Address := builder.L2Info.GetAddress("User2") + beneficiaryAddress := builder.L2Info.GetAddress("Beneficiary") + + deposit := arbmath.BigMul(big.NewInt(1e12), big.NewInt(1e12)) + callValue := big.NewInt(1e6) + + nodeInterface, err := node_interfacegen.NewNodeInterface(types.NodeInterfaceAddress, builder.L2.Client) + Require(t, err, "failed to deploy NodeInterface") + + builder.L2Info.GenerateAccount("zerofunds") + usertxoptsL2 := builder.L2Info.GetDefaultTransactOpts("zerofunds", ctx) + usertxoptsL2.NoSend = true + usertxoptsL2.GasMargin = 0 + usertxoptsL2.GasPrice = big.NewInt(0) + _, err = nodeInterface.EstimateRetryableTicket( + &usertxoptsL2, + usertxoptsL2.From, + deposit, + user2Address, + callValue, + beneficiaryAddress, + beneficiaryAddress, + []byte{}, + ) + Require(t, err, "failed to estimate retryable submission") +} + func TestSubmitRetryableImmediateSuccess(t *testing.T) { t.Parallel() builder, delayedInbox, lookupL2Tx, ctx, teardown := retryableSetup(t)