Skip to content

Commit

Permalink
Implement forwarder OCR2 fallback if fwd not present as a transmitter
Browse files Browse the repository at this point in the history
  • Loading branch information
ilija42 committed May 16, 2024
1 parent 6ee7c81 commit b392880
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 6 deletions.
15 changes: 15 additions & 0 deletions common/txmgr/txmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"sync"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/google/uuid"
nullv4 "gopkg.in/guregu/null.v4"

Expand Down Expand Up @@ -47,6 +48,7 @@ type TxManager[
Trigger(addr ADDR)
CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH]) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error)
GetForwarderForEOA(eoa ADDR) (forwarder ADDR, err error)
GetForwarderForEOAOCR2(eoa, ocr2AggregatorID ADDR) (forwarder ADDR, err error)
RegisterResumeCallback(fn ResumeCallback)
SendNativeToken(ctx context.Context, chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint64) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error)
Reset(addr ADDR, abandon bool) error
Expand Down Expand Up @@ -553,6 +555,15 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetForward
return
}

// GetForwarderForEOAOCR2 Calls forwarderMgr to get a proper forwarder for a given EOA and checs if its set as a transmitter on the OCR2Aggregator contract.
func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetForwarderForEOAOCR2(eoa, ocr2Aggregator ADDR) (forwarder ADDR, err error) {
if !b.txConfig.ForwardersEnabled() {
return forwarder, fmt.Errorf("forwarding is not enabled, to enable set Transactions.ForwardersEnabled =true")
}
forwarder, err = b.fwdMgr.ForwarderForOCR2(eoa, ocr2Aggregator)
return
}

func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) checkEnabled(ctx context.Context, addr ADDR) error {
if err := b.keyStore.CheckEnabled(ctx, addr, b.chainID); err != nil {
return fmt.Errorf("cannot send transaction from %s on chain ID %s: %w", addr, b.chainID.String(), err)
Expand Down Expand Up @@ -649,6 +660,10 @@ func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Cre
func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetForwarderForEOA(addr ADDR) (fwdr ADDR, err error) {
return fwdr, err
}
func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetForwarderForEOAOCR2(eoa common.Address, ocr2AggregatorID common.Address) (fwdr ADDR, err error) {
return fwdr, err
}

func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset(addr ADDR, abandon bool) error {
return nil
}
Expand Down
1 change: 1 addition & 0 deletions common/txmgr/types/forwarder_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
type ForwarderManager[ADDR types.Hashable] interface {
services.Service
ForwarderFor(addr ADDR) (forwarder ADDR, err error)
ForwarderForOCR2(eoa, ocr2Aggregator ADDR) (forwarder ADDR, err error)
// Converts payload to be forwarder-friendly
ConvertPayload(dest ADDR, origPayload []byte) ([]byte, error)
}
28 changes: 28 additions & 0 deletions common/txmgr/types/mocks/forwarder_manager.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 40 additions & 0 deletions core/chains/evm/forwarders/forwarder_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package forwarders

import (
"context"
"slices"
"sync"
"time"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/graph-gophers/graphql-go/errors"
pkgerrors "github.com/pkg/errors"
"github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
Expand Down Expand Up @@ -131,6 +134,43 @@ func (f *FwdMgr) ForwarderFor(addr common.Address) (forwarder common.Address, er
return common.Address{}, pkgerrors.Errorf("Cannot find forwarder for given EOA")
}

func (f *FwdMgr) ForwarderForOCR2(eoa, ocr2Aggregator common.Address) (forwarder common.Address, err error) {
fwdrs, err := f.ORM.FindForwardersByChain(f.ctx, big.Big(*f.evmClient.ConfiguredChainID()))
if err != nil {
return common.Address{}, err
}

offchainAggregator, err := ocr2aggregator.NewOCR2Aggregator(ocr2Aggregator, f.evmClient)
if err != nil {
return common.Address{}, err
}

transmitters, err := offchainAggregator.GetTransmitters(&bind.CallOpts{Context: f.ctx})
if err != nil {
return common.Address{}, errors.Errorf("failed to get ocr2 aggregator transmitters: %s", err.Error())
}

for _, fwdr := range fwdrs {
if !slices.Contains(transmitters, fwdr.Address) {
f.logger.Criticalw("forwarder is not set as a transmitter", "forwarderAddress", fwdr.Address, "err", err)
continue
}

eoas, err := f.getContractSenders(fwdr.Address)
if err != nil {
f.logger.Errorw("Failed to get forwarder senders", "forwarder", fwdr.Address, "err", err)
continue
}
for _, addr := range eoas {
if addr == eoa {
return fwdr.Address, nil
}
}
}
return common.Address{}, pkgerrors.Errorf("Cannot find forwarder for given EOA")

}

func (f *FwdMgr) ConvertPayload(dest common.Address, origPayload []byte) ([]byte, error) {
databytes, err := f.getForwardedPayload(dest, origPayload)
if err != nil {
Expand Down
61 changes: 56 additions & 5 deletions core/chains/evm/forwarders/forwarder_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@ package forwarders_test

import (
"math/big"
"slices"
"testing"
"time"

"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/smartcontractkit/libocr/gethwrappers2/testocr2aggregator"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
"github.com/smartcontractkit/chainlink-common/pkg/utils"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders"
Expand Down Expand Up @@ -102,7 +105,7 @@ func TestFwdMgr_MaybeForwardTransaction(t *testing.T) {
assert.True(t, cleanupCalled)
}

func TestFwdMgr_AccountUnauthorizedToForward_SkipsForwarding(t *testing.T) {
func TestFwdMgr_InvalidForwarderStates(t *testing.T) {
lggr := logger.Test(t)
db := pgtest.NewSqlxDB(t)
ctx := testutils.Context(t)
Expand All @@ -119,10 +122,25 @@ func TestFwdMgr_AccountUnauthorizedToForward_SkipsForwarding(t *testing.T) {
operatorAddr, _, _, err := operator_wrapper.DeployOperator(owner, ec, linkAddr, owner.From)
require.NoError(t, err)

forwarderAddr, _, _, err := authorized_forwarder.DeployAuthorizedForwarder(owner, ec, linkAddr, owner.From, operatorAddr, []byte{})
forwarderAddr, _, forwarder, err := authorized_forwarder.DeployAuthorizedForwarder(owner, ec, linkAddr, owner.From, operatorAddr, []byte{})
require.NoError(t, err)
ec.Commit()

accessAddress, _, _, err := testocr2aggregator.DeploySimpleWriteAccessController(owner, ec)
require.NoError(t, err, "failed to deploy test access controller contract")
ocr2Address, _, ocr2, err := testocr2aggregator.DeployOCR2Aggregator(

Check failure on line 131 in core/chains/evm/forwarders/forwarder_manager_test.go

View workflow job for this annotation

GitHub Actions / lint

ineffectual assignment to err (ineffassign)

Check failure on line 131 in core/chains/evm/forwarders/forwarder_manager_test.go

View workflow job for this annotation

GitHub Actions / lint

ineffectual assignment to err (ineffassign)
owner,
ec,
linkAddr,
big.NewInt(0),
big.NewInt(10),
accessAddress,
accessAddress,
9,
"TEST",
)
ec.Commit()

evmClient := client.NewSimulatedBackendClient(t, ec, testutils.FixtureChainID)
lpOpts := logpoller.Opts{
PollPeriod: 100 * time.Millisecond,
Expand All @@ -144,9 +162,42 @@ func TestFwdMgr_AccountUnauthorizedToForward_SkipsForwarding(t *testing.T) {

err = fwdMgr.Start(testutils.Context(t))
require.NoError(t, err)
addr, err := fwdMgr.ForwarderFor(owner.From)

// cannot find forwarder because it isn't authorized nor added as a transmitter
addr, err := fwdMgr.ForwarderForOCR2(owner.From, ocr2Address)
require.ErrorContains(t, err, "Cannot find forwarder for given EOA")
require.True(t, utils.IsZero(addr))

_, err = forwarder.SetAuthorizedSenders(owner, []common.Address{owner.From})
require.NoError(t, err)
ec.Commit()

// cannot find forwarder because it isn't added as a transmitter
addr, err = fwdMgr.ForwarderForOCR2(owner.From, ocr2Address)
require.ErrorContains(t, err, "Cannot find forwarder for given EOA")
require.True(t, utils.IsZero(addr))

onchainConfig, err := testhelpers.GenerateDefaultOCR2OnchainConfig(big.NewInt(0), big.NewInt(10))
require.NoError(t, err)

_, err = ocr2.SetConfig(owner,
[]common.Address{testutils.NewAddress(), testutils.NewAddress(), testutils.NewAddress(), testutils.NewAddress()},
[]common.Address{forwarderAddr, testutils.NewAddress(), testutils.NewAddress(), testutils.NewAddress()},
1,
onchainConfig,
0,
[]byte{})
require.NoError(t, err)
ec.Commit()

transmitters, err := ocr2.GetTransmitters(&bind.CallOpts{Context: ctx})
require.NoError(t, err)
require.True(t, slices.Contains(transmitters, forwarderAddr))

addr, err = fwdMgr.ForwarderForOCR2(owner.From, ocr2Address)
require.NoError(t, err, "forwarder should be valid and found because it is both authorized and set as a transmitter")
require.Equal(t, forwarderAddr, addr)

err = fwdMgr.Close()
require.NoError(t, err)
}
2 changes: 1 addition & 1 deletion core/services/ocr2/delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ func GetEVMEffectiveTransmitterID(jb *job.Job, chain legacyevm.Chain, lggr logge
if chain == nil {
return "", fmt.Errorf("job forwarding requires non-nil chain")
}
effectiveTransmitterID, err := chain.TxManager().GetForwarderForEOA(common.HexToAddress(spec.TransmitterID.String))
effectiveTransmitterID, err := chain.TxManager().GetForwarderForEOAOCR2(common.HexToAddress(spec.TransmitterID.String), common.HexToAddress(spec.ContractID))
if err == nil {
return effectiveTransmitterID.String(), nil
} else if !spec.TransmitterID.Valid {
Expand Down

0 comments on commit b392880

Please sign in to comment.