diff --git a/.changeset/cyan-items-lie.md b/.changeset/cyan-items-lie.md new file mode 100644 index 00000000000..a15954c2951 --- /dev/null +++ b/.changeset/cyan-items-lie.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#breaking_change Remove the `xdai` `ChainType` config option. Moving forward, only `gnosis` can be used. diff --git a/.changeset/fast-kings-compete.md b/.changeset/fast-kings-compete.md new file mode 100644 index 00000000000..941e8a802c3 --- /dev/null +++ b/.changeset/fast-kings-compete.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#internal keystone: handle local target transmission logic in capability wrapper diff --git a/.changeset/lazy-ravens-hide.md b/.changeset/lazy-ravens-hide.md new file mode 100644 index 00000000000..45bd44646e1 --- /dev/null +++ b/.changeset/lazy-ravens-hide.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +bump chainlink-starknet so it builds reports with median gas price #updated diff --git a/.changeset/neat-zebras-fix.md b/.changeset/neat-zebras-fix.md new file mode 100644 index 00000000000..022fd44a137 --- /dev/null +++ b/.changeset/neat-zebras-fix.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#updated Remove deprecated app.shortcut links diff --git a/.changeset/olive-knives-happen.md b/.changeset/olive-knives-happen.md new file mode 100644 index 00000000000..7f522c96ff1 --- /dev/null +++ b/.changeset/olive-knives-happen.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#internal Generic Plugin `onchainSigningStrategy` support diff --git a/common/config/chaintype.go b/common/config/chaintype.go index 1ddb3f626b5..8c89aeb4ecd 100644 --- a/common/config/chaintype.go +++ b/common/config/chaintype.go @@ -47,7 +47,7 @@ func ChainTypeFromSlug(slug string) ChainType { return ChainArbitrum case "celo": return ChainCelo - case "gnosis", "xdai": + case "gnosis": return ChainGnosis case "kroma": return ChainKroma diff --git a/contracts/test/v0.8/automation/CronUpkeep.test.ts b/contracts/test/v0.8/automation/CronUpkeep.test.ts index 9c0192e61e7..7b769797f12 100644 --- a/contracts/test/v0.8/automation/CronUpkeep.test.ts +++ b/contracts/test/v0.8/automation/CronUpkeep.test.ts @@ -117,7 +117,7 @@ describe('CronUpkeep', () => { it('has a limited public ABI [ @skip-coverage ]', () => { // Casting cron is necessary due to a tricky versioning mismatch issue, likely between ethers // and typechain. Remove once the version issue is resolved. - // https://app.shortcut.com/chainlinklabs/story/21905/remove-contract-cast-in-cronupkeep-test-ts + // https://smartcontract-it.atlassian.net/browse/ARCHIVE-22094 h.publicAbi(cron as unknown as Contract, [ 's_maxJobs', 'performUpkeep', diff --git a/core/capabilities/registry.go b/core/capabilities/registry.go index 3c7bdf2c971..4e3877f0c5f 100644 --- a/core/capabilities/registry.go +++ b/core/capabilities/registry.go @@ -6,15 +6,20 @@ import ( "sync" "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/transmission" "github.com/smartcontractkit/chainlink/v2/core/logger" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" ) // Registry is a struct for the registry of capabilities. // Registry is safe for concurrent use. type Registry struct { - m map[string]capabilities.BaseCapability - mu sync.RWMutex - lggr logger.Logger + lggr logger.Logger + peerID p2ptypes.PeerID + don capabilities.DON + + m map[string]capabilities.BaseCapability + mu sync.RWMutex } // Get gets a capability from the registry. @@ -134,6 +139,17 @@ func (r *Registry) Add(ctx context.Context, c capabilities.BaseCapability) error if !ok { return fmt.Errorf("target capability does not satisfy TargetCapability interface") } + + capInfo, err := c.Info(ctx) + if err != nil { + return fmt.Errorf("failed to get info of target capability: %w", err) + } + + // If the DON is nil this is a local capability and requires wrapping in a local target transmission capability + if capInfo.DON == nil { + c = transmission.NewLocalTargetCapability(r.lggr, r.peerID, r.don, c.(capabilities.TargetCapability)) + } + default: return fmt.Errorf("unknown capability type: %s", info.CapabilityType) } @@ -150,9 +166,11 @@ func (r *Registry) Add(ctx context.Context, c capabilities.BaseCapability) error } // NewRegistry returns a new Registry. -func NewRegistry(lggr logger.Logger) *Registry { +func NewRegistry(lggr logger.Logger, peerID p2ptypes.PeerID, don capabilities.DON) *Registry { return &Registry{ - m: map[string]capabilities.BaseCapability{}, - lggr: lggr.Named("CapabilityRegistry"), + m: map[string]capabilities.BaseCapability{}, + lggr: lggr.Named("CapabilityRegistry"), + peerID: peerID, + don: don, } } diff --git a/core/capabilities/registry_test.go b/core/capabilities/registry_test.go index 3bed31a957a..db366bf41ec 100644 --- a/core/capabilities/registry_test.go +++ b/core/capabilities/registry_test.go @@ -10,9 +10,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers" + "github.com/smartcontractkit/chainlink-common/pkg/values" coreCapabilities "github.com/smartcontractkit/chainlink/v2/core/capabilities" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/transmission" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" ) type mockCapability struct { @@ -34,7 +37,7 @@ func (m *mockCapability) UnregisterFromWorkflow(ctx context.Context, request cap func TestRegistry(t *testing.T) { ctx := testutils.Context(t) - r := coreCapabilities.NewRegistry(logger.TestLogger(t)) + r := coreCapabilities.NewRegistry(logger.TestLogger(t), p2ptypes.PeerID{}, capabilities.DON{}) id := "capability-1" ci, err := capabilities.NewCapabilityInfo( @@ -62,7 +65,7 @@ func TestRegistry(t *testing.T) { func TestRegistry_NoDuplicateIDs(t *testing.T) { ctx := testutils.Context(t) - r := coreCapabilities.NewRegistry(logger.TestLogger(t)) + r := coreCapabilities.NewRegistry(logger.TestLogger(t), p2ptypes.PeerID{}, capabilities.DON{}) id := "capability-1" ci, err := capabilities.NewCapabilityInfo( @@ -173,7 +176,7 @@ func TestRegistry_ChecksExecutionAPIByType(t *testing.T) { } ctx := testutils.Context(t) - reg := coreCapabilities.NewRegistry(logger.TestLogger(t)) + reg := coreCapabilities.NewRegistry(logger.TestLogger(t), p2ptypes.PeerID{}, capabilities.DON{}) for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { id, err := tc.newCapability(ctx, reg) @@ -184,3 +187,47 @@ func TestRegistry_ChecksExecutionAPIByType(t *testing.T) { }) } } + +func TestRegistry_ReturnsLocalTargetCapabilityForLocalTargets(t *testing.T) { + ctx := testutils.Context(t) + r := coreCapabilities.NewRegistry(logger.TestLogger(t), p2ptypes.PeerID{}, capabilities.DON{}) + + id := "capability-1" + ci, err := capabilities.NewRemoteCapabilityInfo( + id, + capabilities.CapabilityTypeTarget, + "capability-1-description", + "v1.0.0", + nil, + ) + require.NoError(t, err) + + c := &mockCapability{CapabilityInfo: ci} + err = r.Add(ctx, c) + require.NoError(t, err) + + targetCapability, err := r.GetTarget(ctx, id) + require.NoError(t, err) + + duffTransmissionSchedule, err := values.NewMap(map[string]any{ + "schedule": transmission.Schedule_AllAtOnce, + "deltaStage": "10banana", + }) + require.NoError(t, err) + + _, err = targetCapability.Execute(ctx, capabilities.CapabilityRequest{ + Config: duffTransmissionSchedule, + }) + assert.NotNil(t, err) + + validTransmissionSchedule, err := values.NewMap(map[string]any{ + "schedule": transmission.Schedule_OneAtATime, + "deltaStage": "10ms", + }) + require.NoError(t, err) + + _, err = targetCapability.Execute(ctx, capabilities.CapabilityRequest{ + Config: validTransmissionSchedule, + }) + assert.NoError(t, err) +} diff --git a/core/capabilities/syncer.go b/core/capabilities/syncer.go index 02a21043d3a..0227bfe1b46 100644 --- a/core/capabilities/syncer.go +++ b/core/capabilities/syncer.go @@ -3,6 +3,7 @@ package capabilities import ( "context" "encoding/hex" + "fmt" "math/big" "slices" "sync" @@ -25,12 +26,14 @@ import ( ) type registrySyncer struct { - peerWrapper p2ptypes.PeerWrapper - registry core.CapabilitiesRegistry - dispatcher remotetypes.Dispatcher - subServices []services.Service - wg sync.WaitGroup - lggr logger.Logger + peerWrapper p2ptypes.PeerWrapper + registry core.CapabilitiesRegistry + dispatcher remotetypes.Dispatcher + subServices []services.Service + networkSetup HardcodedDonNetworkSetup + + wg sync.WaitGroup + lggr logger.Logger } var _ services.Service = ®istrySyncer{} @@ -52,12 +55,14 @@ var defaultStreamConfig = p2ptypes.StreamConfig{ const maxRetryCount = 60 // RegistrySyncer updates local Registry to match its onchain counterpart -func NewRegistrySyncer(peerWrapper p2ptypes.PeerWrapper, registry core.CapabilitiesRegistry, dispatcher remotetypes.Dispatcher, lggr logger.Logger) *registrySyncer { +func NewRegistrySyncer(peerWrapper p2ptypes.PeerWrapper, registry core.CapabilitiesRegistry, dispatcher remotetypes.Dispatcher, lggr logger.Logger, + networkSetup HardcodedDonNetworkSetup) *registrySyncer { return ®istrySyncer{ - peerWrapper: peerWrapper, - registry: registry, - dispatcher: dispatcher, - lggr: lggr, + peerWrapper: peerWrapper, + registry: registry, + dispatcher: dispatcher, + networkSetup: networkSetup, + lggr: lggr, } } @@ -71,97 +76,43 @@ func (s *registrySyncer) Start(ctx context.Context) error { // that reads the configuration from chain (KS-117). func (s *registrySyncer) launch(ctx context.Context) { defer s.wg.Done() - // NOTE: temporary hard-coded DONs - workflowDONPeers := []string{ - "12D3KooWBCF1XT5Wi8FzfgNCqRL76Swv8TRU3TiD4QiJm8NMNX7N", - "12D3KooWG1AyvwmCpZ93J8pBQUE1SuzrjDXnT4BeouncHR3jWLCG", - "12D3KooWGeUKZBRMbx27FUTgBwZa9Ap9Ym92mywwpuqkEtz8XWyv", - "12D3KooW9zYWQv3STmDeNDidyzxsJSTxoCTLicafgfeEz9nhwhC4", - } - triggerDONPeers := []string{ - "12D3KooWBaiTbbRwwt2fbNifiL7Ew9tn3vds9AJE3Nf3eaVBX36m", - "12D3KooWS7JSY9fzSfWgbCE1S3W2LNY6ZVpRuun74moVBkKj6utE", - "12D3KooWMMTDXcWhpVnwrdAer1jnVARTmnr3RyT3v7Djg8ZuoBh9", - "12D3KooWGzVXsKxXsF4zLgxSDM8Gzx1ywq2pZef4PrHMKuVg4K3P", - "12D3KooWSyjmmzjVtCzwN7bXzZQFmWiJRuVcKBerNjVgL7HdLJBW", - "12D3KooWLGz9gzhrNsvyM6XnXS3JRkZoQdEzuAvysovnSChNK5ZK", - "12D3KooWAvZnvknFAfSiUYjATyhzEJLTeKvAzpcLELHi4ogM3GET", - } - triggerDONSigners := []string{ - "0x9CcE7293a4Cc2621b61193135A95928735e4795F", - "0x3c775F20bCB2108C1A818741Ce332Bb5fe0dB925", - "0x50314239e2CF05555ceeD53E7F47eB2A8Eab0dbB", - "0xd76A4f98898c3b9A72b244476d7337b50D54BCd8", - "0x656A873f6895b8a03Fb112dE927d43FA54B2c92A", - "0x5d1e87d87bF2e0cD4Ea64F381a2dbF45e5f0a553", - "0x91d9b0062265514f012Eb8fABA59372fD9520f56", - } - allPeers := make(map[ragetypes.PeerID]p2ptypes.StreamConfig) - addPeersToDONInfo := func(peers []string, donInfo *capabilities.DON) error { - for _, peerID := range peers { - var p ragetypes.PeerID - err := p.UnmarshalText([]byte(peerID)) - if err != nil { - return err - } - allPeers[p] = defaultStreamConfig - donInfo.Members = append(donInfo.Members, p) - } - return nil - } - workflowDonInfo := capabilities.DON{ID: "workflowDon1", F: 1} - if err := addPeersToDONInfo(workflowDONPeers, &workflowDonInfo); err != nil { - s.lggr.Errorw("failed to add peers to workflow DON info", "error", err) - return - } - triggerCapabilityDonInfo := capabilities.DON{ID: "capabilityDon1", F: 1} // NOTE: misconfiguration - should be 2 - if err := addPeersToDONInfo(triggerDONPeers, &triggerCapabilityDonInfo); err != nil { - s.lggr.Errorw("failed to add peers to trigger DON info", "error", err) - return - } - err := s.peerWrapper.GetPeer().UpdateConnections(allPeers) - if err != nil { - s.lggr.Errorw("failed to update connections", "error", err) - return - } - // NOTE: temporary hard-coded capabilities capId := "streams-trigger" triggerInfo, err := capabilities.NewRemoteCapabilityInfo( capId, capabilities.CapabilityTypeTrigger, "Remote Trigger", "v0.0.1", - &triggerCapabilityDonInfo, + &s.networkSetup.TriggerCapabilityDonInfo, ) if err != nil { s.lggr.Errorw("failed to create capability info for streams-trigger", "error", err) return } - myId := s.peerWrapper.GetPeer().ID().String() + myId := s.peerWrapper.GetPeer().ID() config := remotetypes.RemoteTriggerConfig{ RegistrationRefreshMs: 20000, RegistrationExpiryMs: 60000, - MinResponsesToAggregate: uint32(triggerCapabilityDonInfo.F) + 1, + MinResponsesToAggregate: uint32(s.networkSetup.TriggerCapabilityDonInfo.F) + 1, } - if slices.Contains(workflowDONPeers, myId) { + if s.networkSetup.IsWorkflowDon(myId) { s.lggr.Info("member of a workflow DON - starting remote subscribers") codec := streams.NewCodec(s.lggr) - aggregator := triggers.NewMercuryRemoteAggregator(codec, hexStringsToBytes(triggerDONSigners), int(triggerCapabilityDonInfo.F+1), s.lggr) - triggerCap := remote.NewTriggerSubscriber(config, triggerInfo, triggerCapabilityDonInfo, workflowDonInfo, s.dispatcher, aggregator, s.lggr) + aggregator := triggers.NewMercuryRemoteAggregator(codec, hexStringsToBytes(s.networkSetup.triggerDonSigners), int(s.networkSetup.TriggerCapabilityDonInfo.F+1), s.lggr) + triggerCap := remote.NewTriggerSubscriber(config, triggerInfo, s.networkSetup.TriggerCapabilityDonInfo, s.networkSetup.WorkflowsDonInfo, s.dispatcher, aggregator, s.lggr) err = s.registry.Add(ctx, triggerCap) if err != nil { s.lggr.Errorw("failed to add remote target capability to registry", "error", err) return } - err = s.dispatcher.SetReceiver(capId, triggerCapabilityDonInfo.ID, triggerCap) + err = s.dispatcher.SetReceiver(capId, s.networkSetup.TriggerCapabilityDonInfo.ID, triggerCap) if err != nil { - s.lggr.Errorw("workflow DON failed to set receiver", "capabilityId", capId, "donId", triggerCapabilityDonInfo.ID, "error", err) + s.lggr.Errorw("workflow DON failed to set receiver", "capabilityId", capId, "donId", s.networkSetup.TriggerCapabilityDonInfo.ID, "error", err) return } s.subServices = append(s.subServices, triggerCap) } - if slices.Contains(triggerDONPeers, myId) { + if s.networkSetup.IsTriggerDon(myId) { s.lggr.Info("member of a capability DON - starting remote publishers") /*{ @@ -195,12 +146,12 @@ func (s *registrySyncer) launch(ctx context.Context) { continue } workflowDONs := map[string]capabilities.DON{ - workflowDonInfo.ID: workflowDonInfo, + s.networkSetup.WorkflowsDonInfo.ID: s.networkSetup.WorkflowsDonInfo, } - triggerCap := remote.NewTriggerPublisher(config, underlying, triggerInfo, triggerCapabilityDonInfo, workflowDONs, s.dispatcher, s.lggr) - err = s.dispatcher.SetReceiver(capId, triggerCapabilityDonInfo.ID, triggerCap) + triggerCap := remote.NewTriggerPublisher(config, underlying, triggerInfo, s.networkSetup.TriggerCapabilityDonInfo, workflowDONs, s.dispatcher, s.lggr) + err = s.dispatcher.SetReceiver(capId, s.networkSetup.TriggerCapabilityDonInfo.ID, triggerCap) if err != nil { - s.lggr.Errorw("capability DON failed to set receiver", "capabilityId", capId, "donId", triggerCapabilityDonInfo.ID, "error", err) + s.lggr.Errorw("capability DON failed to set receiver", "capabilityId", capId, "donId", s.networkSetup.TriggerCapabilityDonInfo.ID, "error", err) return } s.subServices = append(s.subServices, triggerCap) @@ -241,6 +192,81 @@ func (s *registrySyncer) Name() string { return "RegistrySyncer" } +// HardcodedDonNetworkSetup is a temporary setup for testing purposes +type HardcodedDonNetworkSetup struct { + workflowDonPeers []string + triggerDonPeers []string + triggerDonSigners []string + + WorkflowsDonInfo capabilities.DON + TriggerCapabilityDonInfo capabilities.DON +} + +func NewHardcodedDonNetworkSetup(peerWrapper p2ptypes.PeerWrapper) (HardcodedDonNetworkSetup, error) { + result := HardcodedDonNetworkSetup{} + + result.workflowDonPeers = []string{ + "12D3KooWBCF1XT5Wi8FzfgNCqRL76Swv8TRU3TiD4QiJm8NMNX7N", + "12D3KooWG1AyvwmCpZ93J8pBQUE1SuzrjDXnT4BeouncHR3jWLCG", + "12D3KooWGeUKZBRMbx27FUTgBwZa9Ap9Ym92mywwpuqkEtz8XWyv", + "12D3KooW9zYWQv3STmDeNDidyzxsJSTxoCTLicafgfeEz9nhwhC4", + } + result.triggerDonPeers = []string{ + "12D3KooWBaiTbbRwwt2fbNifiL7Ew9tn3vds9AJE3Nf3eaVBX36m", + "12D3KooWS7JSY9fzSfWgbCE1S3W2LNY6ZVpRuun74moVBkKj6utE", + "12D3KooWMMTDXcWhpVnwrdAer1jnVARTmnr3RyT3v7Djg8ZuoBh9", + "12D3KooWGzVXsKxXsF4zLgxSDM8Gzx1ywq2pZef4PrHMKuVg4K3P", + "12D3KooWSyjmmzjVtCzwN7bXzZQFmWiJRuVcKBerNjVgL7HdLJBW", + "12D3KooWLGz9gzhrNsvyM6XnXS3JRkZoQdEzuAvysovnSChNK5ZK", + "12D3KooWAvZnvknFAfSiUYjATyhzEJLTeKvAzpcLELHi4ogM3GET", + } + result.triggerDonSigners = []string{ + "0x9CcE7293a4Cc2621b61193135A95928735e4795F", + "0x3c775F20bCB2108C1A818741Ce332Bb5fe0dB925", + "0x50314239e2CF05555ceeD53E7F47eB2A8Eab0dbB", + "0xd76A4f98898c3b9A72b244476d7337b50D54BCd8", + "0x656A873f6895b8a03Fb112dE927d43FA54B2c92A", + "0x5d1e87d87bF2e0cD4Ea64F381a2dbF45e5f0a553", + "0x91d9b0062265514f012Eb8fABA59372fD9520f56", + } + + allPeers := make(map[ragetypes.PeerID]p2ptypes.StreamConfig) + addPeersToDONInfo := func(peers []string, donInfo *capabilities.DON) error { + for _, peerID := range peers { + var p ragetypes.PeerID + err := p.UnmarshalText([]byte(peerID)) + if err != nil { + return err + } + allPeers[p] = defaultStreamConfig + donInfo.Members = append(donInfo.Members, p) + } + return nil + } + result.WorkflowsDonInfo = capabilities.DON{ID: "workflowDon1", F: 1} + if err := addPeersToDONInfo(result.workflowDonPeers, &result.WorkflowsDonInfo); err != nil { + return HardcodedDonNetworkSetup{}, fmt.Errorf("failed to add peers to workflow DON info: %w", err) + } + result.TriggerCapabilityDonInfo = capabilities.DON{ID: "capabilityDon1", F: 1} // NOTE: misconfiguration - should be 2 + if err := addPeersToDONInfo(result.triggerDonPeers, &result.TriggerCapabilityDonInfo); err != nil { + return HardcodedDonNetworkSetup{}, fmt.Errorf("failed to add peers to trigger DON info: %w", err) + } + err := peerWrapper.GetPeer().UpdateConnections(allPeers) + if err != nil { + return HardcodedDonNetworkSetup{}, fmt.Errorf("failed to update connections: %w", err) + } + + return result, nil +} + +func (h HardcodedDonNetworkSetup) IsWorkflowDon(id p2ptypes.PeerID) bool { + return slices.Contains(h.workflowDonPeers, id.String()) +} + +func (h HardcodedDonNetworkSetup) IsTriggerDon(id p2ptypes.PeerID) bool { + return slices.Contains(h.triggerDonPeers, id.String()) +} + type mockMercuryDataProducer struct { trigger *triggers.MercuryTriggerService wg sync.WaitGroup diff --git a/core/capabilities/syncer_test.go b/core/capabilities/syncer_test.go index 757135635d8..0dfa49eeeb9 100644 --- a/core/capabilities/syncer_test.go +++ b/core/capabilities/syncer_test.go @@ -32,7 +32,9 @@ func TestSyncer_CleanStartClose(t *testing.T) { dispatcher := remoteMocks.NewDispatcher(t) dispatcher.On("SetReceiver", mock.Anything, mock.Anything, mock.Anything).Return(nil) - syncer := coreCapabilities.NewRegistrySyncer(wrapper, registry, dispatcher, lggr) + networkSetup, err := coreCapabilities.NewHardcodedDonNetworkSetup(wrapper) + require.NoError(t, err) + syncer := coreCapabilities.NewRegistrySyncer(wrapper, registry, dispatcher, lggr, networkSetup) require.NoError(t, syncer.Start(ctx)) require.NoError(t, syncer.Close()) } diff --git a/core/capabilities/transmission/local_target_capability.go b/core/capabilities/transmission/local_target_capability.go new file mode 100644 index 00000000000..4fddd93d403 --- /dev/null +++ b/core/capabilities/transmission/local_target_capability.go @@ -0,0 +1,59 @@ +package transmission + +import ( + "context" + "fmt" + "time" + + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink/v2/core/logger" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" +) + +// LocalTargetCapability handles the transmission protocol required for a target capability that exists in the same don as +// the caller. +type LocalTargetCapability struct { + lggr logger.Logger + capabilities.TargetCapability + peerID p2ptypes.PeerID + don capabilities.DON +} + +func NewLocalTargetCapability(lggr logger.Logger, peerID p2ptypes.PeerID, don capabilities.DON, underlying capabilities.TargetCapability) *LocalTargetCapability { + return &LocalTargetCapability{ + TargetCapability: underlying, + lggr: lggr, + peerID: peerID, + don: don, + } +} + +func (l *LocalTargetCapability) Execute(ctx context.Context, req capabilities.CapabilityRequest) (<-chan capabilities.CapabilityResponse, error) { + if req.Config == nil || req.Config.Underlying["schedule"] == nil { + l.lggr.Debug("no schedule found, executing immediately") + return l.TargetCapability.Execute(ctx, req) + } + + tc, err := ExtractTransmissionConfig(req.Config) + if err != nil { + return nil, fmt.Errorf("failed to extract transmission config from request config: %w", err) + } + + peerIDToTransmissionDelay, err := GetPeerIDToTransmissionDelay(l.don.Members, l.don.Config.SharedSecret, + req.Metadata.WorkflowID+req.Metadata.WorkflowExecutionID, tc) + if err != nil { + return nil, fmt.Errorf("failed to get peer ID to transmission delay map: %w", err) + } + + delay, existsForPeerID := peerIDToTransmissionDelay[l.peerID] + if !existsForPeerID { + return nil, nil + } + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(delay): + return l.TargetCapability.Execute(ctx, req) + } +} diff --git a/core/services/workflows/execution_strategy_test.go b/core/capabilities/transmission/local_target_capability_test.go similarity index 73% rename from core/services/workflows/execution_strategy_test.go rename to core/capabilities/transmission/local_target_capability_test.go index 917ea84c72c..19d51b492ff 100644 --- a/core/services/workflows/execution_strategy_test.go +++ b/core/capabilities/transmission/local_target_capability_test.go @@ -1,6 +1,7 @@ -package workflows +package transmission import ( + "context" "crypto/rand" "encoding/hex" "testing" @@ -25,6 +26,8 @@ func TestScheduledExecutionStrategy_LocalDON(t *testing.T) { var gotTime time.Time var called bool + log := logger.TestLogger(t) + // Our capability has DONInfo == nil, so we'll treat it as a local // capability and use the local DON Info to determine the transmission // schedule. @@ -42,8 +45,6 @@ func TestScheduledExecutionStrategy_LocalDON(t *testing.T) { }, ) - l := logger.TestLogger(t) - // The combination of this key and the metadata above // will yield the permutation [3, 2, 0, 1] key, err := hex.DecodeString("fb13ca015a9ec60089c7141e9522de79") @@ -138,19 +139,17 @@ func TestScheduledExecutionStrategy_LocalDON(t *testing.T) { randKey(), randKey(), } - don := &capabilities.DON{ + don := capabilities.DON{ Members: ids, Config: capabilities.DONConfig{ SharedSecret: [16]byte(key), }, } peerID := ids[tc.position] - de := scheduledExecution{ - DON: don, - PeerID: &peerID, - Position: tc.position, - } - _, err = de.Apply(tests.Context(t), l, mt, req) + localTargetCapability := NewLocalTargetCapability(log, peerID, don, mt) + + _, err = localTargetCapability.Execute(tests.Context(t), req) + require.NoError(t, err) require.True(t, called) @@ -167,3 +166,40 @@ func randKey() [32]byte { } return [32]byte(key) } + +type mockCapability struct { + capabilities.CapabilityInfo + capabilities.CallbackExecutable + response chan capabilities.CapabilityResponse + transform func(capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) +} + +func newMockCapability(info capabilities.CapabilityInfo, transform func(capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error)) *mockCapability { + return &mockCapability{ + transform: transform, + CapabilityInfo: info, + response: make(chan capabilities.CapabilityResponse, 10), + } +} + +func (m *mockCapability) Execute(ctx context.Context, req capabilities.CapabilityRequest) (<-chan capabilities.CapabilityResponse, error) { + cr, err := m.transform(req) + if err != nil { + return nil, err + } + + ch := make(chan capabilities.CapabilityResponse, 10) + + m.response <- cr + ch <- cr + close(ch) + return ch, nil +} + +func (m *mockCapability) RegisterToWorkflow(ctx context.Context, request capabilities.RegisterToWorkflowRequest) error { + return nil +} + +func (m *mockCapability) UnregisterFromWorkflow(ctx context.Context, request capabilities.UnregisterFromWorkflowRequest) error { + return nil +} diff --git a/core/capabilities/transmission/transmission.go b/core/capabilities/transmission/transmission.go index 0129d600265..5121a9bf9f3 100644 --- a/core/capabilities/transmission/transmission.go +++ b/core/capabilities/transmission/transmission.go @@ -13,8 +13,6 @@ import ( p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" ) -// TODO determine location for this code - var ( // S = [N] Schedule_AllAtOnce = "allAtOnce" diff --git a/core/chains/evm/client/errors.go b/core/chains/evm/client/errors.go index 5f03ab102d5..f43b5189c7e 100644 --- a/core/chains/evm/client/errors.go +++ b/core/chains/evm/client/errors.go @@ -149,7 +149,7 @@ var erigon = ClientErrors{ var arbitrumFatal = regexp.MustCompile(`(: |^)(invalid message format|forbidden sender address)$|(: |^)(execution reverted)(:|$)`) var arbitrum = ClientErrors{ // TODO: Arbitrum returns this in case of low or high nonce. Update this when Arbitrum fix it - // https://app.shortcut.com/chainlinklabs/story/16801/add-full-support-for-incorrect-nonce-on-arbitrum + // Archived ticket: story/16801/add-full-support-for-incorrect-nonce-on-arbitrum NonceTooLow: regexp.MustCompile(`(: |^)invalid transaction nonce$|(: |^)nonce too low(:|$)`), NonceTooHigh: regexp.MustCompile(`(: |^)nonce too high(:|$)`), TerminallyUnderpriced: regexp.MustCompile(`(: |^)gas price too low$`), diff --git a/core/chains/evm/config/chain_scoped.go b/core/chains/evm/config/chain_scoped.go index 17d4120ddf6..ae14c09447b 100644 --- a/core/chains/evm/config/chain_scoped.go +++ b/core/chains/evm/config/chain_scoped.go @@ -68,8 +68,8 @@ func (e *EVMConfig) OCR2() OCR2 { return &ocr2Config{c: e.C.OCR2} } -func (e *EVMConfig) ChainWriter() ChainWriter { - return &chainWriterConfig{c: e.C.ChainWriter} +func (e *EVMConfig) Workflow() Workflow { + return &workflowConfig{c: e.C.Workflow} } func (e *EVMConfig) GasEstimator() GasEstimator { diff --git a/core/chains/evm/config/chain_scoped_chain_writer.go b/core/chains/evm/config/chain_scoped_workflow.go similarity index 55% rename from core/chains/evm/config/chain_scoped_chain_writer.go rename to core/chains/evm/config/chain_scoped_workflow.go index 1f1cdcecfa7..36dcb3ea41c 100644 --- a/core/chains/evm/config/chain_scoped_chain_writer.go +++ b/core/chains/evm/config/chain_scoped_workflow.go @@ -5,14 +5,14 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) -type chainWriterConfig struct { - c toml.ChainWriter +type workflowConfig struct { + c toml.Workflow } -func (b *chainWriterConfig) FromAddress() *types.EIP55Address { +func (b *workflowConfig) FromAddress() *types.EIP55Address { return b.c.FromAddress } -func (b *chainWriterConfig) ForwarderAddress() *types.EIP55Address { +func (b *workflowConfig) ForwarderAddress() *types.EIP55Address { return b.c.ForwarderAddress } diff --git a/core/chains/evm/config/config.go b/core/chains/evm/config/config.go index 89e5b6c7d80..e767dad9786 100644 --- a/core/chains/evm/config/config.go +++ b/core/chains/evm/config/config.go @@ -21,7 +21,7 @@ type EVM interface { GasEstimator() GasEstimator OCR() OCR OCR2() OCR2 - ChainWriter() ChainWriter + Workflow() Workflow NodePool() NodePool AutoCreateKey() bool @@ -156,7 +156,7 @@ type BlockHistory interface { TransactionPercentile() uint16 } -type ChainWriter interface { +type Workflow interface { FromAddress() *types.EIP55Address ForwarderAddress() *types.EIP55Address } diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index 265557ae9b1..38385c47c27 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -367,7 +367,7 @@ type Chain struct { NodePool NodePool `toml:",omitempty"` OCR OCR `toml:",omitempty"` OCR2 OCR2 `toml:",omitempty"` - ChainWriter ChainWriter `toml:",omitempty"` + Workflow Workflow `toml:",omitempty"` } func (c *Chain) ValidateConfig() (err error) { @@ -507,12 +507,12 @@ func (a *Automation) setFrom(f *Automation) { } } -type ChainWriter struct { +type Workflow struct { FromAddress *types.EIP55Address `toml:",omitempty"` ForwarderAddress *types.EIP55Address `toml:",omitempty"` } -func (m *ChainWriter) setFrom(f *ChainWriter) { +func (m *Workflow) setFrom(f *Workflow) { if v := f.FromAddress; v != nil { m.FromAddress = v } diff --git a/core/chains/evm/config/toml/defaults.go b/core/chains/evm/config/toml/defaults.go index 622ac132e13..6e60454f3eb 100644 --- a/core/chains/evm/config/toml/defaults.go +++ b/core/chains/evm/config/toml/defaults.go @@ -181,5 +181,5 @@ func (c *Chain) SetFrom(f *Chain) { c.NodePool.setFrom(&f.NodePool) c.OCR.setFrom(&f.OCR) c.OCR2.setFrom(&f.OCR2) - c.ChainWriter.setFrom(&f.ChainWriter) + c.Workflow.setFrom(&f.Workflow) } diff --git a/core/chains/evm/config/toml/defaults/Ethereum_Kovan.toml b/core/chains/evm/config/toml/defaults/Ethereum_Kovan.toml index d3361bb373f..0a4a351ade9 100644 --- a/core/chains/evm/config/toml/defaults/Ethereum_Kovan.toml +++ b/core/chains/evm/config/toml/defaults/Ethereum_Kovan.toml @@ -5,7 +5,7 @@ OperatorFactoryAddress = '0x8007e24251b1D2Fc518Eb843A701d9cD21fe0aA3' [GasEstimator] # FIXME: Kovan has strange behaviour with EIP1559, see: -# https://app.shortcut.com/chainlinklabs/story/34098/kovan-can-emit-blocks-that-violate-assumptions-in-block-history-estimator +# https://smartcontract-it.atlassian.net/browse/BCF-1420 EIP1559DynamicFees = false [GasEstimator.BlockHistory] diff --git a/core/chains/evm/config/toml/defaults/Ethereum_Rinkeby.toml b/core/chains/evm/config/toml/defaults/Ethereum_Rinkeby.toml index 75b01bfb03d..06dc2cb0f58 100644 --- a/core/chains/evm/config/toml/defaults/Ethereum_Rinkeby.toml +++ b/core/chains/evm/config/toml/defaults/Ethereum_Rinkeby.toml @@ -4,7 +4,7 @@ MinContractPayment = '0.1 link' [GasEstimator] # TODO: EIP1559 on rinkeby has not been adequately tested, see: -# https://app.shortcut.com/chainlinklabs/story/34098/kovan-can-emit-blocks-that-violate-assumptions-in-block-history-estimator +# https://smartcontract-it.atlassian.net/browse/BCF-1420 EIP1559DynamicFees = false [GasEstimator.BlockHistory] diff --git a/core/chains/evm/forwarders/forwarder_manager.go b/core/chains/evm/forwarders/forwarder_manager.go index 39ca8236305..638836094dc 100644 --- a/core/chains/evm/forwarders/forwarder_manager.go +++ b/core/chains/evm/forwarders/forwarder_manager.go @@ -43,7 +43,7 @@ type FwdMgr struct { logpoller evmlogpoller.LogPoller // TODO(samhassan): sendersCache should be an LRU capped cache - // https://app.shortcut.com/chainlinklabs/story/37884/forwarder-manager-uses-lru-for-caching-dest-addresses + // https://smartcontract-it.atlassian.net/browse/ARCHIVE-22505 sendersCache map[common.Address][]common.Address latestBlock int64 diff --git a/core/cmd/shell.go b/core/cmd/shell.go index d6f99955e10..0ababfca58d 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -31,6 +31,7 @@ import ( "github.com/jmoiron/sqlx" + commoncapabilities "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" @@ -43,6 +44,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" "github.com/smartcontractkit/chainlink/v2/core/services/periodicbackup" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" @@ -166,7 +168,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G LatestReportDeadline: cfg.Mercury().Cache().LatestReportDeadline(), }) - capabilitiesRegistry := capabilities.NewRegistry(appLggr) + capabilitiesRegistry := capabilities.NewRegistry(appLggr, p2ptypes.PeerID{}, commoncapabilities.DON{}) // create the relayer-chain interoperators from application configuration relayerFactory := chainlink.RelayerFactory{ diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml index 209929b2e8b..a222d5269d7 100644 --- a/core/config/docs/chains-evm.toml +++ b/core/config/docs/chains-evm.toml @@ -15,8 +15,6 @@ BlockBackfillDepth = 10 # Default BlockBackfillSkip = false # Default # ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID. # Available types: `arbitrum`, `celo`, `gnosis`, `kroma`, `metis`, `optimismBedrock`, `scroll`, `wemix`, `xlayer`, `zksync` -# -# `xdai` has been deprecated and will be removed in v2.13.0, use `gnosis` instead. ChainType = 'arbitrum' # Example # FinalityDepth is the number of blocks after which an ethereum transaction is considered "final". Note that the default is automatically set based on chain ID, so it should not be necessary to change this under normal operation. # BlocksConsideredFinal determines how deeply we look back to ensure that transactions are confirmed onto the longest chain @@ -437,7 +435,7 @@ Order = 100 # Default # GasLimit controls the gas limit for transmit transactions from ocr2automation job. GasLimit = 5400000 # Default -[EVM.ChainWriter] +[EVM.Workflow] # FromAddress is Address of the transmitter key to use for workflow writes. FromAddress = '0x2a3e23c6f242F5345320814aC8a1b4E58707D292' # Example # ForwarderAddress is the keystone forwarder contract address on chain. diff --git a/core/config/docs/docs_test.go b/core/config/docs/docs_test.go index fd59edbab6a..2e2451ab57a 100644 --- a/core/config/docs/docs_test.go +++ b/core/config/docs/docs_test.go @@ -81,10 +81,10 @@ func TestDoc(t *testing.T) { docDefaults.FlagsContractAddress = nil docDefaults.LinkContractAddress = nil docDefaults.OperatorFactoryAddress = nil - require.Empty(t, docDefaults.ChainWriter.FromAddress) - require.Empty(t, docDefaults.ChainWriter.ForwarderAddress) - docDefaults.ChainWriter.FromAddress = nil - docDefaults.ChainWriter.ForwarderAddress = nil + require.Empty(t, docDefaults.Workflow.FromAddress) + require.Empty(t, docDefaults.Workflow.ForwarderAddress) + docDefaults.Workflow.FromAddress = nil + docDefaults.Workflow.ForwarderAddress = nil docDefaults.NodePool.Errors = evmcfg.ClientErrors{} // Transactions.AutoPurge configs are only set if the feature is enabled diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 9b950f487bf..ae87baa564e 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -489,7 +489,7 @@ juelsPerFeeCoinSource = """ answer1 [type=median index=0]; """ -gasPriceSource = """ +gasPriceSubunitsSource = """ // data source dsp [type=bridge name="%s"]; dsp_parse [type=jsonparse path="data"]; diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 0e9104a32bb..07f9267877b 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -260,7 +260,7 @@ require ( github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240524201401-88d0b3763b20 // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240527073251-56197f1413e0 // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240531021326-99118e47f696 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.8.1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 6ee7132708d..5c4d31bf47a 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1195,8 +1195,8 @@ github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 h github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917/go.mod h1:jwVxhctE6BgLOSSsVq9wbREpZ8Ev34H+UBxeUhESZRs= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240524201401-88d0b3763b20 h1:ybdconEoRBHLwtDKlZKYaeanQ8UoVqdDiaTlPV+qEiI= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240524201401-88d0b3763b20/go.mod h1:QqcZSwLgEIn7YraAIRmomnBMAuVFephiHrIWVlkWbFI= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240527073251-56197f1413e0 h1:5QNKQTQpIp+0ogXUu9B85tEie473RZttOhYxM2vHyOc= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240527073251-56197f1413e0/go.mod h1:OiWUTrrpSLLTMh7FINWjEh6mmDJCVPaC4yEsDCVaWdU= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240531021326-99118e47f696 h1:h1E87+z+JcUEfvbJVF56SnZA/YUFE5ewUE61MaR/Ewg= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240531021326-99118e47f696/go.mod h1:OiWUTrrpSLLTMh7FINWjEh6mmDJCVPaC4yEsDCVaWdU= github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772 h1:LQmRsrzzaYYN3wEU1l5tWiccznhvbyGnu2N+wHSXZAo= github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 h1:TFe+FvzxClblt6qRfqEhUfa4kFQx5UobuoFGO2W4mMo= diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 3eeaaa880ed..d796faa00c4 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -17,6 +17,7 @@ import ( "go.uber.org/multierr" "go.uber.org/zap/zapcore" + commoncapabilities "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/loop" commonservices "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" @@ -200,10 +201,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { restrictedHTTPClient := opts.RestrictedHTTPClient unrestrictedHTTPClient := opts.UnrestrictedHTTPClient - if opts.CapabilitiesRegistry == nil { - opts.CapabilitiesRegistry = capabilities.NewRegistry(globalLogger) - } - var externalPeerWrapper p2ptypes.PeerWrapper if cfg.Capabilities().Peering().Enabled() { externalPeer := externalp2p.NewExternalPeerWrapper(keyStore.P2P(), cfg.Capabilities().Peering(), globalLogger) @@ -212,10 +209,31 @@ func NewApplication(opts ApplicationOpts) (Application, error) { srvcs = append(srvcs, externalPeerWrapper) + networkSetup, err := capabilities.NewHardcodedDonNetworkSetup(externalPeerWrapper) + if err != nil { + return nil, fmt.Errorf("failed to create hardcoded Don network setup: %w", err) + } + + if opts.CapabilitiesRegistry == nil { + peerID := externalPeerWrapper.GetPeer().ID() + if networkSetup.IsWorkflowDon(peerID) { + opts.CapabilitiesRegistry = capabilities.NewRegistry(globalLogger, peerID, networkSetup.WorkflowsDonInfo) + } else if networkSetup.IsTriggerDon(peerID) { + opts.CapabilitiesRegistry = capabilities.NewRegistry(globalLogger, peerID, networkSetup.TriggerCapabilityDonInfo) + } else { + return nil, fmt.Errorf("peer %s is not a member of any known DON", peerID) + } + } + // NOTE: RegistrySyncer will depend on a Relayer when fully implemented dispatcher := remote.NewDispatcher(externalPeerWrapper, signer, opts.CapabilitiesRegistry, globalLogger) - registrySyncer := capabilities.NewRegistrySyncer(externalPeerWrapper, opts.CapabilitiesRegistry, dispatcher, globalLogger) + registrySyncer := capabilities.NewRegistrySyncer(externalPeerWrapper, opts.CapabilitiesRegistry, dispatcher, globalLogger, networkSetup) + srvcs = append(srvcs, dispatcher, registrySyncer) + } else { + if opts.CapabilitiesRegistry == nil { + opts.CapabilitiesRegistry = capabilities.NewRegistry(globalLogger, p2ptypes.PeerID{}, commoncapabilities.DON{}) + } } // LOOPs can be created as options, in the case of LOOP relayers, or diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index d0d25a5e461..64c83323e39 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -76,17 +76,7 @@ func (c *Config) valueWarnings() (err error) { // deprecationWarnings returns an error if the Config contains deprecated fields. // This is typically used before defaults have been applied, with input from the user. func (c *Config) deprecationWarnings() (err error) { - // ChainType xdai is deprecated and has been renamed to gnosis - for _, evm := range c.EVM { - if evm.ChainType != nil && evm.ChainType.Slug() == "xdai" { - err = multierr.Append(err, config.ErrInvalid{ - Name: "EVM.ChainType", - Value: evm.ChainType.Slug(), - Msg: "deprecated and will be removed in v2.13.0, use 'gnosis' instead", - }) - } - } - return + return nil } // Validate returns an error if the Config is not valid for use, as-is. diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index e02435a946b..e819993d42b 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -1210,11 +1210,11 @@ func TestConfig_full(t *testing.T) { for c := range got.EVM { addr, err := types.NewEIP55Address("0x2a3e23c6f242F5345320814aC8a1b4E58707D292") require.NoError(t, err) - if got.EVM[c].ChainWriter.FromAddress == nil { - got.EVM[c].ChainWriter.FromAddress = &addr + if got.EVM[c].Workflow.FromAddress == nil { + got.EVM[c].Workflow.FromAddress = &addr } - if got.EVM[c].ChainWriter.ForwarderAddress == nil { - got.EVM[c].ChainWriter.ForwarderAddress = &addr + if got.EVM[c].Workflow.ForwarderAddress == nil { + got.EVM[c].Workflow.ForwarderAddress = &addr } for n := range got.EVM[c].Nodes { if got.EVM[c].Nodes[n].WSURL == nil { @@ -1647,13 +1647,6 @@ func TestConfig_warnings(t *testing.T) { }, expectedErrors: []string{"Tracing.TLSCertPath: invalid value (/path/to/cert.pem): must be empty when Tracing.Mode is 'unencrypted'"}, }, - { - name: "Value warning - ChainType=xdai is deprecated", - config: Config{ - EVM: evmcfg.EVMConfigs{{Chain: evmcfg.Chain{ChainType: commonconfig.NewChainTypeConfig("xdai")}}}, - }, - expectedErrors: []string{"EVM.ChainType: invalid value (xdai): deprecated and will be removed in v2.13.0, use 'gnosis' instead"}, - }, } for _, tt := range tests { diff --git a/core/services/job/models_test.go b/core/services/job/models_test.go index c177b3b81e1..04bbbdee0f0 100644 --- a/core/services/job/models_test.go +++ b/core/services/job/models_test.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/codec" "github.com/smartcontractkit/chainlink-common/pkg/types" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index 8ed08a1cb8a..8b98fd219fb 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -12,6 +12,7 @@ import ( "github.com/jmoiron/sqlx" + commoncapabilities "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" @@ -19,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" "github.com/smartcontractkit/chainlink/v2/core/capabilities" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" @@ -296,7 +298,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { evmRelayer, err := evmrelayer.NewRelayer(lggr, chain, evmrelayer.RelayerOpts{ DS: db, CSAETHKeystore: keyStore, - CapabilitiesRegistry: capabilities.NewRegistry(lggr), + CapabilitiesRegistry: capabilities.NewRegistry(lggr, p2ptypes.PeerID{}, commoncapabilities.DON{}), }) assert.NoError(t, err) @@ -314,7 +316,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { ocr2DelegateConfig := ocr2.NewDelegateConfig(config.OCR2(), config.Mercury(), config.Threshold(), config.Insecure(), config.JobPipeline(), processConfig) d := ocr2.NewDelegate(nil, orm, nil, nil, nil, nil, nil, monitoringEndpoint, legacyChains, lggr, ocr2DelegateConfig, - keyStore.OCR2(), keyStore.DKGSign(), keyStore.DKGEncrypt(), ethKeyStore, testRelayGetter, mailMon, capabilities.NewRegistry(lggr)) + keyStore.OCR2(), keyStore.DKGSign(), keyStore.DKGEncrypt(), ethKeyStore, testRelayGetter, mailMon, capabilities.NewRegistry(lggr, p2ptypes.PeerID{}, commoncapabilities.DON{})) delegateOCR2 := &delegate{jobOCR2VRF.Type, []job.ServiceCtx{}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index cd02fc27d11..c70a92c725c 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -275,7 +275,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { head := newHead() executer.OnNewLongestChain(testutils.Context(t), &head) // TODO we want to see an errored run result once this is completed - // https://app.shortcut.com/chainlinklabs/story/25397/remove-failearly-flag-from-eth-call-task + // https://smartcontract-it.atlassian.net/browse/ARCHIVE-22186 cltest.AssertPipelineRunsStays(t, jb.PipelineSpecID, db, 0) }) diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 350cbc8d593..1c70195dd43 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -26,21 +26,25 @@ import ( ocr2keepers20runner "github.com/smartcontractkit/chainlink-automation/pkg/v2/runner" ocr2keepers21config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" ocr2keepers21 "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin" + "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins/ocr3" + + "github.com/smartcontractkit/chainlink/v2/core/config/env" + + "github.com/smartcontractkit/chainlink-vrf/altbn_128" + dkgpkg "github.com/smartcontractkit/chainlink-vrf/dkg" + "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins" - "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins/ocr3" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/types/core" llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - "github.com/smartcontractkit/chainlink-vrf/altbn_128" - dkgpkg "github.com/smartcontractkit/chainlink-vrf/dkg" - "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" - "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -683,9 +687,9 @@ func (d *Delegate) newServicesGenericPlugin( } oracleArgs.ReportingPluginFactory = plugin srvs = append(srvs, plugin) - oracle, err := libocr2.NewOracle(oracleArgs) - if err != nil { - return nil, err + oracle, oracleErr := libocr2.NewOracle(oracleArgs) + if oracleErr != nil { + return nil, oracleErr } srvs = append(srvs, job.NewServiceAdapter(oracle)) @@ -714,6 +718,28 @@ func (d *Delegate) newServicesGenericPlugin( if ocr3Provider, ok := provider.(types.OCR3ContractTransmitter); ok { contractTransmitter = ocr3Provider.OCR3ContractTransmitter() } + var onchainKeyringAdapter ocr3types.OnchainKeyring[[]byte] + if onchainSigningStrategy.IsMultiChain() { + // We are extracting the config beforehand + keyBundles := map[string]ocr2key.KeyBundle{} + for name := range onchainSigningStrategy.ConfigCopy() { + kbID, ostErr := onchainSigningStrategy.KeyBundleID(name) + if ostErr != nil { + return nil, ostErr + } + os, ostErr := d.ks.Get(kbID) + if ostErr != nil { + return nil, ostErr + } + keyBundles[name] = os + } + onchainKeyringAdapter, err = ocrcommon.NewOCR3OnchainKeyringMultiChainAdapter(keyBundles, lggr) + if err != nil { + return nil, err + } + } else { + onchainKeyringAdapter = ocrcommon.NewOCR3OnchainKeyringAdapter(kb) + } oracleArgs := libocr2.OCR3OracleArgs[[]byte]{ BinaryNetworkEndpointFactory: d.peerWrapper.Peer2, V2Bootstrappers: bootstrapPeers, @@ -725,7 +751,7 @@ func (d *Delegate) newServicesGenericPlugin( MonitoringEndpoint: oracleEndpoint, OffchainConfigDigester: provider.OffchainConfigDigester(), OffchainKeyring: kb, - OnchainKeyring: ocrcommon.NewOCR3OnchainKeyringAdapter(kb), + OnchainKeyring: onchainKeyringAdapter, MetricsRegisterer: prometheus.WrapRegistererWith(map[string]string{"job_name": jb.Name.ValueOrZero()}, prometheus.DefaultRegisterer), } oracleArgs.ReportingPluginFactory = plugin diff --git a/core/services/ocr2/plugins/functions/reporting.go b/core/services/ocr2/plugins/functions/reporting.go index d9d68ec9097..f485ecb9d34 100644 --- a/core/services/ocr2/plugins/functions/reporting.go +++ b/core/services/ocr2/plugins/functions/reporting.go @@ -337,7 +337,7 @@ func (r *functionsReporting) Report(ctx context.Context, ts types.ReportTimestam } // TODO: support per-request aggregation method - // https://app.shortcut.com/chainlinklabs/story/57701/per-request-plugin-config + // https://smartcontract-it.atlassian.net/browse/FUN-159 aggregated, errAgg := Aggregate(defaultAggMethod, observations) if errAgg != nil { r.logger.Error("FunctionsReporting Report: error when aggregating reqId", commontypes.LogFields{ diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index 9a85d7993a4..00ddfec000d 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -116,7 +116,7 @@ func validateSpec(ctx context.Context, tree *toml.Tree, spec job.Job, rc plugins case types.OCR2Keeper: return validateOCR2KeeperSpec(spec.OCR2OracleSpec.PluginConfig) case types.Functions: - // TODO validator for DR-OCR spec: https://app.shortcut.com/chainlinklabs/story/54054/ocr-plugin-for-directrequest-ocr + // TODO validator for DR-OCR spec: https://smartcontract-it.atlassian.net/browse/FUN-112 return nil case types.Mercury: return validateOCR2MercurySpec(spec.OCR2OracleSpec.PluginConfig, *spec.OCR2OracleSpec.FeedID) @@ -200,11 +200,31 @@ func (o *OCR2OnchainSigningStrategy) PublicKey() (string, error) { if !ok { return "", nil } - name, ok := pk.(string) + pkString, ok := pk.(string) if !ok { return "", fmt.Errorf("expected string publicKey value, but got: %T", pk) } - return name, nil + return pkString, nil +} + +func (o *OCR2OnchainSigningStrategy) ConfigCopy() job.JSONConfig { + copiedConfig := make(job.JSONConfig) + for k, v := range o.Config { + copiedConfig[k] = v + } + return copiedConfig +} + +func (o *OCR2OnchainSigningStrategy) KeyBundleID(name string) (string, error) { + kbID, ok := o.Config[name] + if !ok { + return "", nil + } + kbIDString, ok := kbID.(string) + if !ok { + return "", fmt.Errorf("expected string %s value, but got: %T", name, kbID) + } + return kbIDString, nil } func validateGenericPluginSpec(ctx context.Context, spec *job.OCR2OracleSpec, rc plugins.RegistrarConfig) error { @@ -222,17 +242,20 @@ func validateGenericPluginSpec(ctx context.Context, spec *job.OCR2OracleSpec, rc return errors.New("generic config invalid: only OCR version 2 and 3 are supported") } - onchainSigningStrategy := OCR2OnchainSigningStrategy{} - err = json.Unmarshal(spec.OnchainSigningStrategy.Bytes(), &onchainSigningStrategy) - if err != nil { - return err - } - pk, err := onchainSigningStrategy.PublicKey() - if err != nil { - return err - } - if pk == "" { - return errors.New("generic config invalid: must provide public key for the onchain signing strategy") + // OnchainSigningStrategy is optional + if spec.OnchainSigningStrategy != nil && len(spec.OnchainSigningStrategy.Bytes()) > 0 { + onchainSigningStrategy := OCR2OnchainSigningStrategy{} + err = json.Unmarshal(spec.OnchainSigningStrategy.Bytes(), &onchainSigningStrategy) + if err != nil { + return err + } + pk, ossErr := onchainSigningStrategy.PublicKey() + if ossErr != nil { + return ossErr + } + if pk == "" { + return errors.New("generic config invalid: must provide public key for the onchain signing strategy") + } } plugEnv := env.NewPlugin(p.PluginName) diff --git a/core/services/ocr2/validate/validate_test.go b/core/services/ocr2/validate/validate_test.go index da896bf4a92..05a10caeaf5 100644 --- a/core/services/ocr2/validate/validate_test.go +++ b/core/services/ocr2/validate/validate_test.go @@ -958,3 +958,36 @@ spec = "a spec" assert.Equal(t, "median", pc.PluginName) assert.Equal(t, "median", pc.TelemetryType) } + +type envelope2 struct { + OnchainSigningStrategy *validate.OCR2OnchainSigningStrategy +} + +func TestOCR2OnchainSigningStrategy_Unmarshal(t *testing.T) { + payload := ` +[onchainSigningStrategy] +strategyName = "single-chain" +[onchainSigningStrategy.config] +evm = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" +publicKey = "0x1234567890123456789012345678901234567890" +` + oss := &envelope2{} + tree, err := toml.Load(payload) + require.NoError(t, err) + o := map[string]any{} + err = tree.Unmarshal(&o) + require.NoError(t, err) + b, err := json.Marshal(o) + require.NoError(t, err) + err = json.Unmarshal(b, oss) + require.NoError(t, err) + + pk, err := oss.OnchainSigningStrategy.PublicKey() + require.NoError(t, err) + kbID, err := oss.OnchainSigningStrategy.KeyBundleID("evm") + require.NoError(t, err) + + assert.False(t, oss.OnchainSigningStrategy.IsMultiChain()) + assert.Equal(t, "0x1234567890123456789012345678901234567890", pk) + assert.Equal(t, "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17", kbID) +} diff --git a/core/services/ocrcommon/adapters.go b/core/services/ocrcommon/adapters.go index 1eee437eb6b..372d9e37f15 100644 --- a/core/services/ocrcommon/adapters.go +++ b/core/services/ocrcommon/adapters.go @@ -2,9 +2,16 @@ package ocrcommon import ( "context" + "fmt" + "github.com/pkg/errors" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/structpb" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" ) var _ ocr3types.OnchainKeyring[[]byte] = (*OCR3OnchainKeyringAdapter)(nil) @@ -71,3 +78,87 @@ func (c *OCR3ContractTransmitterAdapter) Transmit(ctx context.Context, digest oc func (c *OCR3ContractTransmitterAdapter) FromAccount() (ocrtypes.Account, error) { return c.ct.FromAccount() } + +var _ ocr3types.OnchainKeyring[[]byte] = (*OCR3OnchainKeyringMultiChainAdapter)(nil) + +type OCR3OnchainKeyringMultiChainAdapter struct { + keyBundles map[string]ocr2key.KeyBundle + publicKey ocrtypes.OnchainPublicKey + lggr logger.Logger +} + +func NewOCR3OnchainKeyringMultiChainAdapter(ost map[string]ocr2key.KeyBundle, lggr logger.Logger) (*OCR3OnchainKeyringMultiChainAdapter, error) { + if len(ost) == 0 { + return nil, errors.New("no key bundles provided") + } + // We don't need to check for the existence of `publicKey` in the keyBundles map because it is required on validation on `validate/validate.go` + return &OCR3OnchainKeyringMultiChainAdapter{ost, ost["publicKey"].PublicKey(), lggr}, nil +} + +func (a *OCR3OnchainKeyringMultiChainAdapter) PublicKey() ocrtypes.OnchainPublicKey { + return a.publicKey +} + +func (a *OCR3OnchainKeyringMultiChainAdapter) getKeyBundleFromInfo(info []byte) (ocr2key.KeyBundle, error) { + unmarshalledInfo := new(structpb.Struct) + err := proto.Unmarshal(info, unmarshalledInfo) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal report info: %v", err) + } + infoMap := unmarshalledInfo.AsMap() + keyBundleName, ok := infoMap["keyBundleName"] + if !ok { + return nil, errors.New("keyBundleName not found in report info") + } + name, ok := keyBundleName.(string) + if !ok { + return nil, errors.New("keyBundleName is not a string") + } + kb, ok := a.keyBundles[name] + if !ok { + return nil, fmt.Errorf("keyBundle not found: %s", name) + } + return kb, nil +} + +func (a *OCR3OnchainKeyringMultiChainAdapter) Sign(digest ocrtypes.ConfigDigest, seqNr uint64, r ocr3types.ReportWithInfo[[]byte]) (signature []byte, err error) { + kb, err := a.getKeyBundleFromInfo(r.Info) + if err != nil { + return nil, fmt.Errorf("sign: failed to get key bundle from report info: %v", err) + } + return kb.Sign(ocrtypes.ReportContext{ + ReportTimestamp: ocrtypes.ReportTimestamp{ + ConfigDigest: digest, + Epoch: uint32(seqNr), + Round: 0, + }, + ExtraHash: [32]byte(make([]byte, 32)), + }, r.Report) +} + +func (a *OCR3OnchainKeyringMultiChainAdapter) Verify(opk ocrtypes.OnchainPublicKey, digest ocrtypes.ConfigDigest, seqNr uint64, ri ocr3types.ReportWithInfo[[]byte], signature []byte) bool { + kb, err := a.getKeyBundleFromInfo(ri.Info) + if err != nil { + a.lggr.Warnf("verify: failed to get key bundle from report info: %v", err) + return false + } + return kb.Verify(opk, ocrtypes.ReportContext{ + ReportTimestamp: ocrtypes.ReportTimestamp{ + ConfigDigest: digest, + Epoch: uint32(seqNr), + Round: 0, + }, + ExtraHash: [32]byte(make([]byte, 32)), + }, ri.Report, signature) +} + +func (a *OCR3OnchainKeyringMultiChainAdapter) MaxSignatureLength() int { + maxLength := -1 + for _, kb := range a.keyBundles { + l := kb.MaxSignatureLength() + if l > maxLength { + maxLength = l + } + } + return maxLength +} diff --git a/core/services/ocrcommon/adapters_test.go b/core/services/ocrcommon/adapters_test.go index 669e015e7bc..fed854b0b32 100644 --- a/core/services/ocrcommon/adapters_test.go +++ b/core/services/ocrcommon/adapters_test.go @@ -2,15 +2,25 @@ package ocrcommon_test import ( "context" + "encoding/json" "fmt" "reflect" "testing" + "github.com/pelletier/go-toml" "github.com/smartcontractkit/libocr/offchainreporting2/types" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/structpb" + + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/keystest" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" + keystoreMocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" ) @@ -105,6 +115,65 @@ func TestOCR3OnchainKeyringAdapter(t *testing.T) { require.Equal(t, maxSignatureLength, kr.MaxSignatureLength()) } +type envelope struct { + OnchainSigningStrategy *validate.OCR2OnchainSigningStrategy +} + +func TestNewOCR3OnchainKeyringMultiChainAdapter(t *testing.T) { + payload := ` +[onchainSigningStrategy] +strategyName = "single-chain" +[onchainSigningStrategy.config] +evm = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" +publicKey = "pub-key" +` + oss := &envelope{} + tree, err := toml.Load(payload) + require.NoError(t, err) + o := map[string]any{} + err = tree.Unmarshal(&o) + require.NoError(t, err) + b, err := json.Marshal(o) + require.NoError(t, err) + err = json.Unmarshal(b, oss) + require.NoError(t, err) + reportInfo := ocr3types.ReportWithInfo[[]byte]{ + Report: []byte("multi-chain-report"), + } + info, err := structpb.NewStruct(map[string]interface{}{ + "keyBundleName": "evm", + }) + require.NoError(t, err) + infoB, err := proto.Marshal(info) + require.NoError(t, err) + reportInfo.Info = infoB + + ks := keystoreMocks.NewOCR2(t) + fakeKey := ocr2key.MustNewInsecure(keystest.NewRandReaderFromSeed(1), "evm") + pk := fakeKey.PublicKey() + ks.On("Get", "pub-key").Return(fakeKey, nil) + ks.On("Get", "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17").Return(fakeKey, nil) + keyBundles := map[string]ocr2key.KeyBundle{} + for name := range oss.OnchainSigningStrategy.ConfigCopy() { + kbID, ostErr := oss.OnchainSigningStrategy.KeyBundleID(name) + require.NoError(t, ostErr) + os, ostErr := ks.Get(kbID) + require.NoError(t, ostErr) + keyBundles[name] = os + } + + adapter, err := ocrcommon.NewOCR3OnchainKeyringMultiChainAdapter(keyBundles, logger.TestLogger(t)) + require.NoError(t, err) + _, err = ocrcommon.NewOCR3OnchainKeyringMultiChainAdapter(map[string]ocr2key.KeyBundle{}, logger.TestLogger(t)) + require.Error(t, err, "no key bundles provided") + + sig, err := adapter.Sign(configDigest, seqNr, reportInfo) + assert.NoError(t, err) + assert.True(t, adapter.Verify(pk, configDigest, seqNr, reportInfo, sig)) + assert.Equal(t, pk, adapter.PublicKey()) + assert.Equal(t, fakeKey.MaxSignatureLength(), adapter.MaxSignatureLength()) +} + var _ ocrtypes.ContractTransmitter = (*fakeContractTransmitter)(nil) type fakeContractTransmitter struct { diff --git a/core/services/pipeline/scheduler.go b/core/services/pipeline/scheduler.go index b589c9a7449..0405f3b8b11 100644 --- a/core/services/pipeline/scheduler.go +++ b/core/services/pipeline/scheduler.go @@ -170,7 +170,7 @@ func (s *scheduler) Run() { result := <-s.resultCh // TODO: if for some reason the cleanup didn't succeed and we're stuck waiting for reports forever // we should be able to timeout and finish shutting down - // See: https://app.shortcut.com/chainlinklabs/story/21225/straighten-out-and-clarify-context-usage-in-the-pipeline + // See: https://smartcontract-it.atlassian.net/browse/BCF-994 s.waiting-- diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 39160e2f8ac..23740cc8b3b 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -146,7 +146,7 @@ func NewRelayer(lggr logger.Logger, chain legacyevm.Chain, opts RelayerOpts) (*R } // Initialize write target capability if configuration is defined - if chain.Config().EVM().ChainWriter().ForwarderAddress() != nil { + if chain.Config().EVM().Workflow().ForwarderAddress() != nil { ctx := context.Background() capability, err := NewWriteTarget(ctx, relayer, chain, lggr) if err != nil { diff --git a/core/services/relay/evm/write_target.go b/core/services/relay/evm/write_target.go index e5fd1385609..172e4c1423c 100644 --- a/core/services/relay/evm/write_target.go +++ b/core/services/relay/evm/write_target.go @@ -24,7 +24,7 @@ func NewWriteTarget(ctx context.Context, relayer *Relayer, chain legacyevm.Chain } // EVM-specific init - config := chain.Config().EVM().ChainWriter() + config := chain.Config().EVM().Workflow() // Initialize a reader to check whether a value was already transmitted on chain contractReaderConfigEncoded, err := json.Marshal(relayevmtypes.ChainReaderConfig{ diff --git a/core/services/relay/evm/write_target_test.go b/core/services/relay/evm/write_target_test.go index 331a30606cc..b7a1199b5ed 100644 --- a/core/services/relay/evm/write_target_test.go +++ b/core/services/relay/evm/write_target_test.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/values" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink-common/pkg/capabilities" @@ -53,12 +54,12 @@ func TestEvmWrite(t *testing.T) { a := testutils.NewAddress() addr, err2 := types.NewEIP55Address(a.Hex()) require.NoError(t, err2) - c.EVM[0].ChainWriter.FromAddress = &addr + c.EVM[0].Workflow.FromAddress = &addr forwarderA := testutils.NewAddress() forwarderAddr, err2 := types.NewEIP55Address(forwarderA.Hex()) require.NoError(t, err2) - c.EVM[0].ChainWriter.ForwarderAddress = &forwarderAddr + c.EVM[0].Workflow.ForwarderAddress = &forwarderAddr }) evmCfg := evmtest.NewChainScopedConfig(t, cfg) @@ -71,7 +72,7 @@ func TestEvmWrite(t *testing.T) { relayer, err := relayevm.NewRelayer(lggr, chain, relayevm.RelayerOpts{ DS: db, CSAETHKeystore: keyStore, - CapabilitiesRegistry: evmcapabilities.NewRegistry(lggr), + CapabilitiesRegistry: evmcapabilities.NewRegistry(lggr, p2ptypes.PeerID{}, capabilities.DON{}), }) require.NoError(t, err) @@ -91,7 +92,7 @@ func TestEvmWrite(t *testing.T) { require.NoError(t, err) config, err := values.NewMap(map[string]any{ - "Address": evmCfg.EVM().ChainWriter().ForwarderAddress().String(), + "Address": evmCfg.EVM().Workflow().ForwarderAddress().String(), }) require.NoError(t, err) @@ -124,7 +125,7 @@ func TestEvmWrite(t *testing.T) { require.NoError(t, err) config, err := values.NewMap(map[string]any{ - "Address": evmCfg.EVM().ChainWriter().ForwarderAddress().String(), + "Address": evmCfg.EVM().Workflow().ForwarderAddress().String(), }) require.NoError(t, err) @@ -185,7 +186,7 @@ func TestEvmWrite(t *testing.T) { require.NoError(t, err) config, err := values.NewMap(map[string]any{ - "Address": evmCfg.EVM().ChainWriter().ForwarderAddress().String(), + "Address": evmCfg.EVM().Workflow().ForwarderAddress().String(), }) require.NoError(t, err) diff --git a/core/services/workflows/engine.go b/core/services/workflows/engine.go index edb1203c954..cfa15905f29 100644 --- a/core/services/workflows/engine.go +++ b/core/services/workflows/engine.go @@ -119,10 +119,10 @@ func (e *Engine) resolveWorkflowCapabilities(ctx context.Context) error { err := e.initializeCapability(ctx, s) if err != nil { - return err + return fmt.Errorf("failed to initialize capability for step %s: %w", s.Ref, err) } - return e.initializeExecutionStrategy(s) + return nil }) return capabilityRegistrationErr @@ -261,59 +261,6 @@ func (e *Engine) resumeInProgressExecutions(ctx context.Context) error { return nil } -// initializeExecutionStrategy for `step`. -// Broadly speaking, we'll use `immediateExecution` for non-target steps -// and `scheduledExecution` for targets. If we don't have the necessary -// config to initialize a scheduledExecution for a target, we'll fallback to -// using `immediateExecution`. -func (e *Engine) initializeExecutionStrategy(s *step) error { - if s.executionStrategy != nil { - return nil - } - - // If donInfo has no peerID, then the peer wrapper hasn't been initialized. - // Let's error and try again next time around. - if e.donInfo.PeerID() == nil { - return fmt.Errorf("failed to initialize execution strategy: peer ID %s has not been initialized", e.donInfo.PeerID()) - } - - ie := immediateExecution{} - if s.CapabilityType != capabilities.CapabilityTypeTarget { - e.logger.Debugf("initializing step %+v with immediate execution strategy: not a target", s) - s.executionStrategy = ie - return nil - } - - dinfo := e.donInfo - if dinfo.DON == nil { - e.logger.Debugf("initializing target step with immediate execution strategy: donInfo %+v", e.donInfo) - s.executionStrategy = ie - return nil - } - - var position *int - for i, w := range dinfo.Members { - if w == *dinfo.PeerID() { - idx := i - position = &idx - } - } - - if position == nil { - e.logger.Debugf("initializing step %+v with immediate execution strategy: position not found in donInfo %+v", s, e.donInfo) - s.executionStrategy = ie - return nil - } - - s.executionStrategy = scheduledExecution{ - DON: e.donInfo.DON, - Position: *position, - PeerID: e.donInfo.PeerID(), - } - e.logger.Debugf("initializing step %+v with scheduled execution strategy", s) - return nil -} - // registerTrigger is used during the initialization phase to bind a trigger to this workflow func (e *Engine) registerTrigger(ctx context.Context, t *triggerCapability) error { triggerInputs, err := values.NewMap( @@ -660,7 +607,7 @@ func (e *Engine) executeStep(ctx context.Context, l logger.Logger, msg stepReque }, } - output, err := step.executionStrategy.Apply(ctx, l, step.capability, tr) + output, err := executeSyncAndUnwrapSingleValue(ctx, step.capability, tr) if err != nil { return inputs, nil, err } @@ -865,3 +812,21 @@ func NewEngine(cfg Config) (engine *Engine, err error) { } return engine, nil } + +// ExecuteSyncAndUnwrapSingleValue is a convenience method that executes a capability synchronously and unwraps the +// result if it is a single value otherwise returns the list. +func executeSyncAndUnwrapSingleValue(ctx context.Context, cap capabilities.CallbackCapability, req capabilities.CapabilityRequest) (values.Value, error) { + l, err := capabilities.ExecuteSync(ctx, cap, req) + if err != nil { + return nil, err + } + + // `ExecuteSync` returns a `values.List` even if there was + // just one return value. If that is the case, let's unwrap the + // single value to make it easier to use in -- for example -- variable interpolation. + if len(l.Underlying) > 1 { + return l, nil + } + + return l.Underlying[0], nil +} diff --git a/core/services/workflows/engine_test.go b/core/services/workflows/engine_test.go index 808e0b2555d..aebb5c2066f 100644 --- a/core/services/workflows/engine_test.go +++ b/core/services/workflows/engine_test.go @@ -199,7 +199,7 @@ func TestEngineWithHardcodedWorkflow(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { ctx := testutils.Context(t) - reg := coreCap.NewRegistry(logger.TestLogger(t)) + reg := coreCap.NewRegistry(logger.TestLogger(t), p2ptypes.PeerID{}, capabilities.DON{}) trigger, cr := mockTrigger(t) @@ -386,7 +386,7 @@ func mockTarget() *mockCapability { func TestEngine_ErrorsTheWorkflowIfAStepErrors(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - reg := coreCap.NewRegistry(logger.TestLogger(t)) + reg := coreCap.NewRegistry(logger.TestLogger(t), p2ptypes.PeerID{}, capabilities.DON{}) trigger, _ := mockTrigger(t) @@ -480,7 +480,7 @@ func mockAction() (*mockCapability, values.Value) { func TestEngine_MultiStepDependencies(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - reg := coreCap.NewRegistry(logger.TestLogger(t)) + reg := coreCap.NewRegistry(logger.TestLogger(t), p2ptypes.PeerID{}, capabilities.DON{}) trigger, cr := mockTrigger(t) @@ -523,7 +523,7 @@ func TestEngine_MultiStepDependencies(t *testing.T) { func TestEngine_ResumesPendingExecutions(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - reg := coreCap.NewRegistry(logger.TestLogger(t)) + reg := coreCap.NewRegistry(logger.TestLogger(t), p2ptypes.PeerID{}, capabilities.DON{}) trigger := mockNoopTrigger(t) resp, err := values.NewMap(map[string]any{ @@ -577,7 +577,7 @@ func TestEngine_ResumesPendingExecutions(t *testing.T) { func TestEngine_TimesOutOldExecutions(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - reg := coreCap.NewRegistry(logger.TestLogger(t)) + reg := coreCap.NewRegistry(logger.TestLogger(t), p2ptypes.PeerID{}, capabilities.DON{}) trigger := mockNoopTrigger(t) resp, err := values.NewMap(map[string]any{ diff --git a/core/services/workflows/execution_strategy.go b/core/services/workflows/execution_strategy.go deleted file mode 100644 index 5cc8164c4f7..00000000000 --- a/core/services/workflows/execution_strategy.go +++ /dev/null @@ -1,95 +0,0 @@ -package workflows - -import ( - "context" - "fmt" - "time" - - "github.com/smartcontractkit/chainlink-common/pkg/capabilities" - "github.com/smartcontractkit/chainlink-common/pkg/values" - "github.com/smartcontractkit/chainlink/v2/core/capabilities/transmission" - "github.com/smartcontractkit/chainlink/v2/core/logger" - p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" -) - -type executionStrategy interface { - Apply(ctx context.Context, l logger.Logger, cap capabilities.CallbackCapability, req capabilities.CapabilityRequest) (values.Value, error) -} - -var _ executionStrategy = immediateExecution{} - -type immediateExecution struct{} - -func (i immediateExecution) Apply(ctx context.Context, lggr logger.Logger, cap capabilities.CallbackCapability, req capabilities.CapabilityRequest) (values.Value, error) { - l, err := capabilities.ExecuteSync(ctx, cap, req) - if err != nil { - return nil, err - } - - // `ExecuteSync` returns a `values.List` even if there was - // just one return value. If that is the case, let's unwrap the - // single value to make it easier to use in -- for example -- variable interpolation. - if len(l.Underlying) > 1 { - return l, nil - } - - return l.Underlying[0], nil -} - -var _ executionStrategy = scheduledExecution{} - -type scheduledExecution struct { - DON *capabilities.DON - PeerID *p2ptypes.PeerID - Position int -} - -// scheduledExecution generates a pseudo-random transmission schedule, -// and delays execution until a node is required to transmit. -func (d scheduledExecution) Apply(ctx context.Context, lggr logger.Logger, cap capabilities.CallbackCapability, req capabilities.CapabilityRequest) (values.Value, error) { - tc, err := transmission.ExtractTransmissionConfig(req.Config) - if err != nil { - return nil, fmt.Errorf("failed to extract transmission config from request config: %w", err) - } - - info, err := cap.Info(ctx) - if err != nil { - return nil, err - } - - switch { - // Case 1: Local DON - case info.DON == nil: - - // The transmission ID is created using the workflow ID and the workflow execution ID which nodes don't know - // ahead of time and ensures a malicious node cannot game the schedule. - peerIDToTransmissionDelay, err := transmission.GetPeerIDToTransmissionDelay(d.DON.Members, d.DON.Config.SharedSecret, - req.Metadata.WorkflowID+req.Metadata.WorkflowExecutionID, tc) - if err != nil { - return nil, fmt.Errorf("failed to get peer ID to transmission delay map: %w", err) - } - - delay, existsForPeerID := peerIDToTransmissionDelay[*d.PeerID] - if !existsForPeerID { - lggr.Debugw("skipping transmission: node is not included in schedule") - return nil, nil - } - - lggr.Debugf("execution delayed by %+v", delay) - select { - case <-ctx.Done(): - return nil, ctx.Err() - case <-time.After(delay): - lggr.Debugw("executing delayed execution") - return immediateExecution{}.Apply(ctx, lggr, cap, req) - } - // Case 2: Remote DON - default: - - // In this case just execute immediately on the capability and the shims will handle the scheduling and f+1 aggregation - - // TODO: fill in the remote DON case once consensus has been reach on what to do. - lggr.Debugw("remote DON transmission not implemented: using immediate execution") - return immediateExecution{}.Apply(ctx, lggr, cap, req) - } -} diff --git a/core/services/workflows/models.go b/core/services/workflows/models.go index 14e75c6e5d9..d55212a30ca 100644 --- a/core/services/workflows/models.go +++ b/core/services/workflows/models.go @@ -78,9 +78,8 @@ func (w *workflow) dependents(start string) ([]*step, error) { // step wraps a Vertex with additional context for execution that is mutated by the engine type step struct { workflows.Vertex - capability capabilities.CallbackCapability - config *values.Map - executionStrategy executionStrategy + capability capabilities.CallbackCapability + config *values.Map } type triggerCapability struct { diff --git a/core/web/router.go b/core/web/router.go index 9c5cb4b661d..5e90cea237b 100644 --- a/core/web/router.go +++ b/core/web/router.go @@ -415,7 +415,7 @@ func v2Routes(app chainlink.Application, r *gin.RouterGroup) { {"cosmos", NewCosmosNodesController(app)}, } { if chain.path == "evm" { - // TODO still EVM only https://app.shortcut.com/chainlinklabs/story/26276/multi-chain-type-ui-node-chain-configuration + // TODO still EVM only . Archive ticket: story/26276/multi-chain-type-ui-node-chain-configuration nodes.GET("", paginatedRequest(chain.nc.Index)) } nodes.GET(chain.path, paginatedRequest(chain.nc.Index)) diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 3a9829e8ec9..6c94b1d1f62 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -7076,8 +7076,6 @@ ChainType = 'arbitrum' # Example ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID. Available types: `arbitrum`, `celo`, `gnosis`, `kroma`, `metis`, `optimismBedrock`, `scroll`, `wemix`, `xlayer`, `zksync` -`xdai` has been deprecated and will be removed in v2.13.0, use `gnosis` instead. - ### FinalityDepth ```toml FinalityDepth = 50 # Default @@ -8002,9 +8000,9 @@ GasLimit = 5400000 # Default ``` GasLimit controls the gas limit for transmit transactions from ocr2automation job. -## EVM.ChainWriter +## EVM.Workflow ```toml -[EVM.ChainWriter] +[EVM.Workflow] FromAddress = '0x2a3e23c6f242F5345320814aC8a1b4E58707D292' # Example ForwarderAddress = '0x2a3e23c6f242F5345320814aC8a1b4E58707D292' # Example ``` diff --git a/go.mod b/go.mod index e4378e52905..819652f78f9 100644 --- a/go.mod +++ b/go.mod @@ -77,7 +77,7 @@ require ( github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240524201401-88d0b3763b20 - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240527073251-56197f1413e0 + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240531021326-99118e47f696 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 diff --git a/go.sum b/go.sum index 619581b6941..eb6ef514623 100644 --- a/go.sum +++ b/go.sum @@ -1181,8 +1181,8 @@ github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 h github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917/go.mod h1:jwVxhctE6BgLOSSsVq9wbREpZ8Ev34H+UBxeUhESZRs= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240524201401-88d0b3763b20 h1:ybdconEoRBHLwtDKlZKYaeanQ8UoVqdDiaTlPV+qEiI= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240524201401-88d0b3763b20/go.mod h1:QqcZSwLgEIn7YraAIRmomnBMAuVFephiHrIWVlkWbFI= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240527073251-56197f1413e0 h1:5QNKQTQpIp+0ogXUu9B85tEie473RZttOhYxM2vHyOc= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240527073251-56197f1413e0/go.mod h1:OiWUTrrpSLLTMh7FINWjEh6mmDJCVPaC4yEsDCVaWdU= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240531021326-99118e47f696 h1:h1E87+z+JcUEfvbJVF56SnZA/YUFE5ewUE61MaR/Ewg= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240531021326-99118e47f696/go.mod h1:OiWUTrrpSLLTMh7FINWjEh6mmDJCVPaC4yEsDCVaWdU= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 h1:TFe+FvzxClblt6qRfqEhUfa4kFQx5UobuoFGO2W4mMo= diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index f5a5e558572..098b273d9bb 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -73,6 +73,7 @@ type CLTestEnvBuilder struct { var DefaultAllowedMessages = []testreporters.AllowedLogMessage{ testreporters.NewAllowedLogMessage("Failed to get LINK balance", "Happens only when we deploy LINK token for test purposes. Harmless.", zapcore.ErrorLevel, testreporters.WarnAboutAllowedMsgs_No), testreporters.NewAllowedLogMessage("Error stopping job service", "It's a known issue with lifecycle. There's ongoing work that will fix it.", zapcore.DPanicLevel, testreporters.WarnAboutAllowedMsgs_No), + testreporters.NewAllowedLogMessage("SLOW SQL QUERY", "Known issue in Automation Node Upgrade Test - https://smartcontract-it.atlassian.net/browse/BCF-3245", zapcore.DPanicLevel, testreporters.WarnAboutAllowedMsgs_No), } var DefaultChainlinkNodeLogScannerSettings = ChainlinkNodeLogScannerSettings{ diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 10381e8bafb..2da768940a2 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -379,7 +379,7 @@ require ( github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240524201401-88d0b3763b20 // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240527073251-56197f1413e0 // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240531021326-99118e47f696 // indirect github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240328204215-ac91f55f1449 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index ced20a370a6..4db4a7f7098 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1522,8 +1522,8 @@ github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 h github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917/go.mod h1:jwVxhctE6BgLOSSsVq9wbREpZ8Ev34H+UBxeUhESZRs= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240524201401-88d0b3763b20 h1:ybdconEoRBHLwtDKlZKYaeanQ8UoVqdDiaTlPV+qEiI= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240524201401-88d0b3763b20/go.mod h1:QqcZSwLgEIn7YraAIRmomnBMAuVFephiHrIWVlkWbFI= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240527073251-56197f1413e0 h1:5QNKQTQpIp+0ogXUu9B85tEie473RZttOhYxM2vHyOc= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240527073251-56197f1413e0/go.mod h1:OiWUTrrpSLLTMh7FINWjEh6mmDJCVPaC4yEsDCVaWdU= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240531021326-99118e47f696 h1:h1E87+z+JcUEfvbJVF56SnZA/YUFE5ewUE61MaR/Ewg= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240531021326-99118e47f696/go.mod h1:OiWUTrrpSLLTMh7FINWjEh6mmDJCVPaC4yEsDCVaWdU= github.com/smartcontractkit/chainlink-testing-framework v1.28.17 h1:zezoeiG3GUGW1T2+genS/HD1BvRJwC3rqFnFTFNB9aY= github.com/smartcontractkit/chainlink-testing-framework v1.28.17/go.mod h1:xjxJK+4SUjBmJJWfRFl02poauU4XQE37aH7WYtxTLKg= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240328204215-ac91f55f1449 h1:fX/xmGm1GBsD1ZZnooNT+eWA0hiTAqFlHzOC5CY4dy8= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 8975752427e..ff58b0b5314 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -368,7 +368,7 @@ require ( github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240524201401-88d0b3763b20 // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240527073251-56197f1413e0 // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240531021326-99118e47f696 // indirect github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240328204215-ac91f55f1449 // indirect github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index e70edaa726b..30eb0673aa7 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1512,8 +1512,8 @@ github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 h github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917/go.mod h1:jwVxhctE6BgLOSSsVq9wbREpZ8Ev34H+UBxeUhESZRs= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240524201401-88d0b3763b20 h1:ybdconEoRBHLwtDKlZKYaeanQ8UoVqdDiaTlPV+qEiI= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240524201401-88d0b3763b20/go.mod h1:QqcZSwLgEIn7YraAIRmomnBMAuVFephiHrIWVlkWbFI= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240527073251-56197f1413e0 h1:5QNKQTQpIp+0ogXUu9B85tEie473RZttOhYxM2vHyOc= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240527073251-56197f1413e0/go.mod h1:OiWUTrrpSLLTMh7FINWjEh6mmDJCVPaC4yEsDCVaWdU= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240531021326-99118e47f696 h1:h1E87+z+JcUEfvbJVF56SnZA/YUFE5ewUE61MaR/Ewg= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240531021326-99118e47f696/go.mod h1:OiWUTrrpSLLTMh7FINWjEh6mmDJCVPaC4yEsDCVaWdU= github.com/smartcontractkit/chainlink-testing-framework v1.28.17 h1:zezoeiG3GUGW1T2+genS/HD1BvRJwC3rqFnFTFNB9aY= github.com/smartcontractkit/chainlink-testing-framework v1.28.17/go.mod h1:xjxJK+4SUjBmJJWfRFl02poauU4XQE37aH7WYtxTLKg= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240328204215-ac91f55f1449 h1:fX/xmGm1GBsD1ZZnooNT+eWA0hiTAqFlHzOC5CY4dy8= diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar index 3a8f97fb64b..c047b90c133 100644 --- a/testdata/scripts/node/validate/warnings.txtar +++ b/testdata/scripts/node/validate/warnings.txtar @@ -9,15 +9,6 @@ CollectorTarget = 'otel-collector:4317' TLSCertPath = 'something' Mode = 'unencrypted' -[[EVM]] -ChainID = '10200' -ChainType = 'xdai' - -[[EVM.Nodes]] -Name = 'fake' -WSURL = 'wss://foo.bar/ws' -HTTPURL = 'https://foo.bar' - -- secrets.toml -- [Database] URL = 'postgresql://user:pass1234567890abcd@localhost:5432/dbname?sslmode=disable' @@ -41,15 +32,6 @@ CollectorTarget = 'otel-collector:4317' Mode = 'unencrypted' TLSCertPath = 'something' -[[EVM]] -ChainID = '10200' -ChainType = 'xdai' - -[[EVM.Nodes]] -Name = 'fake' -WSURL = 'wss://foo.bar/ws' -HTTPURL = 'https://foo.bar' - # Effective Configuration, with defaults applied: InsecureFastScrypt = false RootDir = '~/.chainlink' @@ -302,99 +284,6 @@ DeltaDial = '15s' DeltaReconcile = '1m0s' ListenAddresses = [] -[[EVM]] -ChainID = '10200' -AutoCreateKey = true -BlockBackfillDepth = 10 -BlockBackfillSkip = false -ChainType = 'xdai' -FinalityDepth = 100 -FinalityTagEnabled = false -LogBackfillBatchSize = 1000 -LogPollInterval = '5s' -LogKeepBlocksDepth = 100000 -LogPrunePageSize = 0 -BackupLogPollerBlockDelay = 100 -MinIncomingConfirmations = 3 -MinContractPayment = '0.00001 link' -NonceAutoSync = true -NoNewHeadsThreshold = '3m0s' -RPCDefaultBatchSize = 250 -RPCBlockQueryDelay = 1 - -[EVM.Transactions] -ForwardersEnabled = false -MaxInFlight = 16 -MaxQueued = 250 -ReaperInterval = '1h0m0s' -ReaperThreshold = '168h0m0s' -ResendAfterThreshold = '1m0s' - -[EVM.Transactions.AutoPurge] -Enabled = false - -[EVM.BalanceMonitor] -Enabled = true - -[EVM.GasEstimator] -Mode = 'BlockHistory' -PriceDefault = '20 gwei' -PriceMax = '500 gwei' -PriceMin = '1 gwei' -LimitDefault = 500000 -LimitMax = 500000 -LimitMultiplier = '1' -LimitTransfer = 21000 -BumpMin = '5 gwei' -BumpPercent = 20 -BumpThreshold = 3 -EIP1559DynamicFees = true -FeeCapDefault = '100 gwei' -TipCapDefault = '1 wei' -TipCapMin = '1 wei' - -[EVM.GasEstimator.BlockHistory] -BatchSize = 25 -BlockHistorySize = 8 -CheckInclusionBlocks = 12 -CheckInclusionPercentile = 90 -TransactionPercentile = 60 - -[EVM.HeadTracker] -HistoryDepth = 100 -MaxBufferSize = 3 -SamplingInterval = '1s' -MaxAllowedFinalityDepth = 10000 -FinalityTagBypass = true - -[EVM.NodePool] -PollFailureThreshold = 5 -PollInterval = '10s' -SelectionMode = 'HighestHead' -SyncThreshold = 5 -LeaseDuration = '0s' -NodeIsSyncingEnabled = false -FinalizedBlockPollInterval = '5s' - -[EVM.OCR] -ContractConfirmations = 4 -ContractTransmitterTransmitTimeout = '10s' -DatabaseTimeout = '10s' -DeltaCOverride = '168h0m0s' -DeltaCJitterOverride = '1h0m0s' -ObservationGracePeriod = '1s' - -[EVM.OCR2] -[EVM.OCR2.Automation] -GasLimit = 5400000 - -[[EVM.Nodes]] -Name = 'fake' -WSURL = 'wss://foo.bar/ws' -HTTPURL = 'https://foo.bar' - # Configuration warning: -2 errors: - - EVM.ChainType: invalid value (xdai): deprecated and will be removed in v2.13.0, use 'gnosis' instead - - Tracing.TLSCertPath: invalid value (something): must be empty when Tracing.Mode is 'unencrypted' +Tracing.TLSCertPath: invalid value (something): must be empty when Tracing.Mode is 'unencrypted' Valid configuration. \ No newline at end of file