diff --git a/.changeset/tender-carpets-cry.md b/.changeset/tender-carpets-cry.md new file mode 100644 index 00000000000..075f769ce00 --- /dev/null +++ b/.changeset/tender-carpets-cry.md @@ -0,0 +1,7 @@ +--- +"chainlink": patch +--- + +Add new relayer type "dummy" for testing. + +#added diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 1c8996a46ec..bc0dd40e289 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -1021,6 +1021,11 @@ func (lp *logPoller) latestBlocks(ctx context.Context) (*evmtypes.Head, int64, e if err != nil { return nil, 0, err } + if latestBlock == nil { + // Shouldn't happen with a real client, but still better rather to + // return error than panic + return nil, 0, errors.New("latest block is nil") + } // If chain has fewer blocks than finalityDepth, return 0 return latestBlock, mathutil.Max(latestBlock.Number-lp.finalityDepth, 0), nil } diff --git a/core/cmd/shell.go b/core/cmd/shell.go index e12b069277b..c79fb703107 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -184,7 +184,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G } // evm always enabled for backward compatibility // TODO BCF-2510 this needs to change in order to clear the path for EVM extraction - initOps := []chainlink.CoreRelayerChainInitFunc{chainlink.InitEVM(ctx, relayerFactory, evmFactoryCfg)} + initOps := []chainlink.CoreRelayerChainInitFunc{chainlink.InitDummy(ctx, relayerFactory), chainlink.InitEVM(ctx, relayerFactory, evmFactoryCfg)} if cfg.CosmosEnabled() { cosmosCfg := chainlink.CosmosFactoryConfig{ diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 5212b29fce3..e86394d82f9 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -387,7 +387,7 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn testCtx := testutils.Context(t) // evm alway enabled for backward compatibility - initOps := []chainlink.CoreRelayerChainInitFunc{chainlink.InitEVM(testCtx, relayerFactory, evmOpts)} + initOps := []chainlink.CoreRelayerChainInitFunc{chainlink.InitDummy(testCtx, relayerFactory), chainlink.InitEVM(testCtx, relayerFactory, evmOpts)} if cfg.CosmosEnabled() { cosmosCfg := chainlink.CosmosFactoryConfig{ diff --git a/core/internal/testutils/testutils.go b/core/internal/testutils/testutils.go index 6b4388fccf4..45609488b46 100644 --- a/core/internal/testutils/testutils.go +++ b/core/internal/testutils/testutils.go @@ -367,15 +367,17 @@ func RequireLogMessage(t *testing.T, observedLogs *observer.ObservedLogs, msg st // // observedZapCore, observedLogs := observer.New(zap.DebugLevel) // lggr := logger.TestLogger(t, observedZapCore) -func WaitForLogMessage(t *testing.T, observedLogs *observer.ObservedLogs, msg string) { +func WaitForLogMessage(t *testing.T, observedLogs *observer.ObservedLogs, msg string) (le observer.LoggedEntry) { AssertEventually(t, func() bool { for _, l := range observedLogs.All() { if strings.Contains(l.Message, msg) { + le = l return true } } return false }) + return } // WaitForLogMessageCount waits until at least count log message containing the diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index 32bcc9f18a4..60381c0d479 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -69,6 +69,10 @@ type ChainsNodesStatuser interface { var _ RelayerChainInteroperators = &CoreRelayerChainInteroperators{} +type DummyFactory interface { + NewDummy(config DummyFactoryConfig) (loop.Relayer, error) +} + // CoreRelayerChainInteroperators implements [RelayerChainInteroperators] // as needed for the core [chainlink.Application] type CoreRelayerChainInteroperators struct { @@ -76,6 +80,8 @@ type CoreRelayerChainInteroperators struct { loopRelayers map[types.RelayID]loop.Relayer legacyChains legacyChains + dummyFactory DummyFactory + // we keep an explicit list of services because the legacy implementations have more than // just the relayer service srvs []services.ServiceCtx @@ -98,6 +104,14 @@ func NewCoreRelayerChainInteroperators(initFuncs ...CoreRelayerChainInitFunc) (* // CoreRelayerChainInitFunc is a hook in the constructor to create relayers from a factory. type CoreRelayerChainInitFunc func(op *CoreRelayerChainInteroperators) error +// InitDummy instantiates a dummy relayer +func InitDummy(ctx context.Context, factory RelayerFactory) CoreRelayerChainInitFunc { + return func(op *CoreRelayerChainInteroperators) error { + op.dummyFactory = &factory + return nil + } +} + // InitEVM is a option for instantiating evm relayers func InitEVM(ctx context.Context, factory RelayerFactory, config EVMFactoryConfig) CoreRelayerChainInitFunc { return func(op *CoreRelayerChainInteroperators) (err error) { @@ -178,6 +192,16 @@ func (rs *CoreRelayerChainInteroperators) Get(id types.RelayID) (loop.Relayer, e defer rs.mu.Unlock() lr, exist := rs.loopRelayers[id] if !exist { + // lazily create dummy relayers + if id.Network == "dummy" { + var err error + lr, err = rs.dummyFactory.NewDummy(DummyFactoryConfig{id.ChainID}) + if err != nil { + return nil, err + } + rs.loopRelayers[id] = lr + return lr, nil + } return nil, fmt.Errorf("%w: %s", ErrNoSuchRelayer, id) } return lr, nil diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index c4fbd26861e..aaf458c76c8 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -198,6 +198,10 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { expectedStarknetNodeCnt int expectedStarknetRelayerIds []types.RelayID + expectedDummyChainCnt int + expectedDummyNodeCnt int + expectedDummyRelayerIds []types.RelayID + expectedCosmosChainCnt int expectedCosmosNodeCnt int expectedCosmosRelayerIds []types.RelayID @@ -368,6 +372,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { expectedChainCnt, expectedNodeCnt = tt.expectedSolanaChainCnt, tt.expectedSolanaNodeCnt case relay.NetworkStarkNet: expectedChainCnt, expectedNodeCnt = tt.expectedStarknetChainCnt, tt.expectedStarknetNodeCnt + case relay.NetworkDummy: + expectedChainCnt, expectedNodeCnt = tt.expectedDummyChainCnt, tt.expectedDummyNodeCnt case relay.NetworkAptos: t.Skip("aptos doesn't need a CoreRelayerChainInteroperator") diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 9c17a5b2217..ae222f56c61 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -26,6 +26,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" corerelay "github.com/smartcontractkit/chainlink/v2/core/services/relay" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/dummy" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" "github.com/smartcontractkit/chainlink/v2/plugins" @@ -39,6 +40,14 @@ type RelayerFactory struct { CapabilitiesRegistry *capabilities.Registry } +type DummyFactoryConfig struct { + ChainID string +} + +func (r *RelayerFactory) NewDummy(config DummyFactoryConfig) (loop.Relayer, error) { + return dummy.NewRelayer(r.Logger, config.ChainID), nil +} + type EVMFactoryConfig struct { legacyevm.ChainOpts evmrelay.CSAETHKeystore diff --git a/core/services/llo/bm/dummy_transmitter.go b/core/services/llo/bm/dummy_transmitter.go index b998c19cb29..5573350b4e6 100644 --- a/core/services/llo/bm/dummy_transmitter.go +++ b/core/services/llo/bm/dummy_transmitter.go @@ -2,8 +2,6 @@ package bm import ( "context" - "crypto/ed25519" - "fmt" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -37,10 +35,10 @@ type transmitter struct { fromAccount string } -func NewTransmitter(lggr logger.Logger, fromAccount ed25519.PublicKey) Transmitter { +func NewTransmitter(lggr logger.Logger, fromAccount string) Transmitter { return &transmitter{ lggr.Named("DummyTransmitter"), - fmt.Sprintf("%x", fromAccount), + fromAccount, } } diff --git a/core/services/llo/bm/dummy_transmitter_test.go b/core/services/llo/bm/dummy_transmitter_test.go index 055b150ad13..e6c59e2f9e9 100644 --- a/core/services/llo/bm/dummy_transmitter_test.go +++ b/core/services/llo/bm/dummy_transmitter_test.go @@ -1,7 +1,6 @@ package bm import ( - "crypto/ed25519" "testing" "github.com/stretchr/testify/require" @@ -19,7 +18,7 @@ import ( func Test_DummyTransmitter(t *testing.T) { lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.DebugLevel) - tr := NewTransmitter(lggr, ed25519.PublicKey("dummy")) + tr := NewTransmitter(lggr, "dummy") servicetest.Run(t, tr) diff --git a/core/services/llo/data_source.go b/core/services/llo/data_source.go index a9c3744f9e3..30f646e1cb3 100644 --- a/core/services/llo/data_source.go +++ b/core/services/llo/data_source.go @@ -61,6 +61,8 @@ func (d *dataSource) Observe(ctx context.Context, streamIDs map[llotypes.StreamI sv := make(llo.StreamValues) var mu sync.Mutex + d.lggr.Debugw("Observing streams", "streamIDs", streamIDs) + for streamID := range streamIDs { go func(streamID llotypes.StreamID) { defer wg.Done() @@ -99,5 +101,7 @@ func (d *dataSource) Observe(ctx context.Context, streamIDs map[llotypes.StreamI wg.Wait() + d.lggr.Debugw("Observed streams", "streamIDs", streamIDs, "values", sv) + return sv, nil } diff --git a/core/services/llo/onchain_config.go b/core/services/llo/onchain_config.go new file mode 100644 index 00000000000..7b5cfffaa9f --- /dev/null +++ b/core/services/llo/onchain_config.go @@ -0,0 +1,21 @@ +package llo + +type OnchainConfig struct{} + +type OnchainConfigCodec interface { + Encode(OnchainConfig) ([]byte, error) + Decode([]byte) (OnchainConfig, error) +} + +var _ OnchainConfigCodec = &JSONOnchainConfigCodec{} + +// TODO: Replace this with protobuf, if it is actually used for something +type JSONOnchainConfigCodec struct{} + +func (c *JSONOnchainConfigCodec) Encode(OnchainConfig) ([]byte, error) { + return nil, nil +} + +func (c *JSONOnchainConfigCodec) Decode([]byte) (OnchainConfig, error) { + return OnchainConfig{}, nil +} diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index a1a1c41774f..875ee0f69ed 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -802,7 +802,7 @@ func (d *Delegate) newServicesMercury( return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "mercury"} } if rid.Network != relay.NetworkEVM { - return nil, fmt.Errorf("mercury services: expected EVM relayer got %s", rid.Network) + return nil, fmt.Errorf("mercury services: expected EVM relayer got %q", rid.Network) } relayer, err := d.RelayGetter.Get(rid) if err != nil { @@ -895,9 +895,6 @@ func (d *Delegate) newServicesLLO( if err != nil { return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "streams"} } - if rid.Network != relay.NetworkEVM { - return nil, fmt.Errorf("streams services: expected EVM relayer got %s", rid.Network) - } relayer, err := d.RelayGetter.Get(rid) if err != nil { return nil, ErrRelayNotEnabled{Err: err, Relay: spec.Relay, PluginName: "streams"} @@ -1079,7 +1076,7 @@ func (d *Delegate) newServicesDKG( return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "DKG"} } if rid.Network != relay.NetworkEVM { - return nil, fmt.Errorf("DKG services: expected EVM relayer got %s", rid.Network) + return nil, fmt.Errorf("DKG services: expected EVM relayer got %q", rid.Network) } chain, err2 := d.legacyChains.Get(rid.ChainID) @@ -1144,7 +1141,7 @@ func (d *Delegate) newServicesOCR2VRF( return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "VRF"} } if rid.Network != relay.NetworkEVM { - return nil, fmt.Errorf("VRF services: expected EVM relayer got %s", rid.Network) + return nil, fmt.Errorf("VRF services: expected EVM relayer got %q", rid.Network) } chain, err2 := d.legacyChains.Get(rid.ChainID) if err2 != nil { @@ -1358,7 +1355,7 @@ func (d *Delegate) newServicesOCR2Keepers21( return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "keeper2"} } if rid.Network != relay.NetworkEVM { - return nil, fmt.Errorf("keeper2 services: expected EVM relayer got %s", rid.Network) + return nil, fmt.Errorf("keeper2 services: expected EVM relayer got %q", rid.Network) } transmitterID := spec.TransmitterID.String @@ -1511,7 +1508,7 @@ func (d *Delegate) newServicesOCR2Keepers20( return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "keepers2.0"} } if rid.Network != relay.NetworkEVM { - return nil, fmt.Errorf("keepers2.0 services: expected EVM relayer got %s", rid.Network) + return nil, fmt.Errorf("keepers2.0 services: expected EVM relayer got %q", rid.Network) } chain, err2 := d.legacyChains.Get(rid.ChainID) if err2 != nil { @@ -1639,7 +1636,7 @@ func (d *Delegate) newServicesOCR2Functions( return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "functions"} } if rid.Network != relay.NetworkEVM { - return nil, fmt.Errorf("functions services: expected EVM relayer got %s", rid.Network) + return nil, fmt.Errorf("functions services: expected EVM relayer got %q", rid.Network) } chain, err := d.legacyChains.Get(rid.ChainID) if err != nil { diff --git a/core/services/ocr2/plugins/llo/config/config.go b/core/services/ocr2/plugins/llo/config/config.go index 1a6e528980b..892229c46c8 100644 --- a/core/services/ocr2/plugins/llo/config/config.go +++ b/core/services/ocr2/plugins/llo/config/config.go @@ -26,7 +26,7 @@ type PluginConfig struct { ChannelDefinitionsContractFromBlock int64 `json:"channelDefinitionsContractFromBlock" toml:"channelDefinitionsContractFromBlock"` // NOTE: ChannelDefinitions is an override. - // If Channe}lDefinitions is specified, values for + // If ChannelDefinitions is specified, values for // ChannelDefinitionsContractAddress and // ChannelDefinitionsContractFromBlock will be ignored ChannelDefinitions string `json:"channelDefinitions" toml:"channelDefinitions"` @@ -41,6 +41,10 @@ type PluginConfig struct { KeyBundleIDs map[string]string `json:"keyBundleIDs" toml:"keyBundleIDs"` } +func (p *PluginConfig) Unmarshal(data []byte) error { + return json.Unmarshal(data, p) +} + func (p PluginConfig) Validate() (merr error) { if p.RawServerURL == "" { merr = errors.New("llo: ServerURL must be specified") diff --git a/core/services/ocr2/plugins/llo/helpers_test.go b/core/services/ocr2/plugins/llo/helpers_test.go index 73f7fedc926..a29953d5d5d 100644 --- a/core/services/ocr2/plugins/llo/helpers_test.go +++ b/core/services/ocr2/plugins/llo/helpers_test.go @@ -130,6 +130,7 @@ type Node struct { App chainlink.Application ClientPubKey credentials.StaticSizedPublicKey KeyBundle ocr2key.KeyBundle + ObservedLogs *observer.ObservedLogs } func (node *Node) AddStreamJob(t *testing.T, spec string) { @@ -197,7 +198,11 @@ func setupNode( }) lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.DebugLevel) - app = cltest.NewApplicationWithConfigV2OnSimulatedBlockchain(t, config, backend, p2pKey, ocr2kb, csaKey, lggr.Named(dbName)) + if backend != nil { + app = cltest.NewApplicationWithConfigV2OnSimulatedBlockchain(t, config, backend, p2pKey, ocr2kb, csaKey, lggr.Named(dbName)) + } else { + app = cltest.NewApplicationWithConfig(t, config, p2pKey, ocr2kb, csaKey, lggr.Named(dbName)) + } err := app.Start(testutils.Context(t)) require.NoError(t, err) @@ -236,74 +241,79 @@ observationSource = """ bridgeName, )) } -func addBootstrapJob(t *testing.T, bootstrapNode Node, chainID *big.Int, verifierAddress common.Address, name string) { + +func addBootstrapJob(t *testing.T, bootstrapNode Node, verifierAddress common.Address, name string, relayType, relayConfig string) { bootstrapNode.AddBootstrapJob(t, fmt.Sprintf(` type = "bootstrap" -relay = "evm" +relay = "%s" schemaVersion = 1 name = "boot-%s" contractID = "%s" contractConfigTrackerPollInterval = "1s" [relayConfig] -chainID = %s -providerType = "llo" - `, name, verifierAddress.Hex(), chainID.String())) +%s +providerType = "llo"`, relayType, name, verifierAddress.Hex(), relayConfig)) } func addLLOJob( t *testing.T, node Node, - verifierAddress, - configStoreAddress common.Address, + verifierAddress common.Address, bootstrapPeerID string, bootstrapNodePort int, - serverURL string, - serverPubKey, clientPubKey ed25519.PublicKey, jobName string, - chainID *big.Int, - fromBlock int, + pluginConfig, + relayType, + relayConfig string, ) { node.AddLLOJob(t, fmt.Sprintf(` type = "offchainreporting2" schemaVersion = 1 -name = "%[1]s" +name = "%s" forwardingAllowed = false maxTaskDuration = "1s" -contractID = "%[2]s" +contractID = "%s" contractConfigTrackerPollInterval = "1s" -ocrKeyBundleID = "%[3]s" +ocrKeyBundleID = "%s" p2pv2Bootstrappers = [ - "%[4]s" + "%s" ] -relay = "evm" +relay = "%s" pluginType = "llo" -transmitterID = "%[5]x" +transmitterID = "%x" [pluginConfig] -serverURL = "%[6]s" -serverPubKey = "%[7]x" -channelDefinitionsContractFromBlock = %[8]d -channelDefinitionsContractAddress = "%[9]s" +%s [relayConfig] -chainID = %[10]s -fromBlock = 1`, +%s`, jobName, verifierAddress.Hex(), node.KeyBundle.ID(), fmt.Sprintf("%s@127.0.0.1:%d", bootstrapPeerID, bootstrapNodePort), + relayType, clientPubKey, - serverURL, - serverPubKey, - fromBlock, - configStoreAddress.Hex(), - chainID.String(), + pluginConfig, + relayConfig, )) } -func addOCRJobs(t *testing.T, streams []Stream, serverPubKey ed25519.PublicKey, serverURL string, verifierAddress common.Address, bootstrapPeerID string, bootstrapNodePort int, nodes []Node, configStoreAddress common.Address, clientPubKeys []ed25519.PublicKey, chainID *big.Int, fromBlock int) { +func addOCRJobs( + t *testing.T, + streams []Stream, + serverPubKey ed25519.PublicKey, + serverURL string, + verifierAddress common.Address, + bootstrapPeerID string, + bootstrapNodePort int, + nodes []Node, + configStoreAddress common.Address, + clientPubKeys []ed25519.PublicKey, + pluginConfig, + relayType, + relayConfig string) { ctx := testutils.Context(t) createBridge := func(name string, i int, p *big.Int, borm bridges.ORM) (bridgeName string) { bridge := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { @@ -343,15 +353,13 @@ func addOCRJobs(t *testing.T, streams []Stream, serverPubKey ed25519.PublicKey, t, node, verifierAddress, - configStoreAddress, bootstrapPeerID, bootstrapNodePort, - serverURL, - serverPubKey, clientPubKeys[i], "feed-1", - chainID, - fromBlock, + pluginConfig, + relayType, + relayConfig, ) } } diff --git a/core/services/ocr2/plugins/llo/integration_test.go b/core/services/ocr2/plugins/llo/integration_test.go index fd955879f56..d80a422e680 100644 --- a/core/services/ocr2/plugins/llo/integration_test.go +++ b/core/services/ocr2/plugins/llo/integration_test.go @@ -3,6 +3,7 @@ package llo_test import ( "crypto/ed25519" "encoding/hex" + "encoding/json" "fmt" "math/big" "math/rand" @@ -20,6 +21,7 @@ import ( "github.com/stretchr/testify/require" chainselectors "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/libocr/offchainreporting2/types" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -72,28 +74,31 @@ type Stream struct { baseBenchmarkPrice *big.Int } -func TestIntegration_LLO(t *testing.T) { - testStartTimeStamp := uint32(time.Now().Unix()) - - const fromBlock = 1 // cannot use zero, start from block 1 - - // streams - btcStream := Stream{ +var ( + btcStream = Stream{ id: 51, baseBenchmarkPrice: big.NewInt(20_000 * multiplier), } - ethStream := Stream{ + ethStream = Stream{ id: 52, baseBenchmarkPrice: big.NewInt(1_568 * multiplier), } - linkStream := Stream{ + linkStream = Stream{ id: 53, baseBenchmarkPrice: big.NewInt(7150 * multiplier / 1000), } - dogeStream := Stream{ + dogeStream = Stream{ id: 54, baseBenchmarkPrice: big.NewInt(2_020 * multiplier), } +) + +func TestIntegration_LLO(t *testing.T) { + testStartTimeStamp := uint32(time.Now().Unix()) + + const fromBlock = 1 // cannot use zero, start from block 1 + + // streams streams := []Stream{btcStream, ethStream, linkStream, dogeStream} streamMap := make(map[uint32]Stream) for _, strm := range streams { @@ -131,10 +136,10 @@ func TestIntegration_LLO(t *testing.T) { ) ports := freeport.GetN(t, nNodes) for i := 0; i < nNodes; i++ { - app, peerID, transmitter, kb, _ := setupNode(t, ports[i], fmt.Sprintf("oracle_streams_%d", i), backend, clientCSAKeys[i]) + app, peerID, transmitter, kb, observedLogs := setupNode(t, ports[i], fmt.Sprintf("oracle_streams_%d", i), backend, clientCSAKeys[i]) nodes = append(nodes, Node{ - app, transmitter, kb, + app, transmitter, kb, observedLogs, }) offchainPublicKey, _ := hex.DecodeString(strings.TrimPrefix(kb.OnChainPublicKey(), "0x")) oracles = append(oracles, confighelper.OracleIdentityExtra{ @@ -159,8 +164,16 @@ func TestIntegration_LLO(t *testing.T) { configDigest := setConfig(t, steve, backend, verifierContract, verifierAddress, nodes, oracles) channelDefinitions := setChannelDefinitions(t, steve, backend, configStoreContract, streams) - addBootstrapJob(t, bootstrapNode, chainID, verifierAddress, "job-1") - addOCRJobs(t, streams, serverPubKey, serverURL, verifierAddress, bootstrapPeerID, bootstrapNodePort, nodes, configStoreAddress, clientPubKeys, chainID, fromBlock) + relayType := "evm" + relayConfig := fmt.Sprintf(`chainID = %s +fromBlock = %d`, chainID.String(), fromBlock) + addBootstrapJob(t, bootstrapNode, verifierAddress, "job-1", relayType, relayConfig) + + pluginConfig := fmt.Sprintf(`serverURL = "%s" +serverPubKey = "%x" +channelDefinitionsContractFromBlock = %d +channelDefinitionsContractAddress = "%s"`, serverURL, serverPubKey, fromBlock, configStoreAddress.String()) + addOCRJobs(t, streams, serverPubKey, serverURL, verifierAddress, bootstrapPeerID, bootstrapNodePort, nodes, configStoreAddress, clientPubKeys, pluginConfig, relayType, relayConfig) t.Run("receives at least one report per feed from each oracle when EAs are at 100% reliability", func(t *testing.T) { // Expect at least one report per channel from each oracle (keyed by transmitter ID) seen := make(map[ocr2types.Account]map[llotypes.ChannelID]struct{}) @@ -254,17 +267,24 @@ func TestIntegration_LLO(t *testing.T) { // TODO: test verification } -func setConfig(t *testing.T, steve *bind.TransactOpts, backend *backends.SimulatedBackend, verifierContract *channel_verifier.ChannelVerifier, verifierAddress common.Address, nodes []Node, oracles []confighelper.OracleIdentityExtra) ocr2types.ConfigDigest { +func generateConfig(t *testing.T, nodes []Node, oracles []confighelper.OracleIdentityExtra) ( + signers []types.OnchainPublicKey, + transmitters []types.Account, + f uint8, + onchainConfig []byte, + offchainConfigVersion uint64, + offchainConfig []byte, +) { // Setup config on contract - rawOnchainConfig := datastreamsllo.OnchainConfig{} - onchainConfig, err := (&datastreamsllo.JSONOnchainConfigCodec{}).Encode(rawOnchainConfig) + rawOnchainConfig := llo.OnchainConfig{} + onchainConfig, err := (&llo.JSONOnchainConfigCodec{}).Encode(rawOnchainConfig) require.NoError(t, err) rawReportingPluginConfig := datastreamsllo.OffchainConfig{} reportingPluginConfig, err := rawReportingPluginConfig.Encode() require.NoError(t, err) - signers, _, _, _, offchainConfigVersion, offchainConfig, err := ocr3confighelper.ContractSetConfigArgsForTests( + signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig, err = ocr3confighelper.ContractSetConfigArgsForTests( 2*time.Second, // DeltaProgress 20*time.Second, // DeltaResend 400*time.Millisecond, // DeltaInitial @@ -285,24 +305,24 @@ func setConfig(t *testing.T, steve *bind.TransactOpts, backend *backends.Simulat ) require.NoError(t, err) + + return +} + +func setConfig(t *testing.T, steve *bind.TransactOpts, backend *backends.SimulatedBackend, verifierContract *channel_verifier.ChannelVerifier, verifierAddress common.Address, nodes []Node, oracles []confighelper.OracleIdentityExtra) ocr2types.ConfigDigest { + signers, _, _, _, offchainConfigVersion, offchainConfig := generateConfig(t, nodes, oracles) + signerAddresses, err := evm.OnchainPublicKeyToAddress(signers) require.NoError(t, err) - offchainTransmitters := make([][32]byte, nNodes) for i := 0; i < nNodes; i++ { offchainTransmitters[i] = nodes[i].ClientPubKey } - _, err = verifierContract.SetConfig(steve, signerAddresses, offchainTransmitters, fNodes, offchainConfig, offchainConfigVersion, offchainConfig, nil) require.NoError(t, err) backend.Commit() - accounts := make([]ocr2types.Account, len(offchainTransmitters)) - for i := range offchainTransmitters { - accounts[i] = ocr2types.Account(fmt.Sprintf("%x", offchainTransmitters[i])) - } - l, err := verifierContract.LatestConfigDigestAndEpoch(&bind.CallOpts{}) require.NoError(t, err) @@ -367,3 +387,136 @@ func setChannelDefinitions(t *testing.T, steve *bind.TransactOpts, backend *back return channelDefinitions } + +func TestIntegration_LLO_Dummy(t *testing.T) { + testStartTimeStamp := time.Now() + + streams := []Stream{btcStream, ethStream, linkStream, dogeStream} + streamMap := make(map[uint32]Stream) + for _, strm := range streams { + streamMap[strm.id] = strm + } + + clientCSAKeys := make([]csakey.KeyV2, nNodes) + clientPubKeys := make([]ed25519.PublicKey, nNodes) + for i := 0; i < nNodes; i++ { + k := big.NewInt(int64(i)) + key := csakey.MustNewV2XXXTestingOnly(k) + clientCSAKeys[i] = key + clientPubKeys[i] = key.PublicKey + } + + // Setup bootstrap + bootstrapCSAKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) + bootstrapNodePort := freeport.GetOne(t) + appBootstrap, bootstrapPeerID, _, bootstrapKb, _ := setupNode(t, bootstrapNodePort, "bootstrap_mercury", nil, bootstrapCSAKey) + bootstrapNode := Node{App: appBootstrap, KeyBundle: bootstrapKb} + + t.Run("with at least one channel", func(t *testing.T) { + // Setup oracle nodes + var ( + oracles []confighelper.OracleIdentityExtra + nodes []Node + ) + ports := freeport.GetN(t, nNodes) + for i := 0; i < nNodes; i++ { + app, peerID, transmitter, kb, observedLogs := setupNode(t, ports[i], fmt.Sprintf("oracle_streams_%d", i), nil, clientCSAKeys[i]) + + nodes = append(nodes, Node{ + app, transmitter, kb, observedLogs, + }) + offchainPublicKey, _ := hex.DecodeString(strings.TrimPrefix(kb.OnChainPublicKey(), "0x")) + oracles = append(oracles, confighelper.OracleIdentityExtra{ + OracleIdentity: confighelper.OracleIdentity{ + OnchainPublicKey: offchainPublicKey, + TransmitAccount: ocr2types.Account(fmt.Sprintf("%x", transmitter[:])), + OffchainPublicKey: kb.OffchainPublicKey(), + PeerID: peerID, + }, + ConfigEncryptionPublicKey: kb.ConfigEncryptionPublicKey(), + }) + } + + verifierAddress := common.Address{} + chainID := "llo-dummy" + relayType := "dummy" + cd := "0x0102030405060708010203040506070801020304050607080102030405060708" + signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig := generateConfig(t, nodes, oracles) + var signersMarshalled, transmittersMarshalled []byte + { + var err error + signersHex := make([]string, len(signers)) + for i, signer := range signers { + signersHex[i] = fmt.Sprintf("0x%x", signer) + } + signersMarshalled, err = json.Marshal(signersHex) + require.NoError(t, err) + + transmittersMarshalled, err = json.Marshal(transmitters) + require.NoError(t, err) + } + + relayConfig := fmt.Sprintf(`chainID = "%s" +configTracker = { + configDigest = "%s", + configCoung = 1, + signers = %s, + transmitters = %s, + f = %d, + onchainConfig = "0x%x", + offchainConfigVersion = %d, + offchainConfig = "0x%x", + blockHeight = 10 +}`, chainID, cd, string(signersMarshalled), string(transmittersMarshalled), f, onchainConfig, offchainConfigVersion, offchainConfig) + addBootstrapJob(t, bootstrapNode, verifierAddress, "job-1", relayType, relayConfig) + + serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) + serverPubKey := serverKey.PublicKey + serverURL := "foo" + configStoreAddress := common.Address{} + + // NOTE: Don't actually care about the chain ID, it just needs to be + // a valid chainSelector + chainSelector, err := chainselectors.SelectorFromChainId(testutils.SimulatedChainID.Uint64()) + require.NoError(t, err) + + channelDefinitions := fmt.Sprintf(`{ +"42": { + "reportFormat": %d, + "chainSelector": %d, + "streamIds": [51, 52] + } +}`, llotypes.ReportFormatJSON, chainSelector) + + pluginConfig := fmt.Sprintf(`serverURL = "foo" +serverPubKey = "%x" +channelDefinitions = %q`, serverPubKey, channelDefinitions) + addOCRJobs(t, streams, serverPubKey, serverURL, verifierAddress, bootstrapPeerID, bootstrapNodePort, nodes, configStoreAddress, clientPubKeys, pluginConfig, relayType, relayConfig) + + for _, node := range nodes { + le := testutils.WaitForLogMessage(t, node.ObservedLogs, "Transmit") + fields := le.ContextMap() + assert.Equal(t, cd[2:], fields["digest"]) + assert.Equal(t, llotypes.ReportInfo{LifeCycleStage: "production", ReportFormat: llotypes.ReportFormatJSON}, fields["report.Info"]) + + binaryReport := fields["report.Report"].(types.Report) + report, err := (datastreamsllo.JSONReportCodec{}).Decode(binaryReport) + require.NoError(t, err) + assert.Equal(t, datastreamsllo.Report{ + ConfigDigest: types.ConfigDigest{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, + ChainSelector: 0x2ee634951ef71b46, + SeqNr: fields["seqNr"].(uint64), + ChannelID: 0x2a, + ValidAfterSeconds: report.ValidAfterSeconds, // tested separately below + ValidUntilSeconds: report.ValidUntilSeconds, // tested separately below + Values: []*big.Int{big.NewInt(2000002000000), big.NewInt(156802000000)}, + Specimen: false, + }, report) + assert.GreaterOrEqual(t, report.ValidUntilSeconds, uint32(testStartTimeStamp.Unix())) + assert.GreaterOrEqual(t, report.ValidAfterSeconds, uint32(testStartTimeStamp.Unix())) + assert.GreaterOrEqual(t, report.ValidUntilSeconds, report.ValidAfterSeconds) + + assert.GreaterOrEqual(t, int(fields["seqNr"].(uint64)), 0) + } + }) +} diff --git a/core/services/relay/dummy/config_digester.go b/core/services/relay/dummy/config_digester.go new file mode 100644 index 00000000000..a74e007b0ba --- /dev/null +++ b/core/services/relay/dummy/config_digester.go @@ -0,0 +1,26 @@ +package dummy + +import ( + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +// Stub config digester that uses a static config digest + +type configDigester struct { + configDigest ocrtypes.ConfigDigest +} + +func NewOffchainConfigDigester(cd ocrtypes.ConfigDigest) (ocrtypes.OffchainConfigDigester, error) { + return &configDigester{cd}, nil +} + +// Compute ConfigDigest for the given ContractConfig. The first two bytes of the +// ConfigDigest must be the big-endian encoding of ConfigDigestPrefix! +func (cd *configDigester) ConfigDigest(ocrtypes.ContractConfig) (ocrtypes.ConfigDigest, error) { + return cd.configDigest, nil +} + +// This should return the same constant value on every invocation +func (cd *configDigester) ConfigDigestPrefix() (ocrtypes.ConfigDigestPrefix, error) { + return ocrtypes.ConfigDigestPrefixFromConfigDigest(cd.configDigest), nil +} diff --git a/core/services/relay/dummy/config_provider.go b/core/services/relay/dummy/config_provider.go new file mode 100644 index 00000000000..10662ee296d --- /dev/null +++ b/core/services/relay/dummy/config_provider.go @@ -0,0 +1,97 @@ +package dummy + +import ( + "context" + + "github.com/ethereum/go-ethereum/common/hexutil" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + + "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +// Stub ConfigTracker that uses static config + +// interim struct used for unmarshalling from relay config +type ConfigTrackerCfg struct { + // OCR Config + ConfigDigest hexutil.Bytes + ConfigCount uint64 + Signers []hexutil.Bytes + Transmitters []string + F uint8 + OnchainConfig hexutil.Bytes + OffchainConfigVersion uint64 + OffchainConfig hexutil.Bytes + + // Tracker config + ChangedInBlock uint64 + BlockHeight uint64 +} + +func (cfg ConfigTrackerCfg) ToContractConfig() (ocrtypes.ContractConfig, error) { + cd, err := ocrtypes.BytesToConfigDigest(cfg.ConfigDigest) + if err != nil { + return ocrtypes.ContractConfig{}, err + } + signers := make([]ocrtypes.OnchainPublicKey, len(cfg.Signers)) + for i, s := range cfg.Signers { + signers[i] = ocrtypes.OnchainPublicKey(s) + } + transmitters := make([]ocrtypes.Account, len(cfg.Transmitters)) + for i, t := range cfg.Transmitters { + transmitters[i] = ocrtypes.Account(t) + } + return ocrtypes.ContractConfig{ + ConfigDigest: cd, + ConfigCount: cfg.ConfigCount, + Signers: signers, + Transmitters: transmitters, + F: cfg.F, + OnchainConfig: cfg.OnchainConfig, + OffchainConfigVersion: cfg.OffchainConfigVersion, + OffchainConfig: cfg.OffchainConfig, + }, nil +} + +type configProvider struct { + lggr logger.Logger + + digester ocrtypes.OffchainConfigDigester + tracker ocrtypes.ContractConfigTracker +} + +func NewConfigProvider(lggr logger.Logger, cfg RelayConfig) (types.ConfigProvider, error) { + cp := &configProvider{lggr: lggr.Named("DummyConfigProvider")} + + { + contractConfig, err := cfg.ConfigTracker.ToContractConfig() + if err != nil { + return nil, err + } + + cp.digester, err = NewOffchainConfigDigester(contractConfig.ConfigDigest) + if err != nil { + return nil, err + } + } + var err error + cp.tracker, err = NewContractConfigTracker(cp.lggr, cfg.ConfigTracker) + if err != nil { + return nil, err + } + return cp, nil +} + +func (cp *configProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigester { + return cp.digester +} +func (cp *configProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker { return cp.tracker } +func (cp *configProvider) Name() string { return cp.lggr.Name() } +func (*configProvider) Start(context.Context) error { return nil } +func (*configProvider) Close() error { return nil } +func (*configProvider) Ready() error { return nil } +func (cp *configProvider) HealthReport() map[string]error { + return map[string]error{cp.lggr.Name(): nil} +} diff --git a/core/services/relay/dummy/config_tracker.go b/core/services/relay/dummy/config_tracker.go new file mode 100644 index 00000000000..0ae188361fa --- /dev/null +++ b/core/services/relay/dummy/config_tracker.go @@ -0,0 +1,51 @@ +package dummy + +import ( + "context" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +type configTracker struct { + lggr logger.Logger + cfg ocrtypes.ContractConfig + + changedInBlock uint64 + blockHeight uint64 +} + +func NewContractConfigTracker(lggr logger.Logger, cfg ConfigTrackerCfg) (ocrtypes.ContractConfigTracker, error) { + contractConfig, err := cfg.ToContractConfig() + if err != nil { + return nil, err + } + return &configTracker{lggr.Named("DummyConfigProvider"), contractConfig, cfg.ChangedInBlock, cfg.BlockHeight}, nil +} + +// Notify may optionally emit notification events when the contract's +// configuration changes. This is purely used as an optimization reducing +// the delay between a configuration change and its enactment. Implementors +// who don't care about this may simply return a nil channel. +// +// The returned channel should never be closed. +func (ct *configTracker) Notify() <-chan struct{} { + return nil +} + +// LatestConfigDetails returns information about the latest configuration, +// but not the configuration itself. +func (ct *configTracker) LatestConfigDetails(ctx context.Context) (changedInBlock uint64, configDigest ocrtypes.ConfigDigest, err error) { + return ct.changedInBlock, ct.cfg.ConfigDigest, nil +} + +// LatestConfig returns the latest configuration. +func (ct *configTracker) LatestConfig(ctx context.Context, changedInBlock uint64) (ocrtypes.ContractConfig, error) { + return ct.cfg, nil +} + +// LatestBlockHeight returns the height of the most recent block in the chain. +func (ct *configTracker) LatestBlockHeight(ctx context.Context) (blockHeight uint64, err error) { + return ct.blockHeight, nil // set LatestBlockHeight to a high number so that OCR considers it to be confirmed +} diff --git a/core/services/relay/dummy/llo_provider.go b/core/services/relay/dummy/llo_provider.go new file mode 100644 index 00000000000..4aeb21bed8a --- /dev/null +++ b/core/services/relay/dummy/llo_provider.go @@ -0,0 +1,86 @@ +package dummy + +import ( + "context" + "errors" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink-common/pkg/services" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + relaytypes "github.com/smartcontractkit/chainlink-common/pkg/types" + llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/llo" +) + +var _ commontypes.LLOProvider = (*lloProvider)(nil) + +type lloProvider struct { + cp commontypes.ConfigProvider + transmitter llo.Transmitter + logger logger.Logger + channelDefinitionCache llotypes.ChannelDefinitionCache + + ms services.MultiStart +} + +func NewLLOProvider( + lggr logger.Logger, + cp commontypes.ConfigProvider, + transmitter llo.Transmitter, + channelDefinitionCache llotypes.ChannelDefinitionCache, +) relaytypes.LLOProvider { + return &lloProvider{ + cp, + transmitter, + lggr.Named("LLOProvider"), + channelDefinitionCache, + services.MultiStart{}, + } +} + +func (p *lloProvider) Start(ctx context.Context) error { + err := p.ms.Start(ctx, p.cp, p.transmitter, p.channelDefinitionCache) + return err +} + +func (p *lloProvider) Close() error { + return p.ms.Close() +} + +func (p *lloProvider) Ready() error { + return errors.Join(p.cp.Ready(), p.transmitter.Ready(), p.channelDefinitionCache.Ready()) +} + +func (p *lloProvider) Name() string { + return p.logger.Name() +} + +func (p *lloProvider) HealthReport() map[string]error { + report := map[string]error{p.Name(): nil} + services.CopyHealth(report, p.cp.HealthReport()) + services.CopyHealth(report, p.transmitter.HealthReport()) + services.CopyHealth(report, p.channelDefinitionCache.HealthReport()) + return report +} + +func (p *lloProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker { + return p.cp.ContractConfigTracker() +} + +func (p *lloProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigester { + return p.cp.OffchainConfigDigester() +} + +func (p *lloProvider) OnchainConfigCodec() llo.OnchainConfigCodec { + return &llo.JSONOnchainConfigCodec{} +} + +func (p *lloProvider) ContractTransmitter() llotypes.Transmitter { + return p.transmitter +} + +func (p *lloProvider) ChannelDefinitionCache() llotypes.ChannelDefinitionCache { + return p.channelDefinitionCache +} diff --git a/core/services/relay/dummy/relayer.go b/core/services/relay/dummy/relayer.go new file mode 100644 index 00000000000..9818eabb201 --- /dev/null +++ b/core/services/relay/dummy/relayer.go @@ -0,0 +1,78 @@ +package dummy + +import ( + "context" + "encoding/json" + "math/big" + + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/llo" + "github.com/smartcontractkit/chainlink/v2/core/services/llo/bm" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/llo/config" +) + +// The dummy relayer is a simple reference implementation that doesn't actually +// connect to any chain. It's useful for testing and as a reference for +// implementing a new relayer. + +type RelayConfig struct { + ConfigTracker ConfigTrackerCfg +} + +type relayer struct { + lggr logger.Logger + chainID string +} + +func NewRelayer(lggr logger.Logger, chainID string) loop.Relayer { + return &relayer{lggr, chainID} +} + +func (r *relayer) NewContractReader(ctx context.Context, contractReaderConfig []byte) (types.ContractReader, error) { + return nil, nil +} +func (r *relayer) NewConfigProvider(_ context.Context, rargs types.RelayArgs) (types.ConfigProvider, error) { + var cfg RelayConfig + if err := json.Unmarshal(rargs.RelayConfig, &cfg); err != nil { + return nil, err + } + return NewConfigProvider(r.lggr, cfg) +} +func (r *relayer) NewPluginProvider(context.Context, types.RelayArgs, types.PluginArgs) (types.PluginProvider, error) { + return nil, nil +} +func (r *relayer) NewLLOProvider(ctx context.Context, rargs types.RelayArgs, pargs types.PluginArgs) (types.LLOProvider, error) { + cp, err := r.NewConfigProvider(ctx, rargs) + if err != nil { + return nil, err + } + transmitter := bm.NewTransmitter(r.lggr, pargs.TransmitterID) + pluginCfg := new(config.PluginConfig) + if err = pluginCfg.Unmarshal(pargs.PluginConfig); err != nil { + return nil, err + } + cdc, err := llo.NewStaticChannelDefinitionCache(r.lggr, pluginCfg.ChannelDefinitions) + if err != nil { + return nil, err + } + return NewLLOProvider(r.lggr, cp, transmitter, cdc), nil +} +func (r *relayer) GetChainStatus(ctx context.Context) (types.ChainStatus, error) { + return types.ChainStatus{}, nil +} +func (r *relayer) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []types.NodeStatus, nextPageToken string, total int, err error) { + return nil, "", 0, nil +} +func (r *relayer) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { + return nil +} +func (r *relayer) Name() string { return r.lggr.Name() } +func (r *relayer) Start(context.Context) error { return nil } +func (r *relayer) Close() error { return nil } +func (r *relayer) Ready() error { return nil } +func (r *relayer) HealthReport() map[string]error { + return map[string]error{r.lggr.Name(): nil} +} diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 61c484f82b2..e6732a81cfd 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -357,7 +357,7 @@ func (r *Relayer) NewLLOProvider(rargs commontypes.RelayArgs, pargs commontypes. var transmitter llo.Transmitter if lloCfg.BenchmarkMode { r.lggr.Info("Benchmark mode enabled, using dummy transmitter. NOTE: THIS WILL NOT TRANSMIT ANYTHING") - transmitter = bm.NewTransmitter(r.lggr, privKey.PublicKey) + transmitter = bm.NewTransmitter(r.lggr, fmt.Sprintf("%x", privKey.PublicKey)) } else { var client wsrpc.Client client, err = r.mercuryPool.Checkout(context.Background(), privKey, lloCfg.ServerPubKey, lloCfg.ServerURL()) diff --git a/core/services/relay/evm/llo_provider.go b/core/services/relay/evm/llo_provider.go index 0ab0773a160..b685565e6e0 100644 --- a/core/services/relay/evm/llo_provider.go +++ b/core/services/relay/evm/llo_provider.go @@ -10,7 +10,6 @@ import ( commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" relaytypes "github.com/smartcontractkit/chainlink-common/pkg/types" llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo" - datastreamsllo "github.com/smartcontractkit/chainlink-data-streams/llo" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/llo" @@ -75,10 +74,8 @@ func (p *lloProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigester { return p.cp.OffchainConfigDigester() } -func (p *lloProvider) OnchainConfigCodec() datastreamsllo.OnchainConfigCodec { - // TODO: This should probably be moved to core since its chain-specific - // https://smartcontract-it.atlassian.net/browse/MERC-3661 - return &datastreamsllo.JSONOnchainConfigCodec{} +func (p *lloProvider) OnchainConfigCodec() llo.OnchainConfigCodec { + return &llo.JSONOnchainConfigCodec{} } func (p *lloProvider) ContractTransmitter() llotypes.Transmitter { diff --git a/core/services/relay/relay.go b/core/services/relay/relay.go index de3f80a5e78..a2681418cee 100644 --- a/core/services/relay/relay.go +++ b/core/services/relay/relay.go @@ -6,6 +6,8 @@ const ( NetworkSolana = "solana" NetworkStarkNet = "starknet" NetworkAptos = "aptos" + + NetworkDummy = "dummy" ) var SupportedNetworks = map[string]struct{}{ @@ -14,4 +16,6 @@ var SupportedNetworks = map[string]struct{}{ NetworkSolana: {}, NetworkStarkNet: {}, NetworkAptos: {}, + + NetworkDummy: {}, }