Skip to content

Commit

Permalink
Merge pull request #2452 from OffchainLabs/add-logopcodes-stylustrace
Browse files Browse the repository at this point in the history
Add LOG opcodes to Stylus tracing
  • Loading branch information
tsahee authored Jul 9, 2024
2 parents 81aa1b8 + 8e7e54c commit 747ecc5
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 12 deletions.
3 changes: 3 additions & 0 deletions arbos/programs/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ func newApiClosures(
return addr, res, cost, nil
}
emitLog := func(topics []common.Hash, data []byte) error {
if tracingInfo != nil {
tracingInfo.RecordEmitLog(topics, data)
}
if readOnly {
return vm.ErrWriteProtection
}
Expand Down
21 changes: 21 additions & 0 deletions arbos/util/tracing.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package util

import (
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -47,6 +48,26 @@ func NewTracingInfo(evm *vm.EVM, from, to common.Address, scenario TracingScenar
}
}

func (info *TracingInfo) RecordEmitLog(topics []common.Hash, data []byte) {
size := uint64(len(data))
var args []uint256.Int
args = append(args, *uint256.NewInt(0)) // offset: byte offset in the memory in bytes
args = append(args, *uint256.NewInt(size)) // size: byte size to copy (length of data)
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,
Stack: TracingStackFromArgs(args...),
Contract: info.Contract,
}
logType := fmt.Sprintf("LOG%d", len(topics))
info.Tracer.CaptureState(0, vm.StringToOp(logType), 0, 0, scope, []byte{}, info.Depth, nil)
}

func (info *TracingInfo) RecordStorageGet(key common.Hash) {
tracer := info.Tracer
if info.Scenario == TracingDuringEVM {
Expand Down
61 changes: 50 additions & 11 deletions system_tests/program_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
Expand Down Expand Up @@ -739,10 +740,15 @@ func testReturnData(t *testing.T, jit bool) {

func TestProgramLogs(t *testing.T) {
t.Parallel()
testLogs(t, true)
testLogs(t, true, false)
}

func testLogs(t *testing.T, jit bool) {
func TestProgramLogsWithTracing(t *testing.T) {
t.Parallel()
testLogs(t, true, true)
}

func testLogs(t *testing.T, jit, tracing bool) {
builder, auth, cleanup := setupProgramTest(t, jit)
ctx := builder.ctx
l2info := builder.L2Info
Expand All @@ -751,6 +757,27 @@ func testLogs(t *testing.T, jit bool) {
logAddr := deployWasm(t, ctx, auth, l2client, rustFile("log"))
multiAddr := deployWasm(t, ctx, auth, l2client, rustFile("multicall"))

type traceLog struct {
Address common.Address `json:"address"`
Topics []common.Hash `json:"topics"`
Data hexutil.Bytes `json:"data"`
}
traceTx := func(tx *types.Transaction) []traceLog {
type traceLogs struct {
Logs []traceLog `json:"logs"`
}
var trace traceLogs
traceConfig := map[string]interface{}{
"tracer": "callTracer",
"tracerConfig": map[string]interface{}{
"withLog": true,
},
}
rpc := l2client.Client()
err := rpc.CallContext(ctx, &trace, "debug_traceTransaction", tx.Hash(), traceConfig)
Require(t, err)
return trace.Logs
}
ensure := func(tx *types.Transaction, err error) *types.Receipt {
t.Helper()
Require(t, err)
Expand All @@ -777,6 +804,20 @@ func testLogs(t *testing.T, jit bool) {
topics[j] = testhelpers.RandomHash()
}
data := randBytes(0, 48)
verifyLogTopicsAndData := func(logData []byte, logTopics []common.Hash) {
if !bytes.Equal(logData, data) {
Fatal(t, "data mismatch", logData, data)
}
if len(logTopics) != len(topics) {
Fatal(t, "topics mismatch", len(logTopics), len(topics))
}
for j := 0; j < i; j++ {
if logTopics[j] != topics[j] {
Fatal(t, "topic mismatch", logTopics, topics)
}
}
}

args := encode(topics, data)
tx := l2info.PrepareTxTo("Owner", &logAddr, 1e9, nil, args)
receipt := ensure(tx, l2client.SendTransaction(ctx, tx))
Expand All @@ -785,16 +826,14 @@ func testLogs(t *testing.T, jit bool) {
Fatal(t, "wrong number of logs", len(receipt.Logs))
}
log := receipt.Logs[0]
if !bytes.Equal(log.Data, data) {
Fatal(t, "data mismatch", log.Data, data)
}
if len(log.Topics) != len(topics) {
Fatal(t, "topics mismatch", len(log.Topics), len(topics))
}
for j := 0; j < i; j++ {
if log.Topics[j] != topics[j] {
Fatal(t, "topic mismatch", log.Topics, topics)
verifyLogTopicsAndData(log.Data, log.Topics)
if tracing {
logs := traceTx(tx)
if len(logs) != 1 {
Fatal(t, "wrong number of logs in trace", len(logs))
}
log := logs[0]
verifyLogTopicsAndData(log.Data, log.Topics)
}
}

Expand Down
2 changes: 1 addition & 1 deletion system_tests/stylus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestProgramArbitratorReturnData(t *testing.T) {
}

func TestProgramArbitratorLogs(t *testing.T) {
testLogs(t, false)
testLogs(t, false, false)
}

func TestProgramArbitratorCreate(t *testing.T) {
Expand Down

0 comments on commit 747ecc5

Please sign in to comment.