Commit c163159b authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into inphi/link-lint

parents 6b283d35 55f41591
......@@ -35,3 +35,11 @@
/infra @ethereum-optimism/infra-reviewers
/specs @ethereum-optimism/contract-reviewers @ethereum-optimism/go-reviewers
/endpoint-monitor @ethereum-optimism/infra-reviewers
# Don't add owners if only package.json is updated
/packages/*/package.json
/*/package.json
# JavaScript Releases
/packages/*/CHANGELOG.md @ethereum-optimism/release-managers
/*/CHANGELOG.md @ethereum-optimism/release-managers
......@@ -7,6 +7,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
......@@ -77,6 +78,20 @@ func (r *faultResponder) BuildTx(ctx context.Context, response Claim) ([]byte, e
}
}
// CanResolve determines if the resolve function on the fault dispute game contract
// would succeed. Returns true if the game can be resolved, otherwise false.
func (r *faultResponder) CanResolve(ctx context.Context) bool {
txData, err := r.buildResolveData()
if err != nil {
return false
}
_, err = r.txMgr.Call(ctx, ethereum.CallMsg{
To: &r.fdgAddr,
Data: txData,
}, nil)
return err == nil
}
// Resolve executes a resolve transaction to resolve a fault dispute game.
func (r *faultResponder) Resolve(ctx context.Context) error {
txData, err := r.buildResolveData()
......
......@@ -10,6 +10,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
......@@ -25,6 +26,7 @@ var (
type mockTxManager struct {
from common.Address
sends int
calls int
sendFails bool
}
......@@ -40,6 +42,14 @@ func (m *mockTxManager) Send(ctx context.Context, candidate txmgr.TxCandidate) (
), nil
}
func (m *mockTxManager) Call(_ context.Context, _ ethereum.CallMsg, _ *big.Int) ([]byte, error) {
if m.sendFails {
return nil, mockSendError
}
m.calls++
return []byte{}, nil
}
func (m *mockTxManager) BlockNumber(ctx context.Context) (uint64, error) {
panic("not implemented")
}
......@@ -57,6 +67,24 @@ func newTestFaultResponder(t *testing.T, sendFails bool) (*faultResponder, *mock
return responder, mockTxMgr
}
// TestResponder_CanResolve_CallFails tests the [Responder.CanResolve] method
// bubbles up the error returned by the [txmgr.Call] method.
func TestResponder_CanResolve_CallFails(t *testing.T) {
responder, mockTxMgr := newTestFaultResponder(t, true)
resolved := responder.CanResolve(context.Background())
require.False(t, resolved)
require.Equal(t, 0, mockTxMgr.sends)
}
// TestResponder_CanResolve_Success tests the [Responder.CanResolve] method
// succeeds when the call message is successfully sent through the txmgr.
func TestResponder_CanResolve_Success(t *testing.T) {
responder, mockTxMgr := newTestFaultResponder(t, false)
resolved := responder.CanResolve(context.Background())
require.True(t, resolved)
require.Equal(t, 1, mockTxMgr.calls)
}
// TestResponder_Resolve_SendFails tests the [Responder.Resolve] method
// bubbles up the error returned by the [txmgr.Send] method.
func TestResponder_Resolve_SendFails(t *testing.T) {
......
......@@ -44,6 +44,9 @@ type fakeTxMgr struct {
func (f fakeTxMgr) From() common.Address {
return f.from
}
func (f fakeTxMgr) Call(_ context.Context, _ ethereum.CallMsg, _ *big.Int) ([]byte, error) {
panic("unimplemented")
}
func (f fakeTxMgr) BlockNumber(_ context.Context) (uint64, error) {
panic("unimplemented")
}
......
......@@ -4,9 +4,12 @@ package mocks
import (
context "context"
big "math/big"
common "github.com/ethereum/go-ethereum/common"
ethereum "github.com/ethereum/go-ethereum"
mock "github.com/stretchr/testify/mock"
txmgr "github.com/ethereum-optimism/optimism/op-service/txmgr"
......@@ -43,6 +46,32 @@ func (_m *TxManager) BlockNumber(ctx context.Context) (uint64, error) {
return r0, r1
}
// Call provides a mock function with given fields: ctx, msg, blockNumber
func (_m *TxManager) Call(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
ret := _m.Called(ctx, msg, blockNumber)
var r0 []byte
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error)); ok {
return rf(ctx, msg, blockNumber)
}
if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) []byte); ok {
r0 = rf(ctx, msg, blockNumber)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
}
}
if rf, ok := ret.Get(1).(func(context.Context, ethereum.CallMsg, *big.Int) error); ok {
r1 = rf(ctx, msg, blockNumber)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// From provides a mock function with given fields:
func (_m *TxManager) From() common.Address {
ret := _m.Called()
......
......@@ -45,6 +45,10 @@ type TxManager interface {
// NOTE: Send can be called concurrently, the nonce will be managed internally.
Send(ctx context.Context, candidate TxCandidate) (*types.Receipt, error)
// Call is used to call a contract.
// Internally, it uses the [ethclient.Client.CallContract] method.
Call(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)
// From returns the sending address associated with the instance of the transaction manager.
// It is static for a single instance of a TxManager.
From() common.Address
......@@ -59,6 +63,9 @@ type ETHBackend interface {
// BlockNumber returns the most recent block number.
BlockNumber(ctx context.Context) (uint64, error)
// CallContract executes an eth_call against the provided contract.
CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)
// TransactionReceipt queries the backend for a receipt associated with
// txHash. If lookup does not fail, but the transaction is not found,
// nil should be returned for both values.
......@@ -155,6 +162,12 @@ func (m *SimpleTxManager) Send(ctx context.Context, candidate TxCandidate) (*typ
return receipt, err
}
// Call is used to call a contract.
// Internally, it uses the [ethclient.Client.CallContract] method.
func (m *SimpleTxManager) Call(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
return m.backend.CallContract(ctx, msg, blockNumber)
}
// send performs the actual transaction creation and sending.
func (m *SimpleTxManager) send(ctx context.Context, candidate TxCandidate) (*types.Receipt, error) {
if m.cfg.TxSendTimeout != 0 {
......
......@@ -194,6 +194,11 @@ func (b *mockBackend) BlockNumber(ctx context.Context) (uint64, error) {
return b.blockHeight, nil
}
// Call mocks a call to the EVM.
func (b *mockBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
return nil, nil
}
func (b *mockBackend) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
return &types.Header{
BaseFee: b.g.basefee(),
......@@ -649,6 +654,10 @@ func (b *failingBackend) HeaderByNumber(_ context.Context, _ *big.Int) (*types.H
}, nil
}
func (b *failingBackend) CallContract(_ context.Context, _ ethereum.CallMsg, _ *big.Int) ([]byte, error) {
return nil, errors.New("unimplemented")
}
func (b *failingBackend) SendTransaction(_ context.Context, _ *types.Transaction) error {
return errors.New("unimplemented")
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment