Skip to content

Commit

Permalink
Filter testing
Browse files Browse the repository at this point in the history
  • Loading branch information
connorwstein committed Oct 3, 2023
1 parent 30076f3 commit b877f2a
Show file tree
Hide file tree
Showing 16 changed files with 171 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
"github.com/smartcontractkit/chainlink/v2/core/services/pg"
)

type CommitStoreInterval struct {
Expand Down Expand Up @@ -64,34 +63,22 @@ type OffchainConfig struct {
}

type CommitStoreReader interface {
Closer
GetExpectedNextSequenceNumber(context context.Context) (uint64, error)

GetLatestPriceEpochAndRound(context context.Context) (uint64, error)

// GetAcceptedCommitReportsGteSeqNum returns all the accepted commit reports that have sequence number greater than or equal to the provided.
GetAcceptedCommitReportsGteSeqNum(ctx context.Context, seqNum uint64, confs int) ([]Event[CommitStoreReport], error)

// GetAcceptedCommitReportsGteTimestamp returns all the commit reports with timestamp greater than or equal to the provided.
GetAcceptedCommitReportsGteTimestamp(ctx context.Context, ts time.Time, confs int) ([]Event[CommitStoreReport], error)

IsDown(ctx context.Context) bool

IsBlessed(ctx context.Context, root [32]byte) (bool, error)

// Notifies the reader that the config has changed onchain
ConfigChanged(onchainConfig []byte, offchainConfig []byte) (common.Address, error)

OffchainConfig() OffchainConfig

GasPriceEstimator() prices.GasPriceEstimatorCommit

EncodeCommitReport(report CommitStoreReport) ([]byte, error)

DecodeCommitReport(report []byte) (CommitStoreReport, error)

Verify(ctx context.Context, report ExecReport) bool

Close(qopts ...pg.QOpt) error
}

func NewCommitStoreReader(lggr logger.Logger, address common.Address, ec client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator) (CommitStoreReader, error) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package ccipdata

import (
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
"github.com/smartcontractkit/chainlink/v2/core/logger"
)

func assertFilterRegistration(t *testing.T, lp *lpmocks.LogPoller, buildCloser func(lp *lpmocks.LogPoller, addr common.Address) Closer, numFilter int) {
// Expected filter properties for a closer:
// - Should be the same filter set registered that is unregistered
// - Should be registered to the address specified
// - Number of events specific to this component should be registered
addr := common.HexToAddress("0x1234")
var filters []logpoller.Filter
lp.On("RegisterFilter", mock.Anything).Run(func(args mock.Arguments) {
f := args.Get(0).(logpoller.Filter)
require.Equal(t, len(f.Addresses), 1)
require.Equal(t, f.Addresses[0], addr)
filters = append(filters, f)
}).Return(nil).Times(numFilter)
c := buildCloser(lp, addr)
for _, filter := range filters {
lp.On("UnregisterFilter", filter.Name).Return(nil)
}
require.NoError(t, c.Close())
lp.AssertExpectations(t)
}

func TestCommitFilters(t *testing.T) {
assertFilterRegistration(t, new(lpmocks.LogPoller), func(lp *lpmocks.LogPoller, addr common.Address) Closer {
c, err := NewCommitStoreV1_0_0(logger.TestLogger(t), addr, new(mocks.Client), lp, nil)
require.NoError(t, err)
return c
}, 1)
assertFilterRegistration(t, new(lpmocks.LogPoller), func(lp *lpmocks.LogPoller, addr common.Address) Closer {
c, err := NewCommitStoreV1_2_0(logger.TestLogger(t), addr, new(mocks.Client), lp, nil)
require.NoError(t, err)
return c
}, 1)
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (

const (
EXEC_REPORT_ACCEPTS = "Exec report accepts"
ReportAccepted = "ReportAccepted"
)

var _ CommitStoreReader = &CommitStoreV1_0_0{}
Expand Down Expand Up @@ -297,8 +298,8 @@ func NewCommitStoreV1_0_0(lggr logger.Logger, addr common.Address, ec client.Cli
return nil, err
}
commitStoreABI := abihelpers.MustParseABI(commit_store.CommitStoreABI)
eventSig := abihelpers.MustGetEventID("ReportAccepted", commitStoreABI)
commitReportArgs := abihelpers.MustGetEventInputs("ReportAccepted", commitStoreABI)
eventSig := abihelpers.MustGetEventID(ReportAccepted, commitStoreABI)
commitReportArgs := abihelpers.MustGetEventInputs(ReportAccepted, commitStoreABI)
var filters = []logpoller.Filter{
{
Name: logpoller.FilterName(EXEC_REPORT_ACCEPTS, addr.String()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,5 @@ func NewCommitStoreV1_2_0(lggr logger.Logger, addr common.Address, ec client.Cli
if err != nil {
return nil, err
}
// TODO: try and read initial config
return &CommitStoreV1_2_0{CommitStoreV1_0_0: commitStoreV100}, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
"github.com/smartcontractkit/chainlink/v2/core/services/pg"
"github.com/smartcontractkit/chainlink/v2/core/store/models"
)

Expand Down Expand Up @@ -123,37 +122,24 @@ type ExecReport struct {
}

type OffRampReader interface {
Closer
// Will error if messages are not a compatible verion
EncodeExecutionReport(report ExecReport) ([]byte, error)

DecodeExecutionReport(report []byte) (ExecReport, error)

// GetExecutionStateChangesBetweenSeqNums returns all the execution state change events for the provided message sequence numbers (inclusive).
GetExecutionStateChangesBetweenSeqNums(ctx context.Context, seqNumMin, seqNumMax uint64, confs int) ([]Event[ExecutionStateChanged], error)

GetDestinationTokens(ctx context.Context) ([]common.Address, error)

GetPoolByDestToken(ctx context.Context, address common.Address) (common.Address, error)

GetDestinationToken(ctx context.Context, address common.Address) (common.Address, error)

GetSupportedTokens(ctx context.Context) ([]common.Address, error)

Address() common.Address

// TODO Needed for cachign, maybe caching should move behind the readers?
// TODO Needed for caching, maybe caching should move behind the readers?
TokenEvents() []common.Hash

// Notifies the reader that the config has changed onchain
ConfigChanged(onchainConfig []byte, offchainConfig []byte) (common.Address, common.Address, error)

OffchainConfig() ExecOffchainConfig

OnchainConfig() ExecOnchainConfig

GasPriceEstimator() prices.GasPriceEstimatorExec

Close(qopts ...pg.QOpt) error
}

// MessageExecutionState defines the execution states of CCIP messages.
Expand All @@ -173,12 +159,13 @@ func NewOffRampReader(lggr logger.Logger, addr common.Address, srcClient, destCl
}
switch version.String() {
case "1.0.0", "1.1.0":
return NewOffRampV1_0_0(lggr, addr, destClient, lp, estimator, srcClient)
return NewOffRampV1_0_0(lggr, addr, destClient, lp, estimator)
case "1.2.0":
return NewOffRampV1_2_0(lggr, addr, destClient, lp, estimator, srcClient)
return NewOffRampV1_2_0(lggr, addr, destClient, lp, estimator)
default:
return nil, errors.Errorf("unsupported offramp verison %v", version.String())
}
// TODO can validate it points to the correct onramp version using srcClinet
}

func ExecReportToEthTxMeta(typ ccipconfig.ContractType, ver semver.Version) (func(report []byte) (*txmgr.TxMeta, error), error) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package ccipdata
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,43 @@ import (
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks"
lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal"
)

func TestExecutionReportEncoding(t *testing.T) {
// Note could consider some fancier testing here (fuzz/property)
// but I think that would essentially be testing geth's abi library
// as our encode/decode is a thin wrapper around that.
report := evm_2_evm_offramp.InternalExecutionReport{
Messages: []evm_2_evm_offramp.InternalEVM2EVMMessage{},
report := ExecReport{
Messages: []internal.EVM2EVMMessage{},
OffchainTokenData: [][][]byte{{}},
Proofs: [][32]byte{testutils.Random32Byte()},
ProofFlagBits: big.NewInt(133),
}
encodeExecutionReport, err := EncodeExecutionReport(evm_2_evm_offramp.InternalExecutionReport{
Messages: report.Messages,
OffchainTokenData: report.OffchainTokenData,
Proofs: report.Proofs,
ProofFlagBits: report.ProofFlagBits,
})
offRamp := &OffRampV1_0_0{}
encodeExecutionReport, err := offRamp.EncodeExecutionReport(report)
require.NoError(t, err)
decodeCommitReport, err := DecodeExecutionReport(encodeExecutionReport)
decodeCommitReport, err := offRamp.DecodeExecutionReport(encodeExecutionReport)
require.NoError(t, err)
require.Equal(t, report, decodeCommitReport)
}

func TestOffRampFilters(t *testing.T) {
assertFilterRegistration(t, new(lpmocks.LogPoller), func(lp *lpmocks.LogPoller, addr common.Address) Closer {
c, err := NewOffRampV1_0_0(logger.TestLogger(t), addr, new(mocks.Client), lp, nil)
require.NoError(t, err)
return c
}, 3)
assertFilterRegistration(t, new(lpmocks.LogPoller), func(lp *lpmocks.LogPoller, addr common.Address) Closer {
c, err := NewOffRampV1_2_0(logger.TestLogger(t), addr, new(mocks.Client), lp, nil)
require.NoError(t, err)
return c
}, 3)
}
74 changes: 34 additions & 40 deletions core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_v1_0_0.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"math/big"
"time"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
Expand Down Expand Up @@ -45,35 +46,32 @@ type OffRampV1_0_0 struct {
ec client.Client
filters []logpoller.Filter
estimator gas.EvmFeeEstimator
offchainConfig ExecOffchainConfig
onchainConfig ExecOnchainConfig
gasPriceEstimator prices.GasPriceEstimatorExec
executionReportArgs abi.Arguments
eventIndex int
eventSig common.Hash
}

func (o *OffRampV1_0_0) GetDestinationToken(ctx context.Context, address common.Address) (common.Address, error) {
//TODO implement me
panic("implement me")
return o.offRamp.GetDestinationToken(&bind.CallOpts{Context: ctx}, address)
}

func (o *OffRampV1_0_0) GetSupportedTokens(ctx context.Context) ([]common.Address, error) {
//TODO implement me
panic("implement me")
return o.offRamp.GetSupportedTokens(&bind.CallOpts{Context: ctx})
}

func (o *OffRampV1_0_0) GetPoolByDestToken(ctx context.Context, address common.Address) (common.Address, error) {
//TODO implement me
panic("implement me")
return o.offRamp.GetPoolByDestToken(&bind.CallOpts{Context: ctx}, address)
}

func (o *OffRampV1_0_0) OffchainConfig() ExecOffchainConfig {
//TODO implement me
panic("implement me")
return o.offchainConfig
}

func (o *OffRampV1_0_0) OnchainConfig() ExecOnchainConfig {
//TODO implement me
panic("implement me")
return o.onchainConfig
}

func (o *OffRampV1_0_0) GasPriceEstimator() prices.GasPriceEstimatorExec {
Expand Down Expand Up @@ -102,6 +100,17 @@ func (o *OffRampV1_0_0) ConfigChanged(onchainConfig []byte, offchainConfig []byt
if err != nil {
return common.Address{}, common.Address{}, err
}
o.offchainConfig = ExecOffchainConfig{
SourceFinalityDepth: offchainConfigParsed.SourceFinalityDepth,
DestFinalityDepth: offchainConfigParsed.DestFinalityDepth,
DestOptimisticConfirmations: offchainConfigParsed.DestOptimisticConfirmations,
BatchGasLimit: offchainConfigParsed.BatchGasLimit,
RelativeBoostPerWaitHour: offchainConfigParsed.RelativeBoostPerWaitHour,
MaxGasPrice: offchainConfigParsed.MaxGasPrice,
InflightCacheExpiry: offchainConfigParsed.InflightCacheExpiry,
RootSnoozeTime: offchainConfigParsed.RootSnoozeTime,
}
o.onchainConfig = ExecOnchainConfig{PermissionLessExecutionThresholdSeconds: time.Second * time.Duration(onchainConfigParsed.PermissionLessExecutionThresholdSeconds)}
o.gasPriceEstimator = prices.NewExecGasPriceEstimator(o.estimator, big.NewInt(int64(offchainConfigParsed.MaxGasPrice)), 0)
o.lggr.Infow("Starting exec plugin",
"offchainConfig", onchainConfigParsed,
Expand Down Expand Up @@ -224,22 +233,23 @@ func decodeExecReportV1_0_0(args abi.Arguments, report []byte) (ExecReport, erro
Amount: tokenAndAmount.Amount,
})
}
// TODO
messages = append(messages, internal.EVM2EVMMessage{
SequenceNumber: msg.SequenceNumber,
GasLimit: nil,
Nonce: 0,
GasLimit: msg.GasLimit,
Nonce: msg.Nonce,
MessageId: msg.MessageId,
SourceChainSelector: 0,
Sender: common.Address{},
Receiver: common.Address{},
Strict: false,
FeeToken: common.Address{},
FeeTokenAmount: nil,
Data: nil,
SourceChainSelector: msg.SourceChainSelector,
Sender: msg.Sender,
Receiver: msg.Receiver,
Strict: msg.Strict,
FeeToken: msg.FeeToken,
FeeTokenAmount: msg.FeeTokenAmount,
Data: msg.Data,
TokenAmounts: tokensAndAmounts,
SourceTokenData: nil,
Hash: [32]byte{}, // TODO
SourceTokenData: msg.SourceTokenData,
// TODO: Not needed for plugins, but should be recomputed for consistentcy.
// Requires the offramp knowing about onramp version
Hash: [32]byte{},
})
}

Expand All @@ -263,7 +273,7 @@ func (o *OffRampV1_0_0) TokenEvents() []common.Hash {
return []common.Hash{abihelpers.MustGetEventID("PoolAdded", offRampABI), abihelpers.MustGetEventID("PoolRemoved", offRampABI)}
}

func NewOffRampV1_0_0(lggr logger.Logger, addr common.Address, ec client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator, srcClient client.Client) (*OffRampV1_0_0, error) {
func NewOffRampV1_0_0(lggr logger.Logger, addr common.Address, ec client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator) (*OffRampV1_0_0, error) {
offRamp, err := evm_2_evm_offramp.NewEVM2EVMOffRamp(addr, ec)
if err != nil {
return nil, err
Expand Down Expand Up @@ -292,22 +302,6 @@ func NewOffRampV1_0_0(lggr logger.Logger, addr common.Address, ec client.Client,
if err := logpollerutil.RegisterLpFilters(lp, filters); err != nil {
return nil, err
}
s, err := offRamp.GetStaticConfig(nil)
if err != nil {
return nil, err
}
// Must point to the correct version onramp
contractType, version, err := ccipconfig.TypeAndVersion(s.OnRamp, srcClient)
if err != nil {
return nil, err
}
if contractType != ccipconfig.EVM2EVMOnRamp || version.String() != "1.0.0" {
return nil, errors.Errorf("offramp points to invalid onramp %v expected 1.0.0", version.String())
}
onRamp, err := evm_2_evm_onramp_1_0_0.NewEVM2EVMOnRamp(s.OnRamp, srcClient)
if err != nil {
return nil, err
}
return &OffRampV1_0_0{offRamp: offRamp, onRamp: onRamp, addr: addr, lggr: lggr, lp: lp, filters: filters,
return &OffRampV1_0_0{offRamp: offRamp, addr: addr, lggr: lggr, lp: lp, filters: filters,
estimator: estimator, executionReportArgs: executionReportArgs, eventSig: stateChanged, eventIndex: executionStateChangedSequenceNumberIndex}, nil
}
Loading

0 comments on commit b877f2a

Please sign in to comment.