From 018e53044bf4bc570bf1d54aa4ad65619ef09900 Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Wed, 5 Mar 2025 11:02:01 -0400 Subject: [PATCH 01/13] Restores forwarder view using labels from the address book --- deployment/keystone/changeset/state.go | 32 +++++-- deployment/keystone/changeset/view.go | 2 +- .../keystone/changeset/view_contracts.go | 91 ++++++++++++++++++- 3 files changed, 114 insertions(+), 11 deletions(-) diff --git a/deployment/keystone/changeset/state.go b/deployment/keystone/changeset/state.go index 9c06e38b458..e54ff50459d 100644 --- a/deployment/keystone/changeset/state.go +++ b/deployment/keystone/changeset/state.go @@ -1,6 +1,7 @@ package changeset import ( + "context" "errors" "fmt" @@ -33,10 +34,15 @@ type GetContractSetsResponse struct { ContractSets map[uint64]ContractSet } +type ForwarderContract struct { + Contract *forwarder.KeystoneForwarder + TypeAndVersion deployment.TypeAndVersion +} + type ContractSet struct { commonchangeset.MCMSWithTimelockState OCR3 map[common.Address]*ocr3_capability.OCR3Capability - Forwarder *forwarder.KeystoneForwarder + Forwarder *ForwarderContract CapabilitiesRegistry *capabilities_registry.CapabilitiesRegistry WorkflowRegistry *workflow_registry.WorkflowRegistry } @@ -46,7 +52,7 @@ func (cs ContractSet) Convert() internal.ContractSet { MCMSWithTimelockState: commonchangeset.MCMSWithTimelockState{ MCMSWithTimelockContracts: cs.MCMSWithTimelockContracts, }, - Forwarder: cs.Forwarder, + Forwarder: cs.Forwarder.Contract, WorkflowRegistry: cs.WorkflowRegistry, OCR3: cs.OCR3, CapabilitiesRegistry: cs.CapabilitiesRegistry, @@ -61,7 +67,7 @@ func (cs ContractSet) TransferableContracts() []common.Address { } } if cs.Forwarder != nil { - out = append(out, cs.Forwarder.Address()) + out = append(out, cs.Forwarder.Contract.Address()) } if cs.CapabilitiesRegistry != nil { out = append(out, cs.CapabilitiesRegistry.Address()) @@ -73,8 +79,8 @@ func (cs ContractSet) TransferableContracts() []common.Address { } // View is a view of the keystone chain -// It is best effort and logs errors -func (cs ContractSet) View(lggr logger.Logger) (KeystoneChainView, error) { +// It is best-effort and logs errors +func (cs ContractSet) View(ctx context.Context, lggr logger.Logger) (KeystoneChainView, error) { out := NewKeystoneChainView() var allErrs error if cs.CapabilitiesRegistry != nil { @@ -90,7 +96,7 @@ func (cs ContractSet) View(lggr logger.Logger) (KeystoneChainView, error) { for addr, ocr3Cap := range cs.OCR3 { oc := *ocr3Cap addrCopy := addr - ocrView, err := GenerateOCR3ConfigView(oc) + ocrView, err := GenerateOCR3ConfigView(ctx, oc) if err != nil { allErrs = errors.Join(allErrs, err) // don't block view on single OCR3 not being configured @@ -114,6 +120,15 @@ func (cs ContractSet) View(lggr logger.Logger) (KeystoneChainView, error) { out.WorkflowRegistry[cs.WorkflowRegistry.Address().String()] = wrView } + if cs.Forwarder != nil { + fwrView, fwrErr := GenerateForwarderView(ctx, cs.Forwarder) + if fwrErr != nil { + allErrs = errors.Join(allErrs, fwrErr) + lggr.Errorf("failed to generate forwarder view: %v", fwrErr) + } + out.Forwarders[cs.Forwarder.Contract.Address().String()] = fwrView + } + return out, allErrs } @@ -179,7 +194,10 @@ func loadContractSet(lggr logger.Logger, chain deployment.Chain, addresses map[s if err != nil { return nil, fmt.Errorf("failed to create forwarder contract from address %s: %w", addr, err) } - out.Forwarder = c + out.Forwarder = &ForwarderContract{ + Contract: c, + TypeAndVersion: tv, + } case OCR3Capability: c, err := ocr3_capability.NewOCR3Capability(common.HexToAddress(addr), chain.Client) if err != nil { diff --git a/deployment/keystone/changeset/view.go b/deployment/keystone/changeset/view.go index 0a5667781ed..40d2ad961f0 100644 --- a/deployment/keystone/changeset/view.go +++ b/deployment/keystone/changeset/view.go @@ -40,7 +40,7 @@ func ViewKeystone(e deployment.Environment) (json.Marshaler, error) { viewErrs = errors.Join(viewErrs, err2) continue } - v, err := contracts.View(e.Logger) + v, err := contracts.View(e.GetContext(), e.Logger) if err != nil { err2 := fmt.Errorf("failed to view chain %s: %w", chainName, err) lggr.Error(err2) diff --git a/deployment/keystone/changeset/view_contracts.go b/deployment/keystone/changeset/view_contracts.go index a5868f4d74e..c80bd06cec4 100644 --- a/deployment/keystone/changeset/view_contracts.go +++ b/deployment/keystone/changeset/view_contracts.go @@ -1,13 +1,18 @@ package changeset import ( + "context" "encoding/hex" "encoding/json" "errors" + "fmt" "math" + "strconv" + "strings" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" "google.golang.org/protobuf/proto" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" @@ -15,6 +20,7 @@ import ( capocr3types "github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3/types" + forwarder "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/forwarder_1_0_0" ocr3_capability "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/ocr3_capability_1_0_0" "github.com/smartcontractkit/chainlink/deployment/common/view" @@ -26,6 +32,7 @@ type KeystoneChainView struct { // OCRContracts is a map of OCR3 contract addresses to their configuration view OCRContracts map[string]OCR3ConfigView `json:"ocrContracts,omitempty"` WorkflowRegistry map[string]common_v1_0.WorkflowRegistryView `json:"workflowRegistry,omitempty"` + Forwarders map[string][]ForwarderView `json:"forwarders,omitempty"` } type OCR3ConfigView struct { @@ -37,9 +44,21 @@ type OCR3ConfigView struct { OffchainConfig OracleConfig `json:"offchainConfig"` } -var ErrOCR3NotConfigured = errors.New("OCR3 not configured") +type ForwarderView struct { + DonID uint32 `json:"donId"` + ConfigVersion uint32 `json:"configVersion"` + F uint8 `json:"f"` + Signers []string `json:"signers"` + TxHash string `json:"txHash,omitempty"` + BlockNumber uint64 `json:"blockNumber,omitempty"` +} + +var ( + ErrOCR3NotConfigured = errors.New("OCR3 not configured") + ErrForwarderNotConfigured = errors.New("forwarder not configured") +) -func GenerateOCR3ConfigView(ocr3Cap ocr3_capability.OCR3Capability) (OCR3ConfigView, error) { +func GenerateOCR3ConfigView(ctx context.Context, ocr3Cap ocr3_capability.OCR3Capability) (OCR3ConfigView, error) { details, err := ocr3Cap.LatestConfigDetails(nil) if err != nil { return OCR3ConfigView{}, err @@ -49,7 +68,7 @@ func GenerateOCR3ConfigView(ocr3Cap ocr3_capability.OCR3Capability) (OCR3ConfigV configIterator, err := ocr3Cap.FilterConfigSet(&bind.FilterOpts{ Start: blockNumber, End: &blockNumber, - Context: nil, + Context: ctx, }) if err != nil { return OCR3ConfigView{}, err @@ -135,6 +154,71 @@ func GenerateOCR3ConfigView(ocr3Cap ocr3_capability.OCR3Capability) (OCR3ConfigV }, nil } +func GenerateForwarderView(ctx context.Context, f *ForwarderContract) ([]ForwarderView, error) { + var deploymentBlock uint64 + lblPrefix := internal.DeploymentBlockLabel + ": " + for lbl := range f.TypeAndVersion.Labels { + if strings.HasPrefix(lbl, lblPrefix) { + // Extract the block number part after the prefix + blockStr := strings.TrimPrefix(lbl, lblPrefix) + blockNum, err := strconv.ParseUint(blockStr, 10, 64) + if err == nil { + deploymentBlock = blockNum + break + } + } + } + + startBlock := uint64(0) + if deploymentBlock > 0 { + startBlock = deploymentBlock + } + + // Let's fetch the `SetConfig` events since the deployment block, since we don't have specific block numbers + // for the `SetConfig` events. + // If no deployment block is available, it will start from 0. + configIterator, err := f.Contract.FilterConfigSet(&bind.FilterOpts{ + Start: startBlock, + End: nil, + Context: ctx, + }, nil, nil) + if err != nil { + return nil, fmt.Errorf("error filtering ConfigSet events: %w", err) + } + + configSets := make([]*forwarder.KeystoneForwarderConfigSet, 0) + for configIterator.Next() { + // We wait for the iterator to receive an event + if configIterator.Event == nil { + // We cannot return an error, since we are capturing all `SetConfig` events, so if there's a nil event, + // we ignore it. + continue + } + configSets = append(configSets, configIterator.Event) + } + if len(configSets) == 0 { + return nil, ErrForwarderNotConfigured + } + + var forwarderViews []ForwarderView + for _, configSet := range configSets { + var readableSigners []string + for _, s := range configSet.Signers { + readableSigners = append(readableSigners, s.String()) + } + forwarderViews = append(forwarderViews, ForwarderView{ + DonID: configSet.DonId, + ConfigVersion: configSet.ConfigVersion, + F: configSet.F, + Signers: readableSigners, + TxHash: configSet.Raw.TxHash.String(), + BlockNumber: configSet.Raw.BlockNumber, + }) + } + + return forwarderViews, nil +} + func millisecondsToUint32(dur time.Duration) uint32 { ms := dur.Milliseconds() if ms > int64(math.MaxUint32) { @@ -149,6 +233,7 @@ func NewKeystoneChainView() KeystoneChainView { CapabilityRegistry: make(map[string]common_v1_0.CapabilityRegistryView), OCRContracts: make(map[string]OCR3ConfigView), WorkflowRegistry: make(map[string]common_v1_0.WorkflowRegistryView), + Forwarders: make(map[string][]ForwarderView), } } From b69e261b641f42367515fd5a00e81f26d8e7569b Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Wed, 5 Mar 2025 11:45:08 -0400 Subject: [PATCH 02/13] Warns on forwarder not configured --- deployment/keystone/changeset/state.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/deployment/keystone/changeset/state.go b/deployment/keystone/changeset/state.go index e54ff50459d..151932ea957 100644 --- a/deployment/keystone/changeset/state.go +++ b/deployment/keystone/changeset/state.go @@ -124,7 +124,11 @@ func (cs ContractSet) View(ctx context.Context, lggr logger.Logger) (KeystoneCha fwrView, fwrErr := GenerateForwarderView(ctx, cs.Forwarder) if fwrErr != nil { allErrs = errors.Join(allErrs, fwrErr) - lggr.Errorf("failed to generate forwarder view: %v", fwrErr) + if errors.Is(fwrErr, ErrForwarderNotConfigured) { + lggr.Warnf("forwarder not configured for address %s", cs.Forwarder.Contract.Address()) + } else { + lggr.Errorf("failed to generate forwarder view: %v", fwrErr) + } } out.Forwarders[cs.Forwarder.Contract.Address().String()] = fwrView } From 9c6a587053c760554baf36be271e317b6f6e6486 Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Wed, 5 Mar 2025 12:10:26 -0400 Subject: [PATCH 03/13] Prevents view blocking on non-configured contracts --- deployment/keystone/changeset/state.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deployment/keystone/changeset/state.go b/deployment/keystone/changeset/state.go index 151932ea957..98277528721 100644 --- a/deployment/keystone/changeset/state.go +++ b/deployment/keystone/changeset/state.go @@ -98,11 +98,11 @@ func (cs ContractSet) View(ctx context.Context, lggr logger.Logger) (KeystoneCha addrCopy := addr ocrView, err := GenerateOCR3ConfigView(ctx, oc) if err != nil { - allErrs = errors.Join(allErrs, err) // don't block view on single OCR3 not being configured if errors.Is(err, ErrOCR3NotConfigured) { lggr.Warnf("ocr3 not configured for address %s", addr) } else { + allErrs = errors.Join(allErrs, err) lggr.Errorf("failed to generate OCR3 config view: %v", err) } } @@ -123,10 +123,11 @@ func (cs ContractSet) View(ctx context.Context, lggr logger.Logger) (KeystoneCha if cs.Forwarder != nil { fwrView, fwrErr := GenerateForwarderView(ctx, cs.Forwarder) if fwrErr != nil { - allErrs = errors.Join(allErrs, fwrErr) + // don't block view on single forwarder not being configured if errors.Is(fwrErr, ErrForwarderNotConfigured) { lggr.Warnf("forwarder not configured for address %s", cs.Forwarder.Contract.Address()) } else { + allErrs = errors.Join(allErrs, fwrErr) lggr.Errorf("failed to generate forwarder view: %v", fwrErr) } } From 10aa29cba51b92b2ab8178bea05b4282d50e6093 Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Wed, 5 Mar 2025 13:51:02 -0400 Subject: [PATCH 04/13] Uses prev view to generate forwarder view --- deployment/ccip/changeset/view.go | 2 +- deployment/changeset.go | 2 +- deployment/data-feeds/changeset/view.go | 2 +- deployment/exemplar/changeset/view.go | 2 +- deployment/keystone/changeset/state.go | 19 +++++-- deployment/keystone/changeset/view.go | 12 ++++- .../keystone/changeset/view_contracts.go | 49 ++++++++++++------- 7 files changed, 62 insertions(+), 26 deletions(-) diff --git a/deployment/ccip/changeset/view.go b/deployment/ccip/changeset/view.go index 9d33368c721..e3f897b58be 100644 --- a/deployment/ccip/changeset/view.go +++ b/deployment/ccip/changeset/view.go @@ -11,7 +11,7 @@ import ( var _ deployment.ViewState = ViewCCIP -func ViewCCIP(e deployment.Environment) (json.Marshaler, error) { +func ViewCCIP(e deployment.Environment, _ []byte) (json.Marshaler, error) { state, err := LoadOnchainState(e) if err != nil { return nil, err diff --git a/deployment/changeset.go b/deployment/changeset.go index dfa1fbae7e5..89592cb0b21 100644 --- a/deployment/changeset.go +++ b/deployment/changeset.go @@ -113,4 +113,4 @@ type ChangesetOutput struct { // ViewState produces a product specific JSON representation of // the on and offchain state of the environment. -type ViewState func(e Environment) (json.Marshaler, error) +type ViewState func(e Environment, previousState []byte) (json.Marshaler, error) diff --git a/deployment/data-feeds/changeset/view.go b/deployment/data-feeds/changeset/view.go index 15348e1f8e1..ca68499c900 100644 --- a/deployment/data-feeds/changeset/view.go +++ b/deployment/data-feeds/changeset/view.go @@ -10,7 +10,7 @@ import ( var _ deployment.ViewState = ViewDataFeeds -func ViewDataFeeds(e deployment.Environment) (json.Marshaler, error) { +func ViewDataFeeds(e deployment.Environment, _ []byte) (json.Marshaler, error) { state, err := LoadOnchainState(e) fmt.Println(state) if err != nil { diff --git a/deployment/exemplar/changeset/view.go b/deployment/exemplar/changeset/view.go index 76784533ad3..aee2c8a679b 100644 --- a/deployment/exemplar/changeset/view.go +++ b/deployment/exemplar/changeset/view.go @@ -20,7 +20,7 @@ func (v *ExemplarView) MarshalJSON() ([]byte, error) { } // ViewExemplar extracts basic information from the environment -var ViewExemplar deployment.ViewState = func(e deployment.Environment) (json.Marshaler, error) { +var ViewExemplar deployment.ViewState = func(e deployment.Environment, _ []byte) (json.Marshaler, error) { lggr := e.Logger lggr.Info("Generating exemplar state view") diff --git a/deployment/keystone/changeset/state.go b/deployment/keystone/changeset/state.go index 98277528721..4c67a477abd 100644 --- a/deployment/keystone/changeset/state.go +++ b/deployment/keystone/changeset/state.go @@ -80,7 +80,7 @@ func (cs ContractSet) TransferableContracts() []common.Address { // View is a view of the keystone chain // It is best-effort and logs errors -func (cs ContractSet) View(ctx context.Context, lggr logger.Logger) (KeystoneChainView, error) { +func (cs ContractSet) View(ctx context.Context, prevView KeystoneChainView, lggr logger.Logger) (KeystoneChainView, error) { out := NewKeystoneChainView() var allErrs error if cs.CapabilitiesRegistry != nil { @@ -121,7 +121,20 @@ func (cs ContractSet) View(ctx context.Context, lggr logger.Logger) (KeystoneCha } if cs.Forwarder != nil { - fwrView, fwrErr := GenerateForwarderView(ctx, cs.Forwarder) + fwrAddr := cs.Forwarder.Contract.Address().String() + var prevViews []ForwarderView + if prevView.Forwarders != nil { + pv, ok := prevView.Forwarders[fwrAddr] + if !ok { + prevViews = []ForwarderView{} + } else { + prevViews = pv + } + } else { + prevViews = []ForwarderView{} + } + + fwrView, fwrErr := GenerateForwarderView(ctx, cs.Forwarder, prevViews) if fwrErr != nil { // don't block view on single forwarder not being configured if errors.Is(fwrErr, ErrForwarderNotConfigured) { @@ -131,7 +144,7 @@ func (cs ContractSet) View(ctx context.Context, lggr logger.Logger) (KeystoneCha lggr.Errorf("failed to generate forwarder view: %v", fwrErr) } } - out.Forwarders[cs.Forwarder.Contract.Address().String()] = fwrView + out.Forwarders[fwrAddr] = fwrView } return out, allErrs diff --git a/deployment/keystone/changeset/view.go b/deployment/keystone/changeset/view.go index 40d2ad961f0..83d77fbee65 100644 --- a/deployment/keystone/changeset/view.go +++ b/deployment/keystone/changeset/view.go @@ -13,7 +13,7 @@ import ( var _ deployment.ViewState = ViewKeystone -func ViewKeystone(e deployment.Environment) (json.Marshaler, error) { +func ViewKeystone(e deployment.Environment, previousView []byte) (json.Marshaler, error) { lggr := e.Logger state, err := GetContractSets(e.Logger, &GetContractSetsRequest{ Chains: e.Chains, @@ -23,6 +23,14 @@ func ViewKeystone(e deployment.Environment) (json.Marshaler, error) { if err != nil { return nil, fmt.Errorf("failed to get contract sets: %w", err) } + var prevView KeystoneView + if previousView == nil || len(previousView) == 0 { + prevView.Chains = make(map[string]KeystoneChainView) + } else if err = json.Unmarshal(previousView, &prevView); err != nil { + lggr.Warnf("failed to unmarshal previous keystone view: %v", err) + prevView.Chains = make(map[string]KeystoneChainView) + } + var viewErrs error chainViews := make(map[string]KeystoneChainView) for chainSel, contracts := range state.ContractSets { @@ -40,7 +48,7 @@ func ViewKeystone(e deployment.Environment) (json.Marshaler, error) { viewErrs = errors.Join(viewErrs, err2) continue } - v, err := contracts.View(e.GetContext(), e.Logger) + v, err := contracts.View(e.GetContext(), prevView.Chains[chainName], e.Logger) if err != nil { err2 := fmt.Errorf("failed to view chain %s: %w", chainName, err) lggr.Error(err2) diff --git a/deployment/keystone/changeset/view_contracts.go b/deployment/keystone/changeset/view_contracts.go index c80bd06cec4..39cc515b43e 100644 --- a/deployment/keystone/changeset/view_contracts.go +++ b/deployment/keystone/changeset/view_contracts.go @@ -7,12 +7,12 @@ import ( "errors" "fmt" "math" + "sort" "strconv" "strings" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" "google.golang.org/protobuf/proto" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment/common/view" common_v1_0 "github.com/smartcontractkit/chainlink/deployment/common/view/v1_0" + "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" ) type KeystoneChainView struct { @@ -154,24 +155,37 @@ func GenerateOCR3ConfigView(ctx context.Context, ocr3Cap ocr3_capability.OCR3Cap }, nil } -func GenerateForwarderView(ctx context.Context, f *ForwarderContract) ([]ForwarderView, error) { - var deploymentBlock uint64 - lblPrefix := internal.DeploymentBlockLabel + ": " - for lbl := range f.TypeAndVersion.Labels { - if strings.HasPrefix(lbl, lblPrefix) { - // Extract the block number part after the prefix - blockStr := strings.TrimPrefix(lbl, lblPrefix) - blockNum, err := strconv.ParseUint(blockStr, 10, 64) - if err == nil { - deploymentBlock = blockNum - break +func GenerateForwarderView(ctx context.Context, f *ForwarderContract, prevViews []ForwarderView) ([]ForwarderView, error) { + startBlock := uint64(0) + + if len(prevViews) > 0 { + // Sort `prevViews` by block number in ascending order, we make sure the last item has the highest block number + sort.Slice(prevViews, func(i, j int) bool { + return prevViews[i].BlockNumber < prevViews[j].BlockNumber + }) + + // If we have previous views, we will start from the last block number +1 of the previous views + startBlock = prevViews[len(prevViews)-1].BlockNumber + 1 + } else { + // If we don't have previous views, we will start from the deployment block number + // which is stored in the forwarder's type and version labels. + var deploymentBlock uint64 + lblPrefix := internal.DeploymentBlockLabel + ": " + for lbl := range f.TypeAndVersion.Labels { + if strings.HasPrefix(lbl, lblPrefix) { + // Extract the block number part after the prefix + blockStr := strings.TrimPrefix(lbl, lblPrefix) + blockNum, err := strconv.ParseUint(blockStr, 10, 64) + if err == nil { + deploymentBlock = blockNum + break + } } } - } - startBlock := uint64(0) - if deploymentBlock > 0 { - startBlock = deploymentBlock + if deploymentBlock > 0 { + startBlock = deploymentBlock + } } // Let's fetch the `SetConfig` events since the deployment block, since we don't have specific block numbers @@ -200,7 +214,8 @@ func GenerateForwarderView(ctx context.Context, f *ForwarderContract) ([]Forward return nil, ErrForwarderNotConfigured } - var forwarderViews []ForwarderView + // We now create a slice with all previous views and the new views, so they get all added to the final view. + forwarderViews := append([]ForwarderView{}, prevViews...) for _, configSet := range configSets { var readableSigners []string for _, s := range configSet.Signers { From 9b60af59a5717ec470a58caf711f32e8cacf50fc Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Wed, 5 Mar 2025 14:48:18 -0400 Subject: [PATCH 05/13] Parallelizes Keystone View generation --- deployment/keystone/changeset/state.go | 140 +++++++++++++++++-------- 1 file changed, 94 insertions(+), 46 deletions(-) diff --git a/deployment/keystone/changeset/state.go b/deployment/keystone/changeset/state.go index 4c67a477abd..f21d2da409c 100644 --- a/deployment/keystone/changeset/state.go +++ b/deployment/keystone/changeset/state.go @@ -4,6 +4,8 @@ import ( "context" "errors" "fmt" + "sync" + "time" "github.com/ethereum/go-ethereum/common" @@ -79,73 +81,119 @@ func (cs ContractSet) TransferableContracts() []common.Address { } // View is a view of the keystone chain -// It is best-effort and logs errors +// It is best-effort, logs errors and generates the views in parallel. func (cs ContractSet) View(ctx context.Context, prevView KeystoneChainView, lggr logger.Logger) (KeystoneChainView, error) { out := NewKeystoneChainView() var allErrs error + var wg sync.WaitGroup + errCh := make(chan error, 4) // We are generating 4 views concurrently + + ctx, cancel := context.WithTimeout(ctx, 3*time.Minute) + defer cancel() + if cs.CapabilitiesRegistry != nil { - capRegView, err := common_v1_0.GenerateCapabilityRegistryView(cs.CapabilitiesRegistry) - if err != nil { - allErrs = errors.Join(allErrs, err) - lggr.Warn("failed to generate capability registry view: %w", err) - } - out.CapabilityRegistry[cs.CapabilitiesRegistry.Address().String()] = capRegView + wg.Add(1) + go func() { + defer wg.Done() + capRegView, err := common_v1_0.GenerateCapabilityRegistryView(cs.CapabilitiesRegistry) + if err != nil { + lggr.Warn("failed to generate capability registry view: %w", err) + errCh <- err + } + out.CapabilityRegistry[cs.CapabilitiesRegistry.Address().String()] = capRegView + }() } if cs.OCR3 != nil { - for addr, ocr3Cap := range cs.OCR3 { - oc := *ocr3Cap - addrCopy := addr - ocrView, err := GenerateOCR3ConfigView(ctx, oc) - if err != nil { - // don't block view on single OCR3 not being configured - if errors.Is(err, ErrOCR3NotConfigured) { - lggr.Warnf("ocr3 not configured for address %s", addr) - } else { - allErrs = errors.Join(allErrs, err) - lggr.Errorf("failed to generate OCR3 config view: %v", err) + wg.Add(1) + go func() { + defer wg.Done() + for addr, ocr3Cap := range cs.OCR3 { + select { + case <-ctx.Done(): + return + default: + oc := *ocr3Cap + addrCopy := addr + ocrView, err := GenerateOCR3ConfigView(ctx, oc) + if err != nil { + // don't block view on single OCR3 not being configured + if errors.Is(err, ErrOCR3NotConfigured) { + lggr.Warnf("ocr3 not configured for address %s", addr) + } else { + lggr.Errorf("failed to generate OCR3 config view: %v", err) + errCh <- err + } + } + out.OCRContracts[addrCopy.String()] = ocrView } } - out.OCRContracts[addrCopy.String()] = ocrView - } + }() } // Process the workflow registry and print if WorkflowRegistryError errors. if cs.WorkflowRegistry != nil { - wrView, wrErrs := common_v1_0.GenerateWorkflowRegistryView(cs.WorkflowRegistry) - for _, err := range wrErrs { - allErrs = errors.Join(allErrs, err) - lggr.Errorf("WorkflowRegistry error: %v", err) - } - out.WorkflowRegistry[cs.WorkflowRegistry.Address().String()] = wrView + wg.Add(1) + go func() { + defer wg.Done() + wrView, wrErrs := common_v1_0.GenerateWorkflowRegistryView(cs.WorkflowRegistry) + for _, err := range wrErrs { + lggr.Errorf("WorkflowRegistry error: %v", err) + errCh <- err + } + out.WorkflowRegistry[cs.WorkflowRegistry.Address().String()] = wrView + }() } if cs.Forwarder != nil { - fwrAddr := cs.Forwarder.Contract.Address().String() - var prevViews []ForwarderView - if prevView.Forwarders != nil { - pv, ok := prevView.Forwarders[fwrAddr] - if !ok { - prevViews = []ForwarderView{} + wg.Add(1) + go func() { + defer wg.Done() + fwrAddr := cs.Forwarder.Contract.Address().String() + var prevViews []ForwarderView + if prevView.Forwarders != nil { + pv, ok := prevView.Forwarders[fwrAddr] + if !ok { + prevViews = []ForwarderView{} + } else { + prevViews = pv + } } else { - prevViews = pv + prevViews = []ForwarderView{} } - } else { - prevViews = []ForwarderView{} - } - fwrView, fwrErr := GenerateForwarderView(ctx, cs.Forwarder, prevViews) - if fwrErr != nil { - // don't block view on single forwarder not being configured - if errors.Is(fwrErr, ErrForwarderNotConfigured) { - lggr.Warnf("forwarder not configured for address %s", cs.Forwarder.Contract.Address()) - } else { - allErrs = errors.Join(allErrs, fwrErr) - lggr.Errorf("failed to generate forwarder view: %v", fwrErr) + select { + case <-ctx.Done(): + errCh <- ctx.Err() + return + default: + fwrView, fwrErr := GenerateForwarderView(ctx, cs.Forwarder, prevViews) + if fwrErr != nil { + // don't block view on single forwarder not being configured + if errors.Is(fwrErr, ErrForwarderNotConfigured) { + lggr.Warnf("forwarder not configured for address %s", cs.Forwarder.Contract.Address()) + } else if errors.Is(fwrErr, context.Canceled) || errors.Is(fwrErr, context.DeadlineExceeded) { + lggr.Warnf("forwarder view generation cancelled for address %s", cs.Forwarder.Contract.Address()) + errCh <- fwrErr + } else { + lggr.Errorf("failed to generate forwarder view: %v", fwrErr) + errCh <- fwrErr + } + } + out.Forwarders[fwrAddr] = fwrView } - } - out.Forwarders[fwrAddr] = fwrView + }() + } + + wg.Wait() + close(errCh) + + var errList []error + // Collect all errors + for err := range errCh { + errList = append(errList, err) } + allErrs = errors.Join(errList...) return out, allErrs } From 6c91b2ba2141eb06576214a5cb84b4c62b4b425d Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Wed, 5 Mar 2025 15:18:42 -0400 Subject: [PATCH 06/13] Fixes tests --- deployment/ccip/changeset/view_test.go | 2 +- deployment/keystone/changeset/view_test.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deployment/ccip/changeset/view_test.go b/deployment/ccip/changeset/view_test.go index cb798835cd7..2a7e15905d4 100644 --- a/deployment/ccip/changeset/view_test.go +++ b/deployment/ccip/changeset/view_test.go @@ -12,6 +12,6 @@ import ( func TestSmokeView(t *testing.T) { t.Parallel() tenv, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(3)) - _, err := changeset.ViewCCIP(tenv.Env) + _, err := changeset.ViewCCIP(tenv.Env, nil) require.NoError(t, err) } diff --git a/deployment/keystone/changeset/view_test.go b/deployment/keystone/changeset/view_test.go index aa21ba4619b..ed9ca2b7b2a 100644 --- a/deployment/keystone/changeset/view_test.go +++ b/deployment/keystone/changeset/view_test.go @@ -79,7 +79,7 @@ func TestKeystoneView(t *testing.T) { _, err = changeset.ConfigureOCR3Contract(env.Env, cfg) require.NoError(t, err) - a, err := changeset.ViewKeystone(env.Env) + a, err := changeset.ViewKeystone(env.Env, nil) require.NoError(t, err) b, err := a.MarshalJSON() require.NoError(t, err) @@ -107,7 +107,7 @@ func TestKeystoneView(t *testing.T) { require.NotNil(t, resp) require.NoError(t, env.Env.ExistingAddresses.Merge(resp.AddressBook)) - _, err = changeset.ViewKeystone(env.Env) + _, err = changeset.ViewKeystone(env.Env, nil) require.ErrorContains(t, err, "failed to view chain") require.ErrorContains(t, err, "OCR3 not configured") }) @@ -128,7 +128,7 @@ func TestKeystoneView(t *testing.T) { } _, err = changeset.ConfigureOCR3Contract(env.Env, cfg) require.NoError(t, err) - _, err = changeset.ViewKeystone(env.Env) + _, err = changeset.ViewKeystone(env.Env, nil) require.ErrorContains(t, err, "failed to view chain") require.ErrorContains(t, err, "DeltaRound (0s) must be less than DeltaProgress (0s)") }) From a1e366d65664b8cd964a7f2386476cc057b9be46 Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Wed, 5 Mar 2025 15:31:40 -0400 Subject: [PATCH 07/13] Fixes lint --- deployment/keystone/changeset/state.go | 7 ++++--- deployment/keystone/changeset/view.go | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/deployment/keystone/changeset/state.go b/deployment/keystone/changeset/state.go index f21d2da409c..c776dffad68 100644 --- a/deployment/keystone/changeset/state.go +++ b/deployment/keystone/changeset/state.go @@ -170,12 +170,13 @@ func (cs ContractSet) View(ctx context.Context, prevView KeystoneChainView, lggr fwrView, fwrErr := GenerateForwarderView(ctx, cs.Forwarder, prevViews) if fwrErr != nil { // don't block view on single forwarder not being configured - if errors.Is(fwrErr, ErrForwarderNotConfigured) { + switch { + case errors.Is(fwrErr, ErrForwarderNotConfigured): lggr.Warnf("forwarder not configured for address %s", cs.Forwarder.Contract.Address()) - } else if errors.Is(fwrErr, context.Canceled) || errors.Is(fwrErr, context.DeadlineExceeded) { + case errors.Is(fwrErr, context.Canceled), errors.Is(fwrErr, context.DeadlineExceeded): lggr.Warnf("forwarder view generation cancelled for address %s", cs.Forwarder.Contract.Address()) errCh <- fwrErr - } else { + default: lggr.Errorf("failed to generate forwarder view: %v", fwrErr) errCh <- fwrErr } diff --git a/deployment/keystone/changeset/view.go b/deployment/keystone/changeset/view.go index 83d77fbee65..ae1743f1186 100644 --- a/deployment/keystone/changeset/view.go +++ b/deployment/keystone/changeset/view.go @@ -24,7 +24,7 @@ func ViewKeystone(e deployment.Environment, previousView []byte) (json.Marshaler return nil, fmt.Errorf("failed to get contract sets: %w", err) } var prevView KeystoneView - if previousView == nil || len(previousView) == 0 { + if len(previousView) == 0 { prevView.Chains = make(map[string]KeystoneChainView) } else if err = json.Unmarshal(previousView, &prevView); err != nil { lggr.Warnf("failed to unmarshal previous keystone view: %v", err) From 6e003e561dd949e726999dc71aeb0dfe5d3f9bb6 Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Wed, 5 Mar 2025 16:01:56 -0400 Subject: [PATCH 08/13] Fixes test --- deployment/keystone/changeset/state.go | 4 +- deployment/keystone/changeset/view_test.go | 48 ++++++++++++++++++---- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/deployment/keystone/changeset/state.go b/deployment/keystone/changeset/state.go index c776dffad68..15435db4173 100644 --- a/deployment/keystone/changeset/state.go +++ b/deployment/keystone/changeset/state.go @@ -124,6 +124,7 @@ func (cs ContractSet) View(ctx context.Context, prevView KeystoneChainView, lggr lggr.Errorf("failed to generate OCR3 config view: %v", err) errCh <- err } + continue } out.OCRContracts[addrCopy.String()] = ocrView } @@ -180,8 +181,9 @@ func (cs ContractSet) View(ctx context.Context, prevView KeystoneChainView, lggr lggr.Errorf("failed to generate forwarder view: %v", fwrErr) errCh <- fwrErr } + } else { + out.Forwarders[fwrAddr] = fwrView } - out.Forwarders[fwrAddr] = fwrView } }() } diff --git a/deployment/keystone/changeset/view_test.go b/deployment/keystone/changeset/view_test.go index ed9ca2b7b2a..9b9421ae3b0 100644 --- a/deployment/keystone/changeset/view_test.go +++ b/deployment/keystone/changeset/view_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" chain_selectors "github.com/smartcontractkit/chain-selectors" @@ -56,12 +57,20 @@ func TestKeystoneView(t *testing.T) { addrs, err := env.Env.ExistingAddresses.AddressesForChain(registryChain) require.NoError(t, err) - var newOCR3Addr string + var newOCR3Addr, newForwarderAddr string for addr, tv := range addrs { - if tv.Type == internal.OCR3Capability { - newOCR3Addr = addr + if newForwarderAddr != "" && newOCR3Addr != "" { break } + switch tv.Type { + case internal.KeystoneForwarder: + newForwarderAddr = addr + continue + case internal.OCR3Capability: + newOCR3Addr = addr + default: + continue + } } t.Run("successfully generates a view of the keystone state", func(t *testing.T) { @@ -97,19 +106,44 @@ func TestKeystoneView(t *testing.T) { require.True(t, ok) viewOCR3Config, ok := viewChain.OCRContracts[newOCR3Addr] require.True(t, ok) + require.Len(t, viewChain.OCRContracts, 1) require.Equal(t, oracleConfig, viewOCR3Config.OffchainConfig) + viewForwarders, ok := viewChain.Forwarders[newForwarderAddr] + require.True(t, ok) + require.Len(t, viewForwarders, 1) + require.Equal(t, uint32(1), viewForwarders[0].DonID) + require.Equal(t, uint8(1), viewForwarders[0].F) + require.Equal(t, uint32(1), viewForwarders[0].ConfigVersion) + require.Len(t, viewForwarders[0].Signers, 4) }) - t.Run("fails to generate a view of the keystone state with OCR3 not configured", func(t *testing.T) { + t.Run("generates a partial view of the keystone state with OCR3 not configured", func(t *testing.T) { // Deploy a new OCR3 contract resp, err := changeset.DeployOCR3(env.Env, registryChain) require.NoError(t, err) require.NotNil(t, resp) require.NoError(t, env.Env.ExistingAddresses.Merge(resp.AddressBook)) - _, err = changeset.ViewKeystone(env.Env, nil) - require.ErrorContains(t, err, "failed to view chain") - require.ErrorContains(t, err, "OCR3 not configured") + a, err := changeset.ViewKeystone(env.Env, nil) + require.NoError(t, err) + b, err := a.MarshalJSON() + require.NoError(t, err) + require.NotEmpty(t, b) + + var outView changeset.KeystoneView + require.NoError(t, json.Unmarshal(b, &outView)) + chainID, err := chain_selectors.ChainIdFromSelector(registryChain) + require.NoError(t, err) + chainName, err := chain_selectors.NameFromChainId(chainID) + require.NoError(t, err) + + view, ok := outView.Chains[chainName] + require.True(t, ok) + assert.NotNil(t, view.Forwarders) + assert.NotNil(t, view.OCRContracts) + require.Len(t, view.OCRContracts, 1) // There already are OCR views available at this point + assert.NotNil(t, view.WorkflowRegistry) + assert.NotNil(t, view.CapabilityRegistry) }) t.Run("fails to generate a view of the keystone state with a bad OracleConfig", func(t *testing.T) { From 2d14d6c48d33dcbe76b877b941b784cefe18cb29 Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Thu, 6 Mar 2025 13:23:58 -0400 Subject: [PATCH 09/13] Addresses PR review --- deployment/ccip/changeset/view.go | 2 +- deployment/changeset.go | 4 +++- deployment/data-feeds/changeset/view.go | 2 +- deployment/exemplar/changeset/view.go | 2 +- deployment/keystone/changeset/state.go | 4 +++- deployment/keystone/changeset/view.go | 14 ++++++++++---- deployment/keystone/changeset/view_contracts.go | 8 +++++++- 7 files changed, 26 insertions(+), 10 deletions(-) diff --git a/deployment/ccip/changeset/view.go b/deployment/ccip/changeset/view.go index e3f897b58be..9d33368c721 100644 --- a/deployment/ccip/changeset/view.go +++ b/deployment/ccip/changeset/view.go @@ -11,7 +11,7 @@ import ( var _ deployment.ViewState = ViewCCIP -func ViewCCIP(e deployment.Environment, _ []byte) (json.Marshaler, error) { +func ViewCCIP(e deployment.Environment) (json.Marshaler, error) { state, err := LoadOnchainState(e) if err != nil { return nil, err diff --git a/deployment/changeset.go b/deployment/changeset.go index 89592cb0b21..fd4b9221bf7 100644 --- a/deployment/changeset.go +++ b/deployment/changeset.go @@ -113,4 +113,6 @@ type ChangesetOutput struct { // ViewState produces a product specific JSON representation of // the on and offchain state of the environment. -type ViewState func(e Environment, previousState []byte) (json.Marshaler, error) +type ViewState func(e Environment) (json.Marshaler, error) + +type ViewStateV2 func(e Environment, previousView json.Marshaler) (json.Marshaler, error) diff --git a/deployment/data-feeds/changeset/view.go b/deployment/data-feeds/changeset/view.go index ca68499c900..15348e1f8e1 100644 --- a/deployment/data-feeds/changeset/view.go +++ b/deployment/data-feeds/changeset/view.go @@ -10,7 +10,7 @@ import ( var _ deployment.ViewState = ViewDataFeeds -func ViewDataFeeds(e deployment.Environment, _ []byte) (json.Marshaler, error) { +func ViewDataFeeds(e deployment.Environment) (json.Marshaler, error) { state, err := LoadOnchainState(e) fmt.Println(state) if err != nil { diff --git a/deployment/exemplar/changeset/view.go b/deployment/exemplar/changeset/view.go index aee2c8a679b..76784533ad3 100644 --- a/deployment/exemplar/changeset/view.go +++ b/deployment/exemplar/changeset/view.go @@ -20,7 +20,7 @@ func (v *ExemplarView) MarshalJSON() ([]byte, error) { } // ViewExemplar extracts basic information from the environment -var ViewExemplar deployment.ViewState = func(e deployment.Environment, _ []byte) (json.Marshaler, error) { +var ViewExemplar deployment.ViewState = func(e deployment.Environment) (json.Marshaler, error) { lggr := e.Logger lggr.Info("Generating exemplar state view") diff --git a/deployment/keystone/changeset/state.go b/deployment/keystone/changeset/state.go index 15435db4173..3da63bfe285 100644 --- a/deployment/keystone/changeset/state.go +++ b/deployment/keystone/changeset/state.go @@ -88,7 +88,9 @@ func (cs ContractSet) View(ctx context.Context, prevView KeystoneChainView, lggr var wg sync.WaitGroup errCh := make(chan error, 4) // We are generating 4 views concurrently - ctx, cancel := context.WithTimeout(ctx, 3*time.Minute) + // Not sure if we want the timeout here... As more blocks are added, the timeout will be reached for Forwarders... + // TODO: If we keep the timeout, we need to make it configurable via ENV or params. + ctx, cancel := context.WithTimeout(ctx, 6*time.Minute) defer cancel() if cs.CapabilitiesRegistry != nil { diff --git a/deployment/keystone/changeset/view.go b/deployment/keystone/changeset/view.go index ae1743f1186..c2723594b01 100644 --- a/deployment/keystone/changeset/view.go +++ b/deployment/keystone/changeset/view.go @@ -11,9 +11,9 @@ import ( commonview "github.com/smartcontractkit/chainlink/deployment/common/view" ) -var _ deployment.ViewState = ViewKeystone +var _ deployment.ViewStateV2 = ViewKeystone -func ViewKeystone(e deployment.Environment, previousView []byte) (json.Marshaler, error) { +func ViewKeystone(e deployment.Environment, previousView json.Marshaler) (json.Marshaler, error) { lggr := e.Logger state, err := GetContractSets(e.Logger, &GetContractSetsRequest{ Chains: e.Chains, @@ -23,10 +23,16 @@ func ViewKeystone(e deployment.Environment, previousView []byte) (json.Marshaler if err != nil { return nil, fmt.Errorf("failed to get contract sets: %w", err) } + + prevViewBytes, err := previousView.MarshalJSON() + if err != nil { + // just log the error, we don't need to stop the execution since the previous view is optional + lggr.Warnf("failed to marshal previous keystone view: %v", err) + } var prevView KeystoneView - if len(previousView) == 0 { + if len(prevViewBytes) == 0 { prevView.Chains = make(map[string]KeystoneChainView) - } else if err = json.Unmarshal(previousView, &prevView); err != nil { + } else if err = json.Unmarshal(prevViewBytes, &prevView); err != nil { lggr.Warnf("failed to unmarshal previous keystone view: %v", err) prevView.Chains = make(map[string]KeystoneChainView) } diff --git a/deployment/keystone/changeset/view_contracts.go b/deployment/keystone/changeset/view_contracts.go index 39cc515b43e..52a9297f375 100644 --- a/deployment/keystone/changeset/view_contracts.go +++ b/deployment/keystone/changeset/view_contracts.go @@ -211,7 +211,13 @@ func GenerateForwarderView(ctx context.Context, f *ForwarderContract, prevViews configSets = append(configSets, configIterator.Event) } if len(configSets) == 0 { - return nil, ErrForwarderNotConfigured + // Forwarder is not configured only if we don't have any previous configuration events. + if len(prevViews) == 0 { + return nil, ErrForwarderNotConfigured + } + + // If we don't have any new config sets, we return the previous views as is. + return prevViews, nil } // We now create a slice with all previous views and the new views, so they get all added to the final view. From f2a14dce67ba70f1e57da6c08e7a9d1b91466cb2 Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Thu, 6 Mar 2025 14:19:21 -0400 Subject: [PATCH 10/13] Fixes CI --- deployment/ccip/changeset/view_test.go | 2 +- deployment/keystone/changeset/view_test.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/deployment/ccip/changeset/view_test.go b/deployment/ccip/changeset/view_test.go index 2a7e15905d4..cb798835cd7 100644 --- a/deployment/ccip/changeset/view_test.go +++ b/deployment/ccip/changeset/view_test.go @@ -12,6 +12,6 @@ import ( func TestSmokeView(t *testing.T) { t.Parallel() tenv, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(3)) - _, err := changeset.ViewCCIP(tenv.Env, nil) + _, err := changeset.ViewCCIP(tenv.Env) require.NoError(t, err) } diff --git a/deployment/keystone/changeset/view_test.go b/deployment/keystone/changeset/view_test.go index 9b9421ae3b0..e987bb4b23b 100644 --- a/deployment/keystone/changeset/view_test.go +++ b/deployment/keystone/changeset/view_test.go @@ -88,7 +88,8 @@ func TestKeystoneView(t *testing.T) { _, err = changeset.ConfigureOCR3Contract(env.Env, cfg) require.NoError(t, err) - a, err := changeset.ViewKeystone(env.Env, nil) + var prevView json.RawMessage = []byte("{}") + a, err := changeset.ViewKeystone(env.Env, prevView) require.NoError(t, err) b, err := a.MarshalJSON() require.NoError(t, err) From 30076790e03da943fac9d43e7a857a0552e5174e Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Thu, 6 Mar 2025 14:32:16 -0400 Subject: [PATCH 11/13] Fixes CI --- deployment/keystone/changeset/view_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/deployment/keystone/changeset/view_test.go b/deployment/keystone/changeset/view_test.go index e987bb4b23b..ade145b45e4 100644 --- a/deployment/keystone/changeset/view_test.go +++ b/deployment/keystone/changeset/view_test.go @@ -125,7 +125,8 @@ func TestKeystoneView(t *testing.T) { require.NotNil(t, resp) require.NoError(t, env.Env.ExistingAddresses.Merge(resp.AddressBook)) - a, err := changeset.ViewKeystone(env.Env, nil) + var prevView json.RawMessage = []byte("{}") + a, err := changeset.ViewKeystone(env.Env, prevView) require.NoError(t, err) b, err := a.MarshalJSON() require.NoError(t, err) @@ -163,7 +164,8 @@ func TestKeystoneView(t *testing.T) { } _, err = changeset.ConfigureOCR3Contract(env.Env, cfg) require.NoError(t, err) - _, err = changeset.ViewKeystone(env.Env, nil) + var prevView json.RawMessage = []byte("{}") + _, err = changeset.ViewKeystone(env.Env, prevView) require.ErrorContains(t, err, "failed to view chain") require.ErrorContains(t, err, "DeltaRound (0s) must be less than DeltaProgress (0s)") }) From e19f59e063a5ac7cac55f289b21dbf14bc9100d0 Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Mon, 10 Mar 2025 11:55:21 -0400 Subject: [PATCH 12/13] Fixes CI --- .../tests/smoke/capabilities/workflow_test.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/system-tests/tests/smoke/capabilities/workflow_test.go b/system-tests/tests/smoke/capabilities/workflow_test.go index 0935c34a7b4..d21ab7184b2 100644 --- a/system-tests/tests/smoke/capabilities/workflow_test.go +++ b/system-tests/tests/smoke/capabilities/workflow_test.go @@ -1,6 +1,7 @@ package capabilities_test import ( + "context" "fmt" "math/big" "net" @@ -16,6 +17,7 @@ import ( "github.com/go-playground/validator/v10" "github.com/pkg/errors" "github.com/rs/zerolog" + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -167,13 +169,13 @@ func validateEnvVars(t *testing.T, in *TestConfig) { // disabled until we can figure out how to generate a gist read:write token in CI /* - This test can be run in two modes: - 1. `existing` mode: it uses a workflow binary (and configuration) file that is already uploaded to Gist - 2. `compile` mode: it compiles a new workflow binary and uploads it to Gist + This test can be run in two modes: + 1. `existing` mode: it uses a workflow binary (and configuration) file that is already uploaded to Gist + 2. `compile` mode: it compiles a new workflow binary and uploads it to Gist - For the `new` mode to work, the `GITHUB_API_TOKEN` env var must be set to a token that has `gist:read` and `gist:write` permissions, but this permissions - are tied to account not to repository. Currently, we have no service account in the CI at all. And using a token that's tied to personal account of a developer - is not a good idea. So, for now, we are only allowing the `existing` mode in CI. + For the `new` mode to work, the `GITHUB_API_TOKEN` env var must be set to a token that has `gist:read` and `gist:write` permissions, but this permissions + are tied to account not to repository. Currently, we have no service account in the CI at all. And using a token that's tied to personal account of a developer + is not a good idea. So, for now, we are only allowing the `existing` mode in CI. */ // we use this special function to subsitute a placeholder env variable with the actual environment variable name @@ -482,6 +484,9 @@ func setupTestEnvironment(t *testing.T, testLogger zerolog.Logger, in *TestConfi Logger: singeFileLogger, Chains: chains, ExistingAddresses: deployment.NewMemoryAddressBook(), + GetContext: func() context.Context { + return testcontext.Get(t) + }, } keystoneContractsInput := &keystonetypes.KeystoneContractsInput{ From 1b2bd8f8f4bf46138a54b04de628a0fdb94781e2 Mon Sep 17 00:00:00 2001 From: vyzaldysanchez Date: Mon, 10 Mar 2025 11:58:06 -0400 Subject: [PATCH 13/13] Fixes CI --- system-tests/tests/smoke/capabilities/workflow_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system-tests/tests/smoke/capabilities/workflow_test.go b/system-tests/tests/smoke/capabilities/workflow_test.go index d21ab7184b2..7c73545ad06 100644 --- a/system-tests/tests/smoke/capabilities/workflow_test.go +++ b/system-tests/tests/smoke/capabilities/workflow_test.go @@ -17,7 +17,6 @@ import ( "github.com/go-playground/validator/v10" "github.com/pkg/errors" "github.com/rs/zerolog" - "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -28,6 +27,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/framework/components/fake" "github.com/smartcontractkit/chainlink-testing-framework/framework/components/jd" ns "github.com/smartcontractkit/chainlink-testing-framework/framework/components/simple_node_set" + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink-testing-framework/seth" "github.com/smartcontractkit/chainlink/deployment"