Skip to content

Commit

Permalink
support default config file overrides (#14090)
Browse files Browse the repository at this point in the history
* support default config file overrides

* lint

* adding test for when default is not used

* WIP: negative test for when an override is specified for a chain that does not exist in the embedded defaults

* using env package

* relaxing strict override restriction, and improving log line details

* lint + CustomDefaultsEnvKey --> CustomDefaults

* removing invalid test

* crash the node if can't read or load all files from overriden defaults

* accounting for Fatalf in control flow

* evm defaults look for evm suffix. Duplicate chain IDs fail validation

* removing negative path testing due to CI failures

* removing mkdirs

* updating config after rebase

* re-enabling negative path

* removing comment
  • Loading branch information
patrickhuie19 authored Aug 30, 2024
1 parent 7e82972 commit 5bda8af
Show file tree
Hide file tree
Showing 4 changed files with 523 additions and 5 deletions.
79 changes: 74 additions & 5 deletions core/chains/evm/config/toml/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package toml
import (
"bytes"
"embed"
"fmt"
"io"
"log"
"os"
"path/filepath"
"slices"
"strings"
Expand All @@ -12,37 +15,43 @@ import (

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/chaintype"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big"
"github.com/smartcontractkit/chainlink/v2/core/config/env"
)

var (

//go:embed defaults/*.toml
defaultsFS embed.FS
fallback Chain
defaults = map[string]Chain{}
defaultNames = map[string]string{}

customDefaults = map[string]Chain{}

// DefaultIDs is the set of chain ids which have defaults.
DefaultIDs []*big.Big
)

func init() {
// read the defaults first

fes, err := defaultsFS.ReadDir("defaults")
if err != nil {
log.Fatalf("failed to read defaults/: %v", err)
}
for _, fe := range fes {
path := filepath.Join("defaults", fe.Name())
b, err := defaultsFS.ReadFile(path)
if err != nil {
log.Fatalf("failed to read %q: %v", path, err)
b, err2 := defaultsFS.ReadFile(path)
if err2 != nil {
log.Fatalf("failed to read %q: %v", path, err2)
}
var config = struct {
ChainID *big.Big
Chain
}{}

if err := cconfig.DecodeTOML(bytes.NewReader(b), &config); err != nil {
log.Fatalf("failed to decode %q: %v", path, err)
if err3 := cconfig.DecodeTOML(bytes.NewReader(b), &config); err3 != nil {
log.Fatalf("failed to decode %q: %v", path, err3)
}
if fe.Name() == "fallback.toml" {
if config.ChainID != nil {
Expand All @@ -65,6 +74,63 @@ func init() {
slices.SortFunc(DefaultIDs, func(a, b *big.Big) int {
return a.Cmp(b)
})

// read the custom defaults overrides
dir := env.CustomDefaults.Get()
if dir == "" {
// short-circuit; no default overrides provided
return
}

// use evm overrides specifically
evmDir := fmt.Sprintf("%s/evm", dir)

// Read directory contents for evm only
entries, err := os.ReadDir(evmDir)
if err != nil {
log.Fatalf("error reading evm custom defaults override directory: %v", err)
return
}

for _, entry := range entries {
if entry.IsDir() {
// Skip directories
continue
}

path := evmDir + "/" + entry.Name()
file, err := os.Open(path)
if err != nil {
log.Fatalf("error opening file (name: %v) in custom defaults override directory: %v", entry.Name(), err)
}

// Read file contents
b, err := io.ReadAll(file)
file.Close()
if err != nil {
log.Fatalf("error reading file (name: %v) contents in custom defaults override directory: %v", entry.Name(), err)
}

var config = struct {
ChainID *big.Big
Chain
}{}

if err := cconfig.DecodeTOML(bytes.NewReader(b), &config); err != nil {
log.Fatalf("failed to decode %q in custom defaults override directory: %v", path, err)
}

if config.ChainID == nil {
log.Fatalf("missing ChainID in: %s in custom defaults override directory. exiting", path)
}

id := config.ChainID.String()

if _, ok := customDefaults[id]; ok {
log.Fatalf("%q contains duplicate ChainID: %s", path, id)
}
customDefaults[id] = config.Chain
}
}

// DefaultsNamed returns the default Chain values, optionally for the given chainID, as well as a name if the chainID is known.
Expand All @@ -78,6 +144,9 @@ func DefaultsNamed(chainID *big.Big) (c Chain, name string) {
c.SetFrom(&d)
name = defaultNames[s]
}
if overrides, ok := customDefaults[s]; ok {
c.SetFrom(&overrides)
}
return
}

Expand Down
1 change: 1 addition & 0 deletions core/config/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var (
ThresholdKeyShare = Secret("CL_THRESHOLD_KEY_SHARE")
// Migrations env vars
EVMChainIDNotNullMigration0195 = "CL_EVM_CHAINID_NOT_NULL_MIGRATION_0195"
CustomDefaults = Var("CL_CHAIN_DEFAULTS")
)

// LOOPP commands and vars
Expand Down
4 changes: 4 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ func TestMain(m *testing.M) {
}))
}

// TestScripts walks through the testdata/scripts directory and runs all tests that end in
// .txt or .txtar with the testscripts library. To run an individual test, specify it in the
// -run param of go test without the txtar or txt suffix, like so:
// go test . -run TestScripts/node/validate/default
func TestScripts(t *testing.T) {
if testing.Short() {
t.Skip("skipping testscript")
Expand Down
Loading

0 comments on commit 5bda8af

Please sign in to comment.