From 340a6bfdf54745dd1c6d9f322d9c9515c97060bb Mon Sep 17 00:00:00 2001 From: cfal Date: Thu, 7 Nov 2024 12:14:10 +0800 Subject: [PATCH] core/services/chainlink/config.go: merge RawConfigs using expected fields (#14433) * core/services/chainlink/config.go: merge RawConfigs using expected fields * core/services/chainlink: update invalid config test * .changeset/strange-radios-teach.md: add changeset * go.mod: update * core/services/chainlink: distinguish between empty, invalid, missing ChainID and Node Name values * testdata/scripts/config/merge_raw_configs.txtar: add testscript for merging raw configs * core/services/chainlink/config.go: merge node configs by name * testdata/scripts/config/merge_raw_configs.txtar: test node matching * core/services/chainlink/config.go: create helper for parsing raw configs * core/services/chainlink/config.go: rewrite if/else to switch statements for lint * core/services/chainlink/config.go: dont check for empty Nodes key in parse, only in ValidateConfig * core/services/chainlink/config_test.go: update errors * core/services/chainlink/config.go: add validateKeys helper and call it instead * update chainlink-common --- .changeset/strange-radios-teach.md | 5 + core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- core/services/chainlink/config.go | 200 +++++++- core/services/chainlink/config_test.go | 6 +- .../chainlink/testdata/config-invalid.toml | 8 +- deployment/go.mod | 2 +- deployment/go.sum | 4 +- go.mod | 4 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 +- .../scripts/config/merge_raw_configs.txtar | 468 ++++++++++++++++++ 15 files changed, 683 insertions(+), 36 deletions(-) create mode 100644 .changeset/strange-radios-teach.md create mode 100644 testdata/scripts/config/merge_raw_configs.txtar diff --git a/.changeset/strange-radios-teach.md b/.changeset/strange-radios-teach.md new file mode 100644 index 00000000000..ea84bfbf359 --- /dev/null +++ b/.changeset/strange-radios-teach.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Merge raw configs correctly #bugfix diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 590ef9f1607..05520c060ba 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -24,7 +24,7 @@ require ( github.com/prometheus/client_golang v1.20.5 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae github.com/smartcontractkit/chainlink/deployment v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/chainlink/v2 v2.14.0-mercury-20240807.0.20241106193309-5560cd76211a github.com/smartcontractkit/libocr v0.0.0-20241007185508-adbe57025f12 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 0d158c973e0..3160b2c6c6c 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1092,8 +1092,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422 h1:VfH/AW5NtTmroY9zz6OYCPFbFTqpMyJ2ubgT9ahYf3U= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7 h1:AGi0kAtMRW1zl1h7sGw+3CKO4Nlev6iA08YfEcgJCGs= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7/go.mod h1:TQ9/KKXZ9vr8QAlUquqGpSvDCpR+DtABKPXZY4CiRns= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae h1:uqce0bjNVYzFrrVLafXgyn8SVNdfOtZekLfAwQihHiA= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae/go.mod h1:TQ9/KKXZ9vr8QAlUquqGpSvDCpR+DtABKPXZY4CiRns= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 476e758ccbb..9f083ef89af 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -3,7 +3,9 @@ package chainlink import ( "errors" "fmt" + "slices" + "github.com/imdario/mergo" "go.uber.org/multierr" gotoml "github.com/pelletier/go-toml/v2" @@ -49,40 +51,201 @@ type Config struct { // RawConfigs is a list of RawConfig. type RawConfigs []RawConfig +func (rs *RawConfigs) SetFrom(configs RawConfigs) error { + if err := configs.validateKeys(); err != nil { + return err + } + + for _, config := range configs { + chainID := config.ChainID() + i := slices.IndexFunc(*rs, func(r RawConfig) bool { + otherChainID := r.ChainID() + return otherChainID != "" && chainID == otherChainID + }) + if i != -1 { + if err := (*rs)[i].SetFrom(config); err != nil { + return err + } + } else { + *rs = append(*rs, config) + } + } + + return nil +} + +func (rs RawConfigs) validateKeys() (err error) { + chainIDs := commonconfig.UniqueStrings{} + for i, config := range rs { + chainID := config.ChainID() + if chainIDs.IsDupe(&chainID) { + err = errors.Join(err, commonconfig.NewErrDuplicate(fmt.Sprintf("%d.ChainID", i), chainID)) + } + } + + nodeNames := commonconfig.UniqueStrings{} + for i, config := range rs { + configNodeNames := config.NodeNames() + for j, nodeName := range configNodeNames { + if nodeNames.IsDupe(&nodeName) { + err = errors.Join(err, commonconfig.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.Name", i, j), nodeName)) + } + } + } + return +} + +func (rs RawConfigs) ValidateConfig() (err error) { + return rs.validateKeys() +} + // RawConfig is the config used for chains that are not embedded. type RawConfig map[string]any -// ValidateConfig returns an error if the Config is not valid for use, as-is. -func (c *RawConfig) ValidateConfig() (err error) { - if v, ok := (*c)["Enabled"]; ok { +type parsedRawConfig struct { + chainID string + nodesExist bool + nodes []map[string]any + nodeNames []string +} + +func (c RawConfig) parse() (*parsedRawConfig, error) { + var err error + if v, ok := c["Enabled"]; ok { if _, ok := v.(bool); !ok { err = multierr.Append(err, commonconfig.ErrInvalid{Name: "Enabled", Value: v, Msg: "expected bool"}) } } - if v, ok := (*c)["ChainID"]; ok { - if _, ok := v.(string); !ok { - err = multierr.Append(err, commonconfig.ErrInvalid{Name: "ChainID", Value: v, Msg: "expected string"}) + + parsedRawConfig := &parsedRawConfig{} + chainID, exists := c["ChainID"] + if !exists { + err = multierr.Append(err, commonconfig.ErrMissing{Name: "ChainID", Msg: "required for all chains"}) + } else { + chainIDStr, ok := chainID.(string) + switch { + case !ok: + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "ChainID", Value: chainID, Msg: "expected string"}) + case chainIDStr == "": + err = multierr.Append(err, commonconfig.ErrEmpty{Name: "ChainID", Msg: "required for all chains"}) + default: + parsedRawConfig.chainID = chainIDStr } } - return err + nodes, nodesExist := c["Nodes"] + parsedRawConfig.nodesExist = nodesExist + if nodesExist { + nodeMaps, ok := nodes.([]any) + switch { + case !ok: + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "Nodes", Value: nodes, Msg: "expected array of node configs"}) + default: + for i, node := range nodeMaps { + nodeConfig, ok := node.(map[string]any) + if !ok { + err = multierr.Append(err, commonconfig.ErrInvalid{Name: fmt.Sprintf("Nodes.%d", i), Value: nodeConfig, Msg: "expected node config map"}) + } else { + parsedRawConfig.nodes = append(parsedRawConfig.nodes, nodeConfig) + nodeName, exists := nodeConfig["Name"] + if !exists { + err = multierr.Append(err, commonconfig.ErrMissing{Name: fmt.Sprintf("Nodes.%d.Name", i), Msg: "required for all nodes"}) + } else { + nodeNameStr, ok := nodeName.(string) + switch { + case !ok: + err = multierr.Append(err, commonconfig.ErrInvalid{Name: fmt.Sprintf("Nodes.%d.Name", i), Value: nodeName, Msg: "expected string"}) + case nodeNameStr == "": + err = multierr.Append(err, commonconfig.ErrEmpty{Name: fmt.Sprintf("Nodes.%d.Name", i), Msg: "required for all nodes"}) + default: + parsedRawConfig.nodeNames = append(parsedRawConfig.nodeNames, nodeNameStr) + } + } + } + } + } + } + + return parsedRawConfig, err } -func (c *RawConfig) IsEnabled() bool { - if c == nil { - return false +// ValidateConfig returns an error if the Config is not valid for use, as-is. +func (c RawConfig) ValidateConfig() error { + parsedRawConfig, err := c.parse() + if !parsedRawConfig.nodesExist { + err = multierr.Append(err, commonconfig.ErrMissing{Name: "Nodes", Msg: "expected at least one node"}) + } else if len(parsedRawConfig.nodes) == 0 { + err = multierr.Append(err, commonconfig.ErrEmpty{Name: "Nodes", Msg: "expected at least one node"}) } + return err +} - enabled, ok := (*c)["Enabled"].(bool) +func (c RawConfig) IsEnabled() bool { + enabled, ok := c["Enabled"].(bool) return ok && enabled } -func (c *RawConfig) ChainID() string { - if c == nil { - return "" +func (c RawConfig) ChainID() string { + chainID, _ := c["ChainID"].(string) + return chainID +} + +func (c *RawConfig) SetFrom(config RawConfig) error { + parsedRawConfig, err := c.parse() + if err != nil { + return err } - chainID, _ := (*c)["ChainID"].(string) - return chainID + incomingParsedRawConfig, err := config.parse() + if err != nil { + return err + } + + // Create a copy of config without nodes to merge other fields + configWithoutNodes := make(RawConfig) + for k, v := range config { + if k != "Nodes" { + configWithoutNodes[k] = v + } + } + + // Merge all non-node fields + if err := mergo.Merge(c, configWithoutNodes, mergo.WithOverride); err != nil { + return err + } + + // Handle node merging + for i, nodeConfig := range incomingParsedRawConfig.nodes { + nodeName := incomingParsedRawConfig.nodeNames[i] + i := slices.Index(parsedRawConfig.nodeNames, nodeName) + if i != -1 { + if err := mergo.Merge(&parsedRawConfig.nodes[i], nodeConfig, mergo.WithOverride); err != nil { + return err + } + } else { + parsedRawConfig.nodes = append(parsedRawConfig.nodes, nodeConfig) + } + } + + // Subsequence SetFrom invocations will call parse(), and expect to be able to cast c["Nodes"] to []any, + // so we can't directly assign parsedRawConfig.nodes back to c["Nodes"]. + anyConfigs := []any{} + for _, nodeConfig := range parsedRawConfig.nodes { + anyConfigs = append(anyConfigs, nodeConfig) + } + + (*c)["Nodes"] = anyConfigs + return nil +} + +func (c RawConfig) NodeNames() []string { + nodes, _ := c["Nodes"].([]any) + nodeNames := []string{} + for _, node := range nodes { + config, _ := node.(map[string]any) + nodeName, _ := config["Name"].(string) + nodeNames = append(nodeNames, nodeName) + } + return nodeNames } // TOMLString returns a TOML encoded string. @@ -185,8 +348,9 @@ func (c *Config) SetFrom(f *Config) (err error) { err = multierr.Append(err, commonconfig.NamedMultiErrorList(err4, "Starknet")) } - // the plugin should handle it's own defaults and merging - c.Aptos = f.Aptos + if err5 := c.Aptos.SetFrom(f.Aptos); err5 != nil { + err = multierr.Append(err, commonconfig.NamedMultiErrorList(err5, "Aptos")) + } _, err = commonconfig.MultiErrorList(err) diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index c6dd58369d0..19ad7529c83 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -1520,7 +1520,11 @@ func TestConfig_Validate(t *testing.T) { - 1: 2 errors: - ChainID: missing: required for all chains - Nodes: missing: must have at least one node - - Aptos.0.Enabled: invalid value (1): expected bool`}, + - Aptos: 2 errors: + - 0.Nodes.1.Name: invalid value (primary): duplicate - must be unique + - 0: 2 errors: + - Enabled: invalid value (1): expected bool + - ChainID: missing: required for all chains`}, } { t.Run(tt.name, func(t *testing.T) { var c Config diff --git a/core/services/chainlink/testdata/config-invalid.toml b/core/services/chainlink/testdata/config-invalid.toml index 411741b1b5b..967ef76de8e 100644 --- a/core/services/chainlink/testdata/config-invalid.toml +++ b/core/services/chainlink/testdata/config-invalid.toml @@ -181,9 +181,15 @@ APIKey = 'key' [[Aptos]] Enabled = 1 +[[Aptos.Nodes]] +Name = 'primary' + +[[Aptos.Nodes]] +Name = 'primary' + [OCR2] Enabled = true [P2P] [P2P.V2] -Enabled = false \ No newline at end of file +Enabled = false diff --git a/deployment/go.mod b/deployment/go.mod index 8a4b7e428dd..26342d19ca2 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -21,7 +21,7 @@ require ( github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86 github.com/smartcontractkit/chain-selectors v1.0.27 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 github.com/smartcontractkit/chainlink/v2 v2.14.0-mercury-20240807.0.20241106193309-5560cd76211a diff --git a/deployment/go.sum b/deployment/go.sum index b937815703e..31f0f69e8e4 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1384,8 +1384,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422 h1:VfH/AW5NtTmroY9zz6OYCPFbFTqpMyJ2ubgT9ahYf3U= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7 h1:AGi0kAtMRW1zl1h7sGw+3CKO4Nlev6iA08YfEcgJCGs= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7/go.mod h1:TQ9/KKXZ9vr8QAlUquqGpSvDCpR+DtABKPXZY4CiRns= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae h1:uqce0bjNVYzFrrVLafXgyn8SVNdfOtZekLfAwQihHiA= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae/go.mod h1:TQ9/KKXZ9vr8QAlUquqGpSvDCpR+DtABKPXZY4CiRns= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= diff --git a/go.mod b/go.mod index b7a89eddf8d..e31d27ab3d2 100644 --- a/go.mod +++ b/go.mod @@ -44,6 +44,7 @@ require ( github.com/hashicorp/go-plugin v1.6.2-0.20240829161738-06afb6d7ae99 github.com/hashicorp/go-retryablehttp v0.7.7 github.com/hdevalence/ed25519consensus v0.1.0 + github.com/imdario/mergo v0.3.16 github.com/jackc/pgconn v1.14.3 github.com/jackc/pgtype v1.14.0 github.com/jackc/pgx/v4 v4.18.3 @@ -76,7 +77,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.27 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e github.com/smartcontractkit/chainlink-feeds v0.1.1 @@ -252,7 +253,6 @@ require ( github.com/huandu/xstrings v1.4.0 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect - github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/invopop/jsonschema v0.12.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect diff --git a/go.sum b/go.sum index e2d7559562b..e0adc852492 100644 --- a/go.sum +++ b/go.sum @@ -1077,8 +1077,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422 h1:VfH/AW5NtTmroY9zz6OYCPFbFTqpMyJ2ubgT9ahYf3U= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7 h1:AGi0kAtMRW1zl1h7sGw+3CKO4Nlev6iA08YfEcgJCGs= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7/go.mod h1:TQ9/KKXZ9vr8QAlUquqGpSvDCpR+DtABKPXZY4CiRns= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae h1:uqce0bjNVYzFrrVLafXgyn8SVNdfOtZekLfAwQihHiA= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae/go.mod h1:TQ9/KKXZ9vr8QAlUquqGpSvDCpR+DtABKPXZY4CiRns= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 3a1a5edb3da..f86b2ee70fa 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -36,7 +36,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.27 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 736bcd8bfc2..144d29156e5 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1405,8 +1405,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422 h1:VfH/AW5NtTmroY9zz6OYCPFbFTqpMyJ2ubgT9ahYf3U= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7 h1:AGi0kAtMRW1zl1h7sGw+3CKO4Nlev6iA08YfEcgJCGs= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7/go.mod h1:TQ9/KKXZ9vr8QAlUquqGpSvDCpR+DtABKPXZY4CiRns= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae h1:uqce0bjNVYzFrrVLafXgyn8SVNdfOtZekLfAwQihHiA= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae/go.mod h1:TQ9/KKXZ9vr8QAlUquqGpSvDCpR+DtABKPXZY4CiRns= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index db41a4d763a..e1c2c4f50a0 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -17,7 +17,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 github.com/slack-go/slack v0.15.0 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.5 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.2 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 8f18bccf4e1..9ad23c4de4c 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1394,8 +1394,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422 h1:VfH/AW5NtTmroY9zz6OYCPFbFTqpMyJ2ubgT9ahYf3U= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7 h1:AGi0kAtMRW1zl1h7sGw+3CKO4Nlev6iA08YfEcgJCGs= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241101093830-33711d0c3de7/go.mod h1:TQ9/KKXZ9vr8QAlUquqGpSvDCpR+DtABKPXZY4CiRns= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae h1:uqce0bjNVYzFrrVLafXgyn8SVNdfOtZekLfAwQihHiA= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241106142051-c7bded1c08ae/go.mod h1:TQ9/KKXZ9vr8QAlUquqGpSvDCpR+DtABKPXZY4CiRns= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= diff --git a/testdata/scripts/config/merge_raw_configs.txtar b/testdata/scripts/config/merge_raw_configs.txtar new file mode 100644 index 00000000000..dbdc1657e0f --- /dev/null +++ b/testdata/scripts/config/merge_raw_configs.txtar @@ -0,0 +1,468 @@ +exec chainlink node -c config1.toml -c config2.toml -s secrets.toml validate +cmp stdout out.txt +! exists $WORK/logs + +-- config1.toml -- +[Log] +Level = 'debug' + +[Feature] +FeedsManager = true +LogPoller = true +UICSAKeys = true + +[OCR2] +Enabled = true + +[P2P] +[P2P.V2] +Enabled = true +DeltaDial = '5s' +DeltaReconcile = '5s' +ListenAddresses = ['0.0.0.0:6691'] + +[WebServer] +HTTPPort = 6688 +TLS.HTTPSPort = 0 +AllowOrigins = '*' + +[[Aptos]] +ChainID = '1' +Enabled = true + +[Aptos.Workflow] +ForwarderAddress = "address" +PublicKey = "" + +[[Aptos.Nodes]] +Name = 'a' +URL = 'https://example.com/a' + +[[Aptos.Nodes]] +Name = 'b' +URL = 'https://example.com/b' + +-- config2.toml -- +Log.Level = 'debug' + +[[Aptos]] +ChainID = '1' + +[Aptos.Workflow] +ForwarderAddress = "replacement-address" +PublicKey = "" + +[[Aptos.Nodes]] +Name = 'b' +URL = 'https://example.com/b/updated' + +[[Aptos.Nodes]] +Name = 'c' +URL = 'https://example.com/c' + +[[Aptos]] +ChainID = '2' + +[Aptos.Workflow] +ForwarderAddress = "chain-two" +Publickey = "abcdef" + +[[Aptos.Nodes]] +Name = 'd' +URL = 'https://example.com/d' + +-- secrets.toml -- +[Database] +URL = 'postgresql://user:pass1234567890abcd@localhost:5432/dbname?sslmode=disable' + +[Password] +Keystore = 'keystore_pass' + +-- out.txt -- +# Secrets: +[Database] +URL = 'xxxxx' +AllowSimplePasswords = false + +[Password] +Keystore = 'xxxxx' + +# Input Configuration: +[Feature] +FeedsManager = true +LogPoller = true +UICSAKeys = true + +[Log] +Level = 'debug' + +[WebServer] +AllowOrigins = '*' +HTTPPort = 6688 + +[WebServer.TLS] +HTTPSPort = 0 + +[OCR2] +Enabled = true + +[P2P] +[P2P.V2] +Enabled = true +DeltaDial = '5s' +DeltaReconcile = '5s' +ListenAddresses = ['0.0.0.0:6691'] + +[[Aptos]] +ChainID = '1' +Enabled = true + +[[Aptos.Nodes]] +Name = 'a' +URL = 'https://example.com/a' + +[[Aptos.Nodes]] +Name = 'b' +URL = 'https://example.com/b/updated' + +[[Aptos.Nodes]] +Name = 'c' +URL = 'https://example.com/c' + +[Aptos.Workflow] +ForwarderAddress = 'replacement-address' +PublicKey = '' + +[[Aptos]] +ChainID = '2' + +[[Aptos.Nodes]] +Name = 'd' +URL = 'https://example.com/d' + +[Aptos.Workflow] +ForwarderAddress = 'chain-two' +Publickey = 'abcdef' + +# Effective Configuration, with defaults applied: +InsecureFastScrypt = false +RootDir = '~/.chainlink' +ShutdownGracePeriod = '5s' + +[Feature] +FeedsManager = true +LogPoller = true +UICSAKeys = true +CCIP = true +MultiFeedsManagers = false + +[Database] +DefaultIdleInTxSessionTimeout = '1h0m0s' +DefaultLockTimeout = '15s' +DefaultQueryTimeout = '10s' +LogQueries = false +MaxIdleConns = 10 +MaxOpenConns = 100 +MigrateOnStartup = true + +[Database.Backup] +Dir = '' +Frequency = '1h0m0s' +Mode = 'none' +OnVersionUpgrade = true + +[Database.Listener] +MaxReconnectDuration = '10m0s' +MinReconnectInterval = '1m0s' +FallbackPollInterval = '30s' + +[Database.Lock] +Enabled = true +LeaseDuration = '10s' +LeaseRefreshInterval = '1s' + +[TelemetryIngress] +UniConn = false +Logging = false +BufferSize = 100 +MaxBatchSize = 50 +SendInterval = '500ms' +SendTimeout = '10s' +UseBatchSend = true + +[AuditLogger] +Enabled = false +ForwardToUrl = '' +JsonWrapperKey = '' +Headers = [] + +[Log] +Level = 'debug' +JSONConsole = false +UnixTS = false + +[Log.File] +Dir = '' +MaxSize = '5.12gb' +MaxAgeDays = 0 +MaxBackups = 1 + +[WebServer] +AuthenticationMethod = 'local' +AllowOrigins = '*' +BridgeResponseURL = '' +BridgeCacheTTL = '0s' +HTTPWriteTimeout = '10s' +HTTPPort = 6688 +SecureCookies = true +SessionTimeout = '15m0s' +SessionReaperExpiration = '240h0m0s' +HTTPMaxSize = '32.77kb' +StartTimeout = '15s' +ListenIP = '0.0.0.0' + +[WebServer.LDAP] +ServerTLS = true +SessionTimeout = '15m0s' +QueryTimeout = '2m0s' +BaseUserAttr = 'uid' +BaseDN = '' +UsersDN = 'ou=users' +GroupsDN = 'ou=groups' +ActiveAttribute = '' +ActiveAttributeAllowedValue = '' +AdminUserGroupCN = 'NodeAdmins' +EditUserGroupCN = 'NodeEditors' +RunUserGroupCN = 'NodeRunners' +ReadUserGroupCN = 'NodeReadOnly' +UserApiTokenEnabled = false +UserAPITokenDuration = '240h0m0s' +UpstreamSyncInterval = '0s' +UpstreamSyncRateLimit = '2m0s' + +[WebServer.MFA] +RPID = '' +RPOrigin = '' + +[WebServer.RateLimit] +Authenticated = 1000 +AuthenticatedPeriod = '1m0s' +Unauthenticated = 5 +UnauthenticatedPeriod = '20s' + +[WebServer.TLS] +CertPath = '' +ForceRedirect = false +Host = '' +HTTPSPort = 0 +KeyPath = '' +ListenIP = '0.0.0.0' + +[JobPipeline] +ExternalInitiatorsEnabled = false +MaxRunDuration = '10m0s' +MaxSuccessfulRuns = 10000 +ReaperInterval = '1h0m0s' +ReaperThreshold = '24h0m0s' +ResultWriteQueueDepth = 100 +VerboseLogging = true + +[JobPipeline.HTTPRequest] +DefaultTimeout = '15s' +MaxSize = '32.77kb' + +[FluxMonitor] +DefaultTransactionQueueDepth = 1 +SimulateTransactions = false + +[OCR2] +Enabled = true +ContractConfirmations = 3 +BlockchainTimeout = '20s' +ContractPollInterval = '1m0s' +ContractSubscribeInterval = '2m0s' +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' +CaptureEATelemetry = false +CaptureAutomationCustomTelemetry = true +DefaultTransactionQueueDepth = 1 +SimulateTransactions = false +TraceLogging = false + +[OCR] +Enabled = false +ObservationTimeout = '5s' +BlockchainTimeout = '20s' +ContractPollInterval = '1m0s' +ContractSubscribeInterval = '2m0s' +DefaultTransactionQueueDepth = 1 +KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' +SimulateTransactions = false +TransmitterAddress = '' +CaptureEATelemetry = false +TraceLogging = false + +[P2P] +IncomingMessageBufferSize = 10 +OutgoingMessageBufferSize = 10 +PeerID = '' +TraceLogging = false + +[P2P.V2] +Enabled = true +AnnounceAddresses = [] +DefaultBootstrappers = [] +DeltaDial = '5s' +DeltaReconcile = '5s' +ListenAddresses = ['0.0.0.0:6691'] + +[Keeper] +DefaultTransactionQueueDepth = 1 +GasPriceBufferPercent = 20 +GasTipCapBufferPercent = 20 +BaseFeeBufferPercent = 20 +MaxGracePeriod = 100 +TurnLookBack = 1000 + +[Keeper.Registry] +CheckGasOverhead = 200000 +PerformGasOverhead = 300000 +MaxPerformDataSize = 5000 +SyncInterval = '30m0s' +SyncUpkeepQueueSize = 10 + +[AutoPprof] +Enabled = false +ProfileRoot = '' +PollInterval = '10s' +GatherDuration = '10s' +GatherTraceDuration = '5s' +MaxProfileSize = '100.00mb' +CPUProfileRate = 1 +MemProfileRate = 1 +BlockProfileRate = 1 +MutexProfileFraction = 1 +MemThreshold = '4.00gb' +GoroutineThreshold = 5000 + +[Pyroscope] +ServerAddress = '' +Environment = 'mainnet' + +[Sentry] +Debug = false +DSN = '' +Environment = '' +Release = '' + +[Insecure] +DevWebServer = false +OCRDevelopmentMode = false +InfiniteDepthQueries = false +DisableRateLimiting = false + +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 +Mode = 'tls' +TLSCertPath = '' + +[Mercury] +VerboseLogging = false + +[Mercury.Cache] +LatestReportTTL = '1s' +MaxStaleAge = '1h0m0s' +LatestReportDeadline = '5s' + +[Mercury.TLS] +CertFile = '' + +[Mercury.Transmitter] +TransmitQueueMaxSize = 10000 +TransmitTimeout = '5s' + +[Capabilities] +[Capabilities.Peering] +IncomingMessageBufferSize = 10 +OutgoingMessageBufferSize = 10 +PeerID = '' +TraceLogging = false + +[Capabilities.Peering.V2] +Enabled = false +AnnounceAddresses = [] +DefaultBootstrappers = [] +DeltaDial = '15s' +DeltaReconcile = '1m0s' +ListenAddresses = [] + +[Capabilities.Dispatcher] +SupportedVersion = 1 +ReceiverBufferSize = 10000 + +[Capabilities.Dispatcher.RateLimit] +GlobalRPS = 800.0 +GlobalBurst = 1000 +PerSenderRPS = 10.0 +PerSenderBurst = 50 + +[Capabilities.ExternalRegistry] +Address = '' +NetworkID = 'evm' +ChainID = '1' + +[Capabilities.GatewayConnector] +ChainIDForNodeKey = '' +NodeAddress = '' +DonID = '' +WSHandshakeTimeoutMillis = 0 +AuthMinChallengeLen = 0 +AuthTimestampToleranceSec = 0 + +[[Capabilities.GatewayConnector.Gateways]] +ID = '' +URL = '' + +[Telemetry] +Enabled = false +CACertFile = '' +Endpoint = '' +InsecureConnection = false +TraceSampleRatio = 0.01 + +[[Aptos]] +ChainID = '1' +Enabled = true + +[[Aptos.Nodes]] +Name = 'a' +URL = 'https://example.com/a' + +[[Aptos.Nodes]] +Name = 'b' +URL = 'https://example.com/b/updated' + +[[Aptos.Nodes]] +Name = 'c' +URL = 'https://example.com/c' + +[Aptos.Workflow] +ForwarderAddress = 'replacement-address' +PublicKey = '' + +[[Aptos]] +ChainID = '2' + +[[Aptos.Nodes]] +Name = 'd' +URL = 'https://example.com/d' + +[Aptos.Workflow] +ForwarderAddress = 'chain-two' +Publickey = 'abcdef' + +Valid configuration.