Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
33 changes: 30 additions & 3 deletions pkg/chainaccessor/default_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,36 @@ func (l *DefaultAccessor) GetChainFeeComponents(ctx context.Context) (cciptypes.
return *fc, nil
}

func (l *DefaultAccessor) Sync(ctx context.Context, contracts cciptypes.ContractAddresses) error {
// TODO(NONEVM-1865): implement
panic("implement me")
func (l *DefaultAccessor) Sync(
ctx context.Context,
contractName string,
contractAddress cciptypes.UnknownAddress,
) error {
lggr := logutil.WithContextValues(ctx, l.lggr)
addressStr, err := l.addrCodec.AddressBytesToString(contractAddress, l.chainSelector)
if err != nil {
return fmt.Errorf("unable to convert address bytes to string: %w, address: %v", err, contractAddress)
}

contract := types.BoundContract{
Address: addressStr,
Name: contractName,
}

lggr.Debugw("Binding contract",
"chainSelector", l.chainSelector,
"contractName", contractName,
"address", addressStr,
)
// Bind the contract address to the reader.
// If the same address exists -> no-op
// If the address is changed -> updates the address, overwrites the existing one
// If the contract not bound -> binds to the new address
if err := l.contractReader.Bind(ctx, []types.BoundContract{contract}); err != nil {
return fmt.Errorf("unable to bind %s %s for chain %d: %w", contractName, addressStr, l.chainSelector, err)
}

return nil
}

func (l *DefaultAccessor) MsgsBetweenSeqNums(
Expand Down
34 changes: 14 additions & 20 deletions pkg/reader/ccip.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,8 +527,6 @@ func (r *ccipChainReader) buildSigners(signers []signer) []cciptypes.RemoteSigne
}

func (r *ccipChainReader) GetRMNRemoteConfig(ctx context.Context) (cciptypes.RemoteConfig, error) {
lggr := logutil.WithContextValues(ctx, r.lggr)

if err := validateReaderExistence(r.contractReaders, r.destChain); err != nil {
return cciptypes.RemoteConfig{}, fmt.Errorf("validate dest=%d extended reader existence: %w", r.destChain, err)
}
Expand All @@ -549,7 +547,7 @@ func (r *ccipChainReader) GetRMNRemoteConfig(ctx context.Context) (cciptypes.Rem
return cciptypes.RemoteConfig{}, fmt.Errorf("get RMNRemote proxy contract address: %w", err)
}

rmnRemoteAddress, err := r.getRMNRemoteAddress(ctx, lggr, r.destChain, proxyContractAddress)
rmnRemoteAddress, err := r.getRMNRemoteAddress(ctx, r.destChain, proxyContractAddress)
if err != nil {
return cciptypes.RemoteConfig{}, fmt.Errorf("get RMNRemote address: %w", err)
}
Expand Down Expand Up @@ -794,21 +792,14 @@ func (r *ccipChainReader) Sync(ctx context.Context, contracts ContractAddresses)
return nil
}

// the extended reader will do nothing if the contract is already bound.
_, err := bindReaderContract(
ctx,
lggr,
r.contractReaders,
chainSelector,
boundContract.name,
boundContract.address,
r.addrCodec)
if err != nil {
if errors.Is(err, ErrContractReaderNotFound) {
// don't support this chain, nothing to do.
return nil
}
chainAccessor, err := getChainAccessor(r.accessors, chainSelector)
if err != nil && errors.Is(err, ErrChainAccessorNotFound) {
// don't support this chain, nothing to do.
return nil
}

err = chainAccessor.Sync(ctx, boundContract.name, boundContract.address)
if err != nil {
return fmt.Errorf("bind reader contract %s on chain %s: %w", boundContract.name, chainSelector, err)
}

Expand Down Expand Up @@ -1129,12 +1120,15 @@ type versionedConfig struct {
//nolint:lll
func (r *ccipChainReader) getRMNRemoteAddress(
ctx context.Context,
lggr logger.Logger,
chain cciptypes.ChainSelector,
rmnRemoteProxyAddress []byte) ([]byte, error) {
_, err := bindReaderContract(ctx, lggr, r.contractReaders, chain, consts.ContractNameRMNProxy, rmnRemoteProxyAddress, r.addrCodec)
chainAccessor, err := getChainAccessor(r.accessors, chain)
if err != nil {
return nil, fmt.Errorf("unable to getChainAccessor: %w", err)
}
err = chainAccessor.Sync(ctx, consts.ContractNameRMNProxy, rmnRemoteProxyAddress)
if err != nil {
return nil, fmt.Errorf("bind RMN proxy contract: %w", err)
return nil, fmt.Errorf("sync RMN proxy contract: %w", err)
}

// Get the address from cache instead of making a contract call
Expand Down
1 change: 1 addition & 0 deletions pkg/reader/ccip_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
)

var (
ErrChainAccessorNotFound = errors.New("chain accessor not found")
ErrContractReaderNotFound = errors.New("contract reader not found")
ErrContractWriterNotFound = errors.New("contract writer not found")
)
Expand Down
135 changes: 107 additions & 28 deletions pkg/reader/ccip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,20 @@ func TestCCIPChainReader_Sync_HappyPath_BindsContractsSuccessfully(t *testing.T)
s1Onramp := []byte{0x1}
s2Onramp := []byte{0x2}
destNonceMgr := []byte{0x3}
offRamp := []byte{0x4}

mockAddrCodec := internal.NewMockAddressCodecHex(t)
destNonceMgrAddrStr, err := mockAddrCodec.AddressBytesToString(destNonceMgr, destChain)
require.NoError(t, err)
offRampAddrStr, err := mockAddrCodec.AddressBytesToString(offRamp, destChain)
require.NoError(t, err)
destExtended := reader_mocks.NewMockExtended(t)
destExtended.EXPECT().Bind(mock.Anything, []types.BoundContract{
{
Name: consts.ContractNameOffRamp,
Address: offRampAddrStr,
},
}).Return(nil)
destExtended.EXPECT().Bind(mock.Anything, []types.BoundContract{
{
Name: consts.ContractNameNonceManager,
Expand Down Expand Up @@ -187,17 +196,26 @@ func TestCCIPChainReader_Sync_HappyPath_BindsContractsSuccessfully(t *testing.T)
defer source1Extended.AssertExpectations(t)
defer source2Extended.AssertExpectations(t)

ccipReader := &ccipChainReader{
contractReaders: map[cciptypes.ChainSelector]contractreader.Extended{
cw := writer_mocks.NewMockContractWriter(t)
contractWriters := make(map[cciptypes.ChainSelector]types.ContractWriter)
contractWriters[destChain] = cw
contractWriters[sourceChain1] = cw
contractWriters[sourceChain2] = cw

ccipReader, err := newCCIPChainReaderInternal(
ctx,
logger.Test(t),
map[cciptypes.ChainSelector]contractreader.ContractReaderFacade{
destChain: destExtended,
sourceChain1: source1Extended,
sourceChain2: source2Extended,
},
donAddressBook: addressbook.NewBook(),
destChain: destChain,
lggr: logger.Test(t),
addrCodec: mockAddrCodec,
}
contractWriters,
destChain,
offRamp,
mockAddrCodec,
)
require.NoError(t, err)

contracts := ContractAddresses{
consts.ContractNameOnRamp: {
Expand All @@ -211,6 +229,8 @@ func TestCCIPChainReader_Sync_HappyPath_BindsContractsSuccessfully(t *testing.T)

err = ccipReader.Sync(ctx, contracts)
require.NoError(t, err)
err = ccipReader.Close()
require.NoError(t, err)
}

func TestCCIPChainReader_Sync_HappyPath_SkipsEmptyAddress(t *testing.T) {
Expand All @@ -219,6 +239,7 @@ func TestCCIPChainReader_Sync_HappyPath_SkipsEmptyAddress(t *testing.T) {
sourceChain1 := cciptypes.ChainSelector(2)
sourceChain2 := cciptypes.ChainSelector(3)
s1Onramp := []byte{0x1}
offRamp := []byte{0x4}

// empty address, should get skipped
s2Onramp := []byte{}
Expand All @@ -228,6 +249,14 @@ func TestCCIPChainReader_Sync_HappyPath_SkipsEmptyAddress(t *testing.T) {
mockAddrCodec := internal.NewMockAddressCodecHex(t)
destNonceMgrAddrStr, err := mockAddrCodec.AddressBytesToString(destNonceMgr, destChain)
require.NoError(t, err)
offRampAddrStr, err := mockAddrCodec.AddressBytesToString(offRamp, destChain)
require.NoError(t, err)
destExtended.EXPECT().Bind(mock.Anything, []types.BoundContract{
{
Name: consts.ContractNameOffRamp,
Address: offRampAddrStr,
},
}).Return(nil)
destExtended.EXPECT().Bind(mock.Anything, []types.BoundContract{
{
Name: consts.ContractNameNonceManager,
Expand All @@ -252,17 +281,26 @@ func TestCCIPChainReader_Sync_HappyPath_SkipsEmptyAddress(t *testing.T) {
defer source1Extended.AssertExpectations(t)
defer source2Extended.AssertExpectations(t)

ccipReader := &ccipChainReader{
contractReaders: map[cciptypes.ChainSelector]contractreader.Extended{
cw := writer_mocks.NewMockContractWriter(t)
contractWriters := make(map[cciptypes.ChainSelector]types.ContractWriter)
contractWriters[destChain] = cw
contractWriters[sourceChain1] = cw
contractWriters[sourceChain2] = cw

ccipReader, err := newCCIPChainReaderInternal(
ctx,
logger.Test(t),
map[cciptypes.ChainSelector]contractreader.ContractReaderFacade{
destChain: destExtended,
sourceChain1: source1Extended,
sourceChain2: source2Extended,
},
donAddressBook: addressbook.NewBook(),
destChain: destChain,
lggr: logger.Test(t),
addrCodec: mockAddrCodec,
}
contractWriters,
destChain,
offRamp,
mockAddrCodec,
)
require.NoError(t, err)

contracts := ContractAddresses{
consts.ContractNameOnRamp: {
Expand All @@ -276,6 +314,8 @@ func TestCCIPChainReader_Sync_HappyPath_SkipsEmptyAddress(t *testing.T) {

err = ccipReader.Sync(ctx, contracts)
require.NoError(t, err)
err = ccipReader.Close()
require.NoError(t, err)
}

func TestCCIPChainReader_Sync_HappyPath_DontSupportAllChains(t *testing.T) {
Expand All @@ -286,11 +326,20 @@ func TestCCIPChainReader_Sync_HappyPath_DontSupportAllChains(t *testing.T) {
s1Onramp := []byte{0x1}
s2Onramp := []byte{0x2}
destNonceMgr := []byte{0x3}
offRamp := []byte{0x4}
destExtended := reader_mocks.NewMockExtended(t)
mockAddrCodec := internal.NewMockAddressCodecHex(t)

destNonceMgrAddrStr, err := mockAddrCodec.AddressBytesToString(destNonceMgr, destChain)
require.NoError(t, err)
offRampAddrStr, err := mockAddrCodec.AddressBytesToString(offRamp, destChain)
require.NoError(t, err)
destExtended.EXPECT().Bind(mock.Anything, []types.BoundContract{
{
Name: consts.ContractNameOffRamp,
Address: offRampAddrStr,
},
}).Return(nil)
destExtended.EXPECT().Bind(mock.Anything, []types.BoundContract{
{
Name: consts.ContractNameNonceManager,
Expand All @@ -312,16 +361,24 @@ func TestCCIPChainReader_Sync_HappyPath_DontSupportAllChains(t *testing.T) {
defer destExtended.AssertExpectations(t)
defer source2Extended.AssertExpectations(t)

ccipReader := &ccipChainReader{
contractReaders: map[cciptypes.ChainSelector]contractreader.Extended{
cw := writer_mocks.NewMockContractWriter(t)
contractWriters := make(map[cciptypes.ChainSelector]types.ContractWriter)
contractWriters[destChain] = cw
contractWriters[sourceChain2] = cw

ccipReader, err := newCCIPChainReaderInternal(
ctx,
logger.Test(t),
map[cciptypes.ChainSelector]contractreader.ContractReaderFacade{
destChain: destExtended,
sourceChain2: source2Extended,
},
donAddressBook: addressbook.NewBook(),
destChain: destChain,
lggr: logger.Test(t),
addrCodec: mockAddrCodec,
}
contractWriters,
destChain,
offRamp,
mockAddrCodec,
)
require.NoError(t, err)

contracts := ContractAddresses{
consts.ContractNameOnRamp: {
Expand All @@ -335,6 +392,8 @@ func TestCCIPChainReader_Sync_HappyPath_DontSupportAllChains(t *testing.T) {

err = ccipReader.Sync(ctx, contracts)
require.NoError(t, err)
err = ccipReader.Close()
require.NoError(t, err)
}

func TestCCIPChainReader_Sync_BindError(t *testing.T) {
Expand All @@ -345,11 +404,20 @@ func TestCCIPChainReader_Sync_BindError(t *testing.T) {
s1Onramp := []byte{0x1}
s2Onramp := []byte{0x2}
destNonceMgr := []byte{0x3}
offRamp := []byte{0x4}

mockAddrCodec := internal.NewMockAddressCodecHex(t)
destNonceMgrAddrStr, err := mockAddrCodec.AddressBytesToString(destNonceMgr, destChain)
require.NoError(t, err)
offRampAddrStr, err := mockAddrCodec.AddressBytesToString(offRamp, destChain)
require.NoError(t, err)
destExtended := reader_mocks.NewMockExtended(t)
destExtended.EXPECT().Bind(mock.Anything, []types.BoundContract{
{
Name: consts.ContractNameOffRamp,
Address: offRampAddrStr,
},
}).Return(nil)
destExtended.EXPECT().Bind(mock.Anything, []types.BoundContract{
{
Name: consts.ContractNameNonceManager,
Expand Down Expand Up @@ -382,17 +450,26 @@ func TestCCIPChainReader_Sync_BindError(t *testing.T) {
defer source1Extended.AssertExpectations(t)
defer source2Extended.AssertExpectations(t)

ccipReader := &ccipChainReader{
contractReaders: map[cciptypes.ChainSelector]contractreader.Extended{
cw := writer_mocks.NewMockContractWriter(t)
contractWriters := make(map[cciptypes.ChainSelector]types.ContractWriter)
contractWriters[destChain] = cw
contractWriters[sourceChain1] = cw
contractWriters[sourceChain2] = cw

ccipReader, err := newCCIPChainReaderInternal(
ctx,
logger.Test(t),
map[cciptypes.ChainSelector]contractreader.ContractReaderFacade{
destChain: destExtended,
sourceChain1: source1Extended,
sourceChain2: source2Extended,
},
donAddressBook: addressbook.NewBook(),
destChain: destChain,
lggr: logger.Test(t),
addrCodec: mockAddrCodec,
}
contractWriters,
destChain,
offRamp,
mockAddrCodec,
)
require.NoError(t, err)

contracts := ContractAddresses{
consts.ContractNameOnRamp: {
Expand All @@ -407,6 +484,8 @@ func TestCCIPChainReader_Sync_BindError(t *testing.T) {
err = ccipReader.Sync(ctx, contracts)
require.Error(t, err)
require.ErrorIs(t, err, expectedErr)
err = ccipReader.Close()
require.NoError(t, err)
}

// The round1 version returns NoBindingFound errors for onramp contracts to simulate
Expand Down
Loading
Loading