Skip to content

Commit

Permalink
Test: decode tx from TxCall
Browse files Browse the repository at this point in the history
  • Loading branch information
dajuguan committed Sep 30, 2024
1 parent 15e66c1 commit 740c568
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 43 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/ethereum-optimism/optimism

go 1.21
go 1.21.13

require (
github.com/BurntSushi/toml v1.3.2
Expand Down
32 changes: 21 additions & 11 deletions op-challenger/game/fault/contracts/faultdisputegame.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ var (
methodL2BlockNumberChallenged = "l2BlockNumberChallenged"
methodL2BlockNumberChallenger = "l2BlockNumberChallenger"
methodChallengeRootL2Block = "challengeRootL2Block"
subClaimField = "_claim"
)

var (
Expand Down Expand Up @@ -174,10 +175,6 @@ func (f *FaultDisputeGameContractLatest) GetBlockRange(ctx context.Context) (pre
return
}

func (f *FaultDisputeGameContractLatest) GetContract() *batching.BoundContract {
return f.contract
}

type GameMetadata struct {
L1Head common.Hash
L2BlockNum uint64
Expand Down Expand Up @@ -450,7 +447,6 @@ func (f *FaultDisputeGameContractLatest) GetAllClaims(ctx context.Context, block
func (f *FaultDisputeGameContractLatest) GetSubClaims(ctx context.Context, block rpcblock.Block, aggClaim *types.Claim) ([]common.Hash, error) {
defer f.metrics.StartContractRequest("GetAllSubClaims")()

// findMoveTransaction
filter, err := bindings.NewFaultDisputeGameFilterer(f.contract.Addr(), f.multiCaller)
if err != nil {
return nil, err
Expand All @@ -469,16 +465,30 @@ func (f *FaultDisputeGameContractLatest) GetSubClaims(ctx context.Context, block
}
txHash := moveIter.Event.Raw.TxHash

// todo: replace hardcoded nary, method name
nary := 1
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, batching.NewTxCall(f.contract.Abi(), txHash, "move"))
// todo: replace hardcoded method name
txCall := batching.NewTxCall(f.contract.Abi(), txHash, "move")
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, txCall)
if err != nil {
return nil, fmt.Errorf("failed to load claim calldata: %w", err)
}

txn, err := txCall.DecodeToTx(result)
if err != nil {
return nil, fmt.Errorf("failed to decode tx: %w", err)
}

var subClaims []common.Hash
// We should start from 2 du to the signature of move(Claim _disputed, uint256 _challengeIndex, Claim _claim)
for i := 2; i < nary+2; i++ {
subClaims = append(subClaims, result.GetHash(i))

if len(txn.BlobHashes()) > 0 {
// todo: fetch Blobs and unpack it into subClaims
} else {
inputMap, err := txCall.UnpackCallData(txn)
if err != nil {
return nil, fmt.Errorf("failed to unpack tx resp: %w", err)
}
// todo: replace claim with nary-subclaims
claim := *abi.ConvertType(inputMap[subClaimField], new([32]byte)).(*[32]byte)
subClaims = append(subClaims, claim)
}

return subClaims, nil
Expand Down
19 changes: 16 additions & 3 deletions op-challenger/game/fault/contracts/faultdisputegame_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ func TestGetAllClaims(t *testing.T) {

func TestGetSubClaims(t *testing.T) {
for _, version := range versions {
// todo: backward and forward support
if version.Is("1.2.0") {
version := version
t.Run(version.version, func(t *testing.T) {
Expand All @@ -344,7 +345,7 @@ func TestGetSubClaims(t *testing.T) {
block := rpcblock.ByNumber(42)
stubRpc.SetResponse(fdgAddr, methodClaimCount, block, nil, []interface{}{big.NewInt(int64(len(expectedClaims)))})

name := "Move"
eventName := "Move"
fdgAbi := version.loadAbi()

var challgenIndex []interface{}
Expand All @@ -354,7 +355,7 @@ func TestGetSubClaims(t *testing.T) {
query := [][]interface{}{challgenIndex, claim, address}
txHash := common.Hash{0xff}

query = append([][]interface{}{{fdgAbi.Events[name].ID}}, query...)
query = append([][]interface{}{{fdgAbi.Events[eventName].ID}}, query...)

topics, err := abi.MakeTopics(query...)
var queryTopics []common.Hash
Expand All @@ -373,7 +374,19 @@ func TestGetSubClaims(t *testing.T) {
stubRpc.SetFilterLogResponse(topics, fdgAddr, block, out)

contractCall := batching.NewContractCall(fdgAbi, fdgAddr, "move", claim0.ClaimData.Value, challgenIndex[0], claim0.ClaimData.Value, true)
packed, err := contractCall.Pack()
inputData, err := contractCall.Pack()
require.NoError(t, err)

tx := coreTypes.NewTx(&coreTypes.LegacyTx{
Nonce: 0,
GasPrice: big.NewInt(11111),
Gas: 1111,
To: &claim0.Claimant,
Value: big.NewInt(111),
Data: inputData,
})
require.NoError(t, err)
packed, err := tx.MarshalBinary()
require.NoError(t, err)
stubRpc.SetTxResponse(txHash, packed)

Expand Down
2 changes: 0 additions & 2 deletions op-service/sources/batching/event_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ type EventCall struct {
to []common.Address
}

var _ Call = (*EventCall)(nil)

func NewEventCall(q ethereum.FilterQuery) *EventCall {
return &EventCall{
topics: q.Topics,
Expand Down
4 changes: 2 additions & 2 deletions op-service/sources/batching/multicall.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ func (m *MultiCaller) Call(ctx context.Context, block rpcblock.Block, calls ...C
return callResults, nil
}

// FilterLogs filters contract logs for past blocks, returning the necessary
// channels to construct a strongly typed bound iterator on top of them.
// implment LogFilterer interface
func (m *MultiCaller) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) {
call := NewEventCall(q)
results, err := m.SingleCall(ctx, rpcblock.ByNumber(q.FromBlock.Uint64()), call)
Expand All @@ -97,6 +96,7 @@ func (m *MultiCaller) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([
return out, nil
}

// implment LogFilterer interface
func (m *MultiCaller) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
return nil, errors.New("unimplemented")
}
4 changes: 2 additions & 2 deletions op-service/sources/batching/test/event_stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ func (c *expectedFilterLogsCall) Matches(rpcMethod string, args ...interface{})

to := args[1].(common.Address)
if to != c.to {
return fmt.Errorf("expected contract address %v but was %v", c.topics, topics)
return fmt.Errorf("expected contract address %v but was %v", c.to, to)
}
return c.err
}

func (c *expectedFilterLogsCall) Execute(t *testing.T, out interface{}) error {
j, err := json.Marshal((c.outputs))
j, err := json.Marshal(c.outputs)
require.NoError(t, err)
json.Unmarshal(j, out)
return c.err
Expand Down
26 changes: 14 additions & 12 deletions op-service/sources/batching/tx_call.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package batching

import (
"fmt"

"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rpc"
)

Expand All @@ -16,8 +15,6 @@ type TxCall struct {
Method string
}

var _ Call = (*TxCall)(nil)

func NewTxCall(abi *abi.ABI, txhash common.Hash, method string) *TxCall {
return &TxCall{
Abi: abi,
Expand All @@ -38,8 +35,8 @@ func (b *TxCall) ToBatchElemCreator() (BatchElementCreator, error) {
}

func (c *TxCall) HandleResult(result interface{}) (*CallResult, error) {
out, err := c.Unpack(*result.(*hexutil.Bytes))
return out, err
res := result.(*hexutil.Bytes)
return &CallResult{out: []interface{}{*res}}, nil
}

func (c *TxCall) DecodeTxParams(data []byte) (map[string]interface{}, error) {
Expand All @@ -54,12 +51,17 @@ func (c *TxCall) DecodeTxParams(data []byte) (map[string]interface{}, error) {
return v, nil
}

func (c *TxCall) Unpack(hex hexutil.Bytes) (*CallResult, error) {
inputs := c.Abi.Methods[c.Method].Inputs

out, err := inputs.UnpackValues(hex[4:])
func (c *TxCall) DecodeToTx(res *CallResult) (*types.Transaction, error) {
txn := new(types.Transaction)
hex := res.out[0].(hexutil.Bytes)
err := txn.UnmarshalBinary(hex)
if err != nil {
return nil, fmt.Errorf("failed to unpack inputs: %w", err)
return nil, err
}
return &CallResult{out: out}, nil
return txn, nil
}

func (c *TxCall) UnpackCallData(txn *types.Transaction) (map[string]interface{}, error) {
input := txn.Data()
return c.DecodeTxParams(input)
}
31 changes: 21 additions & 10 deletions op-service/sources/batching/tx_call_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import (
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/test"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"
)

func TestTxCall_ToCallArgs(t *testing.T) {
func TestDecodeTxCall(t *testing.T) {
addr := common.Address{0xbd}
testAbi, err := test.ERC20MetaData.GetAbi()
require.NoError(t, err)
Expand All @@ -26,14 +27,9 @@ func TestTxCall_ToCallArgs(t *testing.T) {
require.NoError(t, err)
require.Equal(t, expectedAmount, unpackedMap["amount"])
require.Equal(t, expectedSpender, unpackedMap["spender"])

unpacked, err := call.Unpack(packed)
require.NoError(t, err)
require.Equal(t, expectedSpender, unpacked.GetAddress(0))
require.Equal(t, expectedAmount, unpacked.GetBigInt(1))
}

func TestGetTxCalldata(t *testing.T) {
func TestUnpackTxCalldata(t *testing.T) {
expectedSpender := common.Address{0xcc}
expectedAmount := big.NewInt(1234444)
txHash := common.Hash{0x11}
Expand All @@ -42,7 +38,17 @@ func TestGetTxCalldata(t *testing.T) {
testAbi, err := test.ERC20MetaData.GetAbi()
require.NoError(t, err)
contractCall := NewContractCall(testAbi, addr, "approve", expectedSpender, expectedAmount)
packed, err := contractCall.Pack()
inputData, err := contractCall.Pack()
tx := types.NewTx(&types.LegacyTx{
Nonce: 0,
GasPrice: big.NewInt(11111),
Gas: 1111,
To: &addr,
Value: big.NewInt(111),
Data: inputData,
})
require.NoError(t, err)
packed, err := tx.MarshalBinary()
require.NoError(t, err)

stub := test.NewRpcStub(t)
Expand All @@ -52,6 +58,11 @@ func TestGetTxCalldata(t *testing.T) {
txCall := NewTxCall(testAbi, txHash, "approve")
result, err := caller.SingleCall(context.Background(), rpcblock.Latest, txCall)
require.NoError(t, err)
require.Equal(t, expectedSpender, result.GetAddress(0))
require.Equal(t, expectedAmount, result.GetBigInt(1))

decodedTx, err := txCall.DecodeToTx(result)
require.NoError(t, err)
unpackedMap, err := txCall.UnpackCallData(decodedTx)
require.NoError(t, err)
require.Equal(t, expectedSpender, unpackedMap["spender"])
require.Equal(t, expectedAmount, unpackedMap["amount"])
}

0 comments on commit 740c568

Please sign in to comment.