Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(op-challenger): add EventCall, TxCall and GetSubClaims #63

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion op-challenger/game/fault/contracts/delayed_weth.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func NewDelayedWETHContract(metrics metrics.ContractMetricer, addr common.Addres
return &DelayedWETHContract{
metrics: metrics,
multiCaller: caller,
contract: batching.NewBoundContract(contractAbi, addr),
contract: batching.NewBoundContract(contractAbi, addr, caller),
}
}

Expand Down
61 changes: 57 additions & 4 deletions op-challenger/game/fault/contracts/faultdisputegame.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
Expand Down Expand Up @@ -54,6 +55,7 @@ var (
methodL2BlockNumberChallenged = "l2BlockNumberChallenged"
methodL2BlockNumberChallenger = "l2BlockNumberChallenger"
methodChallengeRootL2Block = "challengeRootL2Block"
subClaimField = "_claim"
)

var (
Expand Down Expand Up @@ -96,7 +98,7 @@ func NewFaultDisputeGameContract(ctx context.Context, metrics metrics.ContractMe
FaultDisputeGameContractLatest: FaultDisputeGameContractLatest{
metrics: metrics,
multiCaller: caller,
contract: batching.NewBoundContract(legacyAbi, addr),
contract: batching.NewBoundContract(legacyAbi, addr, caller),
},
}, nil
} else if strings.HasPrefix(version, "0.18.") || strings.HasPrefix(version, "1.0.") {
Expand All @@ -106,7 +108,7 @@ func NewFaultDisputeGameContract(ctx context.Context, metrics metrics.ContractMe
FaultDisputeGameContractLatest: FaultDisputeGameContractLatest{
metrics: metrics,
multiCaller: caller,
contract: batching.NewBoundContract(legacyAbi, addr),
contract: batching.NewBoundContract(legacyAbi, addr, caller),
},
}, nil
} else if strings.HasPrefix(version, "1.1.") {
Expand All @@ -116,14 +118,14 @@ func NewFaultDisputeGameContract(ctx context.Context, metrics metrics.ContractMe
FaultDisputeGameContractLatest: FaultDisputeGameContractLatest{
metrics: metrics,
multiCaller: caller,
contract: batching.NewBoundContract(legacyAbi, addr),
contract: batching.NewBoundContract(legacyAbi, addr, caller),
},
}, nil
} else {
return &FaultDisputeGameContractLatest{
metrics: metrics,
multiCaller: caller,
contract: batching.NewBoundContract(contractAbi, addr),
contract: batching.NewBoundContract(contractAbi, addr, caller),
}, nil
}
}
Expand Down Expand Up @@ -442,6 +444,56 @@ func (f *FaultDisputeGameContractLatest) GetAllClaims(ctx context.Context, block
return claims, nil
}

func (f *FaultDisputeGameContractLatest) GetSubClaims(ctx context.Context, block rpcblock.Block, aggClaim *types.Claim) ([]common.Hash, error) {
defer f.metrics.StartContractRequest("GetAllSubClaims")()

filter, err := bindings.NewFaultDisputeGameFilterer(f.contract.Addr(), f.multiCaller)
if err != nil {
return nil, err
}

parentIndex := [...]*big.Int{big.NewInt(int64(aggClaim.ParentContractIndex))}
claim := [...][32]byte{aggClaim.ClaimData.ValueBytes()}
claimant := [...]common.Address{aggClaim.Claimant}
moveIter, err := filter.FilterMove(nil, parentIndex[:], claim[:], claimant[:])
if err != nil {
return nil, fmt.Errorf("failed to filter move event log: %w", err)
}
ok := moveIter.Next()
if !ok {
return nil, fmt.Errorf("failed to get move event log: %w", moveIter.Error())
}
txHash := moveIter.Event.Raw.TxHash

// 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

if len(txn.BlobHashes()) > 0 {
// todo: fetch Blobs and unpack it into subClaims
dajuguan marked this conversation as resolved.
Show resolved Hide resolved
} 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
}

func (f *FaultDisputeGameContractLatest) IsResolved(ctx context.Context, block rpcblock.Block, claims ...types.Claim) ([]bool, error) {
defer f.metrics.StartContractRequest("IsResolved")()
calls := make([]batching.Call, 0, len(claims))
Expand Down Expand Up @@ -624,4 +676,5 @@ type FaultDisputeGameContract interface {
ResolveClaimTx(claimIdx uint64) (txmgr.TxCandidate, error)
CallResolve(ctx context.Context) (gameTypes.GameStatus, error)
ResolveTx() (txmgr.TxCandidate, error)
GetSubClaims(ctx context.Context, block rpcblock.Block, aggClaim *types.Claim) ([]common.Hash, error)
}
78 changes: 78 additions & 0 deletions op-challenger/game/fault/contracts/faultdisputegame_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
coreTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -321,6 +322,83 @@ 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) {
stubRpc, game := setupFaultDisputeGameTest(t, version)
claim0 := faultTypes.Claim{
ClaimData: faultTypes.ClaimData{
Value: common.Hash{0xaa},
Position: faultTypes.NewPositionFromGIndex(big.NewInt(1)),
Bond: big.NewInt(5),
},
CounteredBy: common.Address{0x01},
Claimant: common.Address{0x02},
Clock: decodeClock(big.NewInt(1234)),
ContractIndex: 0,
ParentContractIndex: math.MaxUint32,
}
expectedClaims := []faultTypes.Claim{claim0}
block := rpcblock.ByNumber(42)
stubRpc.SetResponse(fdgAddr, methodClaimCount, block, nil, []interface{}{big.NewInt(int64(len(expectedClaims)))})

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

var challgenIndex []interface{}
challgenIndex = append(challgenIndex, big.NewInt(int64(claim0.ParentContractIndex)))
claim := []interface{}{claim0.ClaimData.ValueBytes()}
address := []interface{}{claim0.Claimant}
query := [][]interface{}{challgenIndex, claim, address}
txHash := common.Hash{0xff}

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

topics, err := abi.MakeTopics(query...)
var queryTopics []common.Hash
for _, item := range topics {
queryTopics = append(queryTopics, item[0])
}
require.NoError(t, err)
out := []coreTypes.Log{
{
Address: fdgAddr,
Topics: queryTopics,
Data: []byte{},
TxHash: txHash,
},
}
stubRpc.SetFilterLogResponse(topics, fdgAddr, block, out)

contractCall := batching.NewContractCall(fdgAbi, fdgAddr, "move", claim0.ClaimData.Value, challgenIndex[0], claim0.ClaimData.Value, true)
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)
blockchaindevsh marked this conversation as resolved.
Show resolved Hide resolved
packed, err := tx.MarshalBinary()
require.NoError(t, err)
stubRpc.SetTxResponse(txHash, packed)

claims, err := game.GetSubClaims(context.Background(), block, &claim0)
require.NoError(t, err)
require.Equal(t, 1, len(claims))
require.Equal(t, claim0.ClaimData.Value, claims[0])
})
}
}
}

func TestGetBalance(t *testing.T) {
for _, version := range versions {
version := version
Expand Down
2 changes: 1 addition & 1 deletion op-challenger/game/fault/contracts/gamefactory.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func NewDisputeGameFactoryContract(m metrics.ContractMetricer, addr common.Addre
return &DisputeGameFactoryContract{
metrics: m,
multiCaller: caller,
contract: batching.NewBoundContract(factoryAbi, addr),
contract: batching.NewBoundContract(factoryAbi, addr, caller),
abi: factoryAbi,
}
}
Expand Down
2 changes: 1 addition & 1 deletion op-challenger/game/fault/contracts/oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func NewPreimageOracleContract(addr common.Address, caller *batching.MultiCaller
return &PreimageOracleContract{
addr: addr,
multiCaller: caller,
contract: batching.NewBoundContract(oracleAbi, addr),
contract: batching.NewBoundContract(oracleAbi, addr, caller),
}
}

Expand Down
2 changes: 1 addition & 1 deletion op-challenger/game/fault/contracts/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func NewVMContract(addr common.Address, caller *batching.MultiCaller) *VMContrac

return &VMContract{
multiCaller: caller,
contract: batching.NewBoundContract(mipsAbi, addr),
contract: batching.NewBoundContract(mipsAbi, addr, caller),
}
}

Expand Down
17 changes: 12 additions & 5 deletions op-service/sources/batching/bound.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
Expand All @@ -17,21 +18,27 @@ var (
)

type BoundContract struct {
abi *abi.ABI
addr common.Address
abi *abi.ABI
addr common.Address
filter bind.ContractFilterer
}

func NewBoundContract(abi *abi.ABI, addr common.Address) *BoundContract {
func NewBoundContract(abi *abi.ABI, addr common.Address, filter bind.ContractFilterer) *BoundContract {
return &BoundContract{
abi: abi,
addr: addr,
abi: abi,
addr: addr,
filter: filter,
dajuguan marked this conversation as resolved.
Show resolved Hide resolved
}
}

func (b *BoundContract) Addr() common.Address {
return b.addr
}

func (b *BoundContract) Abi() *abi.ABI {
return b.abi
}

func (b *BoundContract) Call(method string, args ...interface{}) *ContractCall {
return NewContractCall(b.abi, b.addr, method, args...)
}
Expand Down
4 changes: 2 additions & 2 deletions op-service/sources/batching/bound_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestDecodeCall(t *testing.T) {
validData, err := testAbi.Pack(method, spender, amount)
require.NoError(t, err)

contract := NewBoundContract(testAbi, common.Address{0xaa})
contract := NewBoundContract(testAbi, common.Address{0xaa}, nil)
t.Run("TooShort", func(t *testing.T) {
_, _, err := contract.DecodeCall([]byte{1, 2, 3})
require.ErrorIs(t, err, ErrUnknownMethod)
Expand Down Expand Up @@ -60,7 +60,7 @@ func TestDecodeEvent(t *testing.T) {
// event Transfer(address indexed from, address indexed to, uint256 amount);
event := testAbi.Events["Transfer"]

contract := NewBoundContract(testAbi, common.Address{0xaa})
contract := NewBoundContract(testAbi, common.Address{0xaa}, nil)
t.Run("NoTopics", func(t *testing.T) {
log := &types.Log{}
_, _, err := contract.DecodeEvent(log)
Expand Down
37 changes: 37 additions & 0 deletions op-service/sources/batching/event_call.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package batching

import (
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rpc"
)

type EventCall struct {
topics [][]common.Hash
to []common.Address
}

func NewEventCall(q ethereum.FilterQuery) *EventCall {
return &EventCall{
topics: q.Topics,
to: q.Addresses,
}
}

func (b *EventCall) ToBatchElemCreator() (BatchElementCreator, error) {
return func(block rpcblock.Block) (any, rpc.BatchElem) {
out := new([]types.Log)
return out, rpc.BatchElem{
Method: "eth_getFilterLogs",
Args: []interface{}{b.topics, b.to[0], block.ArgValue()},
Result: &out,
}
}, nil
}

func (c *EventCall) HandleResult(result interface{}) (*CallResult, error) {
res := result.(*[]types.Log)
return &CallResult{out: []interface{}{*res}}, nil
}
Loading