diff --git a/core/capabilities/targets/write_target.go b/core/capabilities/targets/write_target.go index de65cb85199..f178beb5224 100644 --- a/core/capabilities/targets/write_target.go +++ b/core/capabilities/targets/write_target.go @@ -29,6 +29,8 @@ type WriteTarget struct { forwarderAddress string capabilities.CapabilityInfo lggr logger.Logger + + bound bool } func NewWriteTarget(lggr logger.Logger, id string, cr commontypes.ContractReader, cw commontypes.ChainWriter, forwarderAddress string) *WriteTarget { @@ -46,6 +48,7 @@ func NewWriteTarget(lggr logger.Logger, id string, cr commontypes.ContractReader forwarderAddress, info, logger, + false, } } @@ -73,6 +76,21 @@ func success() <-chan capabilities.CapabilityResponse { } func (cap *WriteTarget) Execute(ctx context.Context, request capabilities.CapabilityRequest) (<-chan capabilities.CapabilityResponse, error) { + // Bind to the contract address on the write path. + // Bind() requires a connection to the node's RPCs and + // cannot be run during initialization. + if !cap.bound { + cap.lggr.Debugw("Binding to forwarder address") + err := cap.cr.Bind(ctx, []commontypes.BoundContract{{ + Address: cap.forwarderAddress, + Name: "forwarder", + }}) + if err != nil { + return nil, err + } + cap.bound = true + } + cap.lggr.Debugw("Execute", "request", request) reqConfig, err := parseConfig(request.Config) diff --git a/core/capabilities/targets/write_target_test.go b/core/capabilities/targets/write_target_test.go index 9f243389f27..9a752b79483 100644 --- a/core/capabilities/targets/write_target_test.go +++ b/core/capabilities/targets/write_target_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/values" "github.com/smartcontractkit/chainlink/v2/core/capabilities/targets" "github.com/smartcontractkit/chainlink/v2/core/capabilities/targets/mocks" @@ -47,6 +48,13 @@ func TestWriteTarget(t *testing.T) { }) require.NoError(t, err) + cr.On("Bind", mock.Anything, []types.BoundContract{ + { + Address: forwarderAddr, + Name: "forwarder", + }, + }).Return(nil) + cr.On("GetLatestValue", mock.Anything, "forwarder", "getTransmitter", mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { transmitter := args.Get(4).(*common.Address) *transmitter = common.HexToAddress("0x0") diff --git a/core/services/registrysyncer/syncer.go b/core/services/registrysyncer/syncer.go index 5a4ce4b6ba5..6b44d7b2c86 100644 --- a/core/services/registrysyncer/syncer.go +++ b/core/services/registrysyncer/syncer.go @@ -73,6 +73,9 @@ type contractReaderFactory interface { NewContractReader(context.Context, []byte) (types.ContractReader, error) } +// NOTE: this can't be called while initializing the syncer and needs to be called in the sync loop. +// This is because Bind() makes an onchain call to verify that the contract address exists, and if +// called during initialization, this results in a "no live nodes" error. func newReader(ctx context.Context, lggr logger.Logger, relayer contractReaderFactory, remoteRegistryAddress string) (types.ContractReader, error) { contractReaderConfig := evmrelaytypes.ChainReaderConfig{ Contracts: map[string]evmrelaytypes.ChainContractReader{ diff --git a/core/services/relay/evm/write_target.go b/core/services/relay/evm/write_target.go index dc1a3635330..fb1c694a2e7 100644 --- a/core/services/relay/evm/write_target.go +++ b/core/services/relay/evm/write_target.go @@ -7,7 +7,6 @@ import ( chainselectors "github.com/smartcontractkit/chain-selectors" - commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/capabilities/targets" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/forwarder" @@ -46,13 +45,6 @@ func NewWriteTarget(ctx context.Context, relayer *Relayer, chain legacyevm.Chain if err != nil { return nil, err } - err = cr.Bind(ctx, []commontypes.BoundContract{{ - Address: config.ForwarderAddress().String(), - Name: "forwarder", - }}) - if err != nil { - return nil, err - } chainWriterConfig := relayevmtypes.ChainWriterConfig{ Contracts: map[string]*relayevmtypes.ContractConfig{