Skip to content

Commit ad05839

Browse files
authored
Merge branch 'main' into simon/e2e/block-timestamp
2 parents 44a7392 + 2b8dd94 commit ad05839

File tree

17 files changed

+945
-304
lines changed

17 files changed

+945
-304
lines changed

build/devenv/cmd/ccv/ccv.go

Lines changed: 246 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ package main
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"os"
78
"os/exec"
9+
"path/filepath"
810
"strconv"
911
"strings"
1012
"syscall"
@@ -20,6 +22,9 @@ import (
2022

2123
"github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm/deployment/v1_7_0/operations/committee_verifier"
2224
"github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm/deployment/v1_7_0/operations/mock_receiver"
25+
offrampoperations "github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm/deployment/v1_7_0/operations/offramp"
26+
onrampoperations "github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm/deployment/v1_7_0/operations/onramp"
27+
"github.com/smartcontractkit/chainlink-ccip/chains/evm/deployment/v1_6_0/operations/rmn_remote"
2328
"github.com/smartcontractkit/chainlink-ccv/devenv/cciptestinterfaces"
2429
"github.com/smartcontractkit/chainlink-ccv/devenv/services"
2530
"github.com/smartcontractkit/chainlink-ccv/protocol"
@@ -442,6 +447,223 @@ var printAddressesCmd = &cobra.Command{
442447
},
443448
}
444449

450+
var generateConfigsCmd = &cobra.Command{
451+
Use: "generate-configs",
452+
Short: "Generate the verifier and executor jobspecs (CL deployment only), and the aggregator and indexer TOML configuration files for the environment",
453+
RunE: func(cmd *cobra.Command, args []string) error {
454+
// TODO: maybe move the actual generation logic into a function
455+
// so that it can potentially be re-used (maybe from CLD?)
456+
addressRefsPath, err := cmd.Flags().GetString("address-refs-json")
457+
if err != nil {
458+
return err
459+
}
460+
verifierPubKeys, err := cmd.Flags().GetStringSlice("verifier-pubkeys")
461+
if err != nil {
462+
return err
463+
}
464+
aggregatorAddr, err := cmd.Flags().GetString("aggregator-addr")
465+
if err != nil {
466+
return err
467+
}
468+
aggregatorPort, err := cmd.Flags().GetInt("aggregator-port")
469+
if err != nil {
470+
return err
471+
}
472+
numExecutors, err := cmd.Flags().GetInt("num-executors")
473+
if err != nil {
474+
return err
475+
}
476+
if numExecutors == -1 {
477+
numExecutors = len(verifierPubKeys)
478+
}
479+
if numExecutors > len(verifierPubKeys) {
480+
return fmt.Errorf("number of executors cannot be greater than number of verifiers")
481+
}
482+
indexerAddress, err := cmd.Flags().GetString("indexer-addr")
483+
if err != nil {
484+
return err
485+
}
486+
monitoringOtelExporterHTTPEndpoint, err := cmd.Flags().GetString("monitoring-otel-exporter-http-endpoint")
487+
if err != nil {
488+
return err
489+
}
490+
491+
ocrThreshold := func(n int) uint8 {
492+
f := (n - 1) / 3 // n = 3f + 1 => f = (n - 1) / 3
493+
return uint8(f + 1) // OCR threshold is f + 1
494+
}
495+
496+
ccv.Plog.Info().
497+
Str("address-refs-json", addressRefsPath).
498+
Strs("verifier-pubkeys", verifierPubKeys).
499+
Str("aggregator-addr", aggregatorAddr).
500+
Int("aggregator-port", aggregatorPort).
501+
Int("num-executors", numExecutors).
502+
Msg("Generating configs")
503+
504+
// Load the address refs from the JSON file
505+
f, err := os.Open(addressRefsPath)
506+
if err != nil {
507+
return fmt.Errorf("failed to open address refs JSON file: %w", err)
508+
}
509+
defer f.Close()
510+
511+
decoder := json.NewDecoder(f)
512+
var addressRefs []datastore.AddressRef
513+
if err := decoder.Decode(&addressRefs); err != nil {
514+
return fmt.Errorf("failed to decode address refs JSON: %w", err)
515+
}
516+
517+
const (
518+
verifierIDPrefix = "default-verifier-"
519+
executorIDPrefix = "default-executor-"
520+
committeeName = "default"
521+
)
522+
var (
523+
onRampAddresses = make(map[string]string)
524+
// TODO: both maps below store the same data, just the key type is different
525+
committeeVerifierAddresses = make(map[string]string)
526+
committeeVerifierResolverProxyAddresses = make(map[uint64]string)
527+
defaultExecutorOnRampAddresses = make(map[string]string)
528+
defaultExecutorOnRampAddressesUint64 = make(map[uint64]string)
529+
rmnRemoteAddresses = make(map[string]string)
530+
rmnRemoteAddressesUint64 = make(map[uint64]string)
531+
offRampAddresses = make(map[uint64]string)
532+
thresholdPerSource = make(map[uint64]uint8)
533+
blockchainInfos = make(map[string]*protocol.BlockchainInfo)
534+
)
535+
for _, ref := range addressRefs {
536+
chainSelectorStr := strconv.FormatUint(ref.ChainSelector, 10)
537+
switch ref.Type {
538+
case datastore.ContractType(onrampoperations.ContractType):
539+
onRampAddresses[chainSelectorStr] = ref.Address
540+
case datastore.ContractType(committee_verifier.ResolverProxyType):
541+
committeeVerifierAddresses[chainSelectorStr] = ref.Address
542+
committeeVerifierResolverProxyAddresses[ref.ChainSelector] = ref.Address
543+
case datastore.ContractType(executor_operations.ContractType):
544+
defaultExecutorOnRampAddresses[chainSelectorStr] = ref.Address
545+
defaultExecutorOnRampAddressesUint64[ref.ChainSelector] = ref.Address
546+
case datastore.ContractType(rmn_remote.ContractType):
547+
rmnRemoteAddresses[chainSelectorStr] = ref.Address
548+
rmnRemoteAddressesUint64[ref.ChainSelector] = ref.Address
549+
case datastore.ContractType(offrampoperations.ContractType):
550+
offRampAddresses[ref.ChainSelector] = ref.Address
551+
}
552+
thresholdPerSource[ref.ChainSelector] = ocrThreshold(len(verifierPubKeys))
553+
554+
// TODO: these values don't really matter for deployments that use the chainlink node.
555+
// Blockchain infos should be moved to a separate config for standalone mode verifiers.
556+
blockchainInfos[chainSelectorStr] = &protocol.BlockchainInfo{
557+
ChainID: chainSelectorStr,
558+
Type: "evm",
559+
Family: "evm",
560+
UniqueChainName: fmt.Sprintf("blockchain-%s", chainSelectorStr),
561+
Nodes: []*protocol.Node{
562+
{
563+
ExternalHTTPUrl: fmt.Sprintf("some-random-http-url-%s", chainSelectorStr),
564+
InternalHTTPUrl: fmt.Sprintf("some-random-internal-http-url-%s", chainSelectorStr),
565+
ExternalWSUrl: fmt.Sprintf("some-random-ws-url-%s", chainSelectorStr),
566+
InternalWSUrl: fmt.Sprintf("some-random-internal-ws-url-%s", chainSelectorStr),
567+
},
568+
},
569+
}
570+
}
571+
572+
// create temporary directory to store the generated configs
573+
tempDir, err := os.MkdirTemp("", "ccv-configs")
574+
if err != nil {
575+
return fmt.Errorf("failed to create temporary directory: %w", err)
576+
}
577+
ccv.Plog.Info().Str("temp-dir", tempDir).Msg("Created temporary directory for configs")
578+
579+
// create the VerifierInput for each verifier
580+
verifierInputs := make([]*services.VerifierInput, 0, len(verifierPubKeys))
581+
for i, pubKey := range verifierPubKeys {
582+
verifierInputs = append(verifierInputs, &services.VerifierInput{
583+
ContainerName: fmt.Sprintf("%s%d", verifierIDPrefix, i),
584+
AggregatorAddress: fmt.Sprintf("%s:%d", aggregatorAddr, aggregatorPort),
585+
SigningKeyPublic: pubKey,
586+
CommitteeVerifierAddresses: committeeVerifierAddresses,
587+
OnRampAddresses: onRampAddresses,
588+
DefaultExecutorOnRampAddresses: defaultExecutorOnRampAddresses,
589+
RMNRemoteAddresses: rmnRemoteAddresses,
590+
CommitteeName: committeeName,
591+
MonitoringOtelExporterHTTPEndpoint: monitoringOtelExporterHTTPEndpoint,
592+
BlockchainInfos: blockchainInfos,
593+
})
594+
}
595+
// generate and print the job spec to stdout for now
596+
for _, verifierInput := range verifierInputs {
597+
verifierJobSpec, err := verifierInput.GenerateJobSpec()
598+
if err != nil {
599+
return fmt.Errorf("failed to generate verifier job spec: %w", err)
600+
}
601+
ccv.Plog.Info().Msg("Generated verifier job spec, writing to temporary directory as a separate file")
602+
// write to a file in the temporary directory generated above
603+
filePath := filepath.Join(tempDir, fmt.Sprintf("verifier-%s-job-spec.toml", verifierInput.ContainerName))
604+
if err := os.WriteFile(filePath, []byte(verifierJobSpec), 0o644); err != nil {
605+
return fmt.Errorf("failed to write verifier job spec to file: %w", err)
606+
}
607+
ccv.Plog.Info().Str("file-path", filePath).Msg("Wrote verifier job spec to file")
608+
}
609+
610+
// create the ExecutorInput for each executor
611+
executorInputs := make([]services.ExecutorInput, 0, numExecutors)
612+
// create executor pool first
613+
executorPool := make([]string, 0, numExecutors)
614+
for i := 0; i < numExecutors; i++ {
615+
executorPool = append(executorPool, fmt.Sprintf("%s%d", executorIDPrefix, i))
616+
}
617+
for i := 0; i < numExecutors; i++ {
618+
executorInputs = append(executorInputs, services.ExecutorInput{
619+
ExecutorID: fmt.Sprintf("%s%d", executorIDPrefix, i),
620+
ExecutorPool: executorPool,
621+
OfframpAddresses: offRampAddresses,
622+
IndexerAddress: indexerAddress,
623+
ExecutorAddresses: defaultExecutorOnRampAddressesUint64,
624+
RmnAddresses: rmnRemoteAddressesUint64,
625+
BlockchainInfos: blockchainInfos,
626+
})
627+
}
628+
// generate and print the config to stdout for now
629+
for _, executorInput := range executorInputs {
630+
executorJobSpec, err := executorInput.GenerateJobSpec()
631+
if err != nil {
632+
return fmt.Errorf("failed to generate executor job spec: %w", err)
633+
}
634+
ccv.Plog.Info().Msg("Generated executor job spec, writing to temporary directory as a separate file")
635+
// write to a file in the temporary directory generated above
636+
filePath := filepath.Join(tempDir, fmt.Sprintf("executor-%s-job-spec.toml", executorInput.ExecutorID))
637+
if err := os.WriteFile(filePath, []byte(executorJobSpec), 0o644); err != nil {
638+
return fmt.Errorf("failed to write executor job spec to file: %w", err)
639+
}
640+
ccv.Plog.Info().Str("file-path", filePath).Msg("Wrote executor job spec to file")
641+
}
642+
643+
// Create the AggregatorInput
644+
aggregatorInput := services.AggregatorInput{
645+
CommitteeName: committeeName,
646+
CommitteeVerifierResolverProxyAddresses: committeeVerifierResolverProxyAddresses,
647+
ThresholdPerSource: thresholdPerSource,
648+
MonitoringOtelExporterHTTPEndpoint: monitoringOtelExporterHTTPEndpoint,
649+
}
650+
// generate and print the config to stdout for now
651+
aggregatorConfig, err := aggregatorInput.GenerateConfig(verifierInputs)
652+
if err != nil {
653+
return fmt.Errorf("failed to generate aggregator config: %w", err)
654+
}
655+
ccv.Plog.Info().Msg("Generated aggregator config:")
656+
// write to a file in the temporary directory generated above
657+
filePath := filepath.Join(tempDir, "aggregator-config.toml")
658+
if err := os.WriteFile(filePath, aggregatorConfig, 0o644); err != nil {
659+
return fmt.Errorf("failed to write aggregator config to file: %w", err)
660+
}
661+
ccv.Plog.Info().Str("file-path", filePath).Msg("Wrote aggregator config to file")
662+
663+
return nil
664+
},
665+
}
666+
445667
var monitorContractsCmd = &cobra.Command{
446668
Use: "upload-on-chain-metrics <source> <dest>",
447669
Short: "Reads on-chain EVM contract events and temporary exposes them as Prometheus metrics endpoint to be scraped",
@@ -542,6 +764,11 @@ var sendCmd = &cobra.Command{
542764
ctx := context.Background()
543765
ctx = ccv.Plog.WithContext(ctx)
544766

767+
receiverQualifier, err := cmd.Flags().GetString("receiver-qualifier")
768+
if err != nil {
769+
return fmt.Errorf("failed to parse 'receiver-qualifier' flag: %w", err)
770+
}
771+
545772
// Read the env flag, default to "out"
546773
envName, err := cmd.Flags().GetString("env")
547774
if err != nil {
@@ -591,7 +818,7 @@ var sendCmd = &cobra.Command{
591818
dest,
592819
datastore.ContractType(mock_receiver.ContractType),
593820
semver.MustParse(mock_receiver.Deploy.Version()),
594-
evm.DefaultReceiverQualifier))
821+
receiverQualifier))
595822
if err != nil {
596823
return fmt.Errorf("failed to get mock receiver address: %w", err)
597824
}
@@ -691,6 +918,7 @@ func init() {
691918
rootCmd.AddCommand(printAddressesCmd)
692919
rootCmd.AddCommand(sendCmd)
693920
sendCmd.Flags().String("env", "out", "Select environment file to use (e.g., 'staging' for env-staging.toml, defaults to env-out.toml)")
921+
sendCmd.Flags().String("receiver-qualifier", evm.DefaultReceiverQualifier, "Receiver qualifier to use for the mock receiver contract")
694922

695923
// on-chain monitoring
696924
rootCmd.AddCommand(monitorContractsCmd)
@@ -699,6 +927,23 @@ func init() {
699927
// contract management
700928
rootCmd.AddCommand(deployCommitVerifierCmd)
701929
rootCmd.AddCommand(deployReceiverCmd)
930+
931+
// config generation
932+
rootCmd.AddCommand(generateConfigsCmd)
933+
generateConfigsCmd.Flags().String("address-refs-json", "", "Path to the CLD address_refs.json file")
934+
generateConfigsCmd.Flags().StringSlice("verifier-pubkeys", []string{}, "List of verifier public keys (comma separated), implies number of verifiers to generate configs for")
935+
generateConfigsCmd.Flags().String("aggregator-addr", "", "Aggregator gRPC address")
936+
generateConfigsCmd.Flags().Int("aggregator-port", 0, "Aggregator gRPC port")
937+
generateConfigsCmd.Flags().String("indexer-addr", "", "Indexer HTTP/s URL address")
938+
generateConfigsCmd.Flags().String("monitoring-otel-exporter-http-endpoint", "", "Monitoring OpenTelemetry HTTP endpoint, e.g. otel-collector:4318")
939+
generateConfigsCmd.Flags().Int("num-executors", -1, "Number of executors to generate configs for, defaults to number of verifiers if not provided")
940+
941+
_ = generateConfigsCmd.MarkFlagRequired("address-refs-json")
942+
_ = generateConfigsCmd.MarkFlagRequired("verifier-pubkeys")
943+
_ = generateConfigsCmd.MarkFlagRequired("aggregator-addr")
944+
_ = generateConfigsCmd.MarkFlagRequired("aggregator-port")
945+
_ = generateConfigsCmd.MarkFlagRequired("indexer-addr")
946+
_ = generateConfigsCmd.MarkFlagRequired("monitoring-otel-exporter-http-endpoint")
702947
}
703948

704949
func checkDockerIsRunning() {

build/devenv/env-staging.toml

Lines changed: 68 additions & 11 deletions
Large diffs are not rendered by default.

build/devenv/environment.go

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -525,11 +525,11 @@ func createJobs(in *Cfg, vIn []*services.VerifierInput, executorIn []*services.E
525525
case services.CL:
526526
index, clClient := roundRobin.GetNext()
527527

528-
tomlConfig, err := ver.GenerateConfig()
528+
jobSpec, err := ver.GenerateJobSpec()
529529
if err != nil {
530530
return fmt.Errorf("failed to generate verifier config: %w", err)
531531
}
532-
jb, resp, err := clClient.CreateJobRaw(committeeVerifierSpec(string(tomlConfig)))
532+
jb, resp, err := clClient.CreateJobRaw(jobSpec)
533533
if err != nil {
534534
return fmt.Errorf("failed to create committee verifier job: %w", err)
535535
}
@@ -550,12 +550,12 @@ func createJobs(in *Cfg, vIn []*services.VerifierInput, executorIn []*services.E
550550
case services.CL:
551551
index, clClient := roundRobin.GetNext()
552552

553-
tomlConfig, err := exec.GenerateConfig()
553+
jobSpec, err := exec.GenerateJobSpec()
554554
if err != nil {
555555
return fmt.Errorf("failed to generate executor config: %w", err)
556556
}
557557

558-
jb, resp, err := clClient.CreateJobRaw(executorSpec(string(tomlConfig)))
558+
jb, resp, err := clClient.CreateJobRaw(jobSpec)
559559
if err != nil {
560560
return fmt.Errorf("failed to create executor job: %w", err)
561561
}
@@ -574,30 +574,6 @@ func createJobs(in *Cfg, vIn []*services.VerifierInput, executorIn []*services.E
574574
return nil
575575
}
576576

577-
func executorSpec(tomlConfig string) string {
578-
return fmt.Sprintf(
579-
`
580-
schemaVersion = 1
581-
type = "ccvexecutor"
582-
executorConfig = """
583-
%s
584-
"""
585-
`, tomlConfig,
586-
)
587-
}
588-
589-
func committeeVerifierSpec(tomlConfig string) string {
590-
return fmt.Sprintf(
591-
`
592-
schemaVersion = 1
593-
type = "ccvcommitteeverifier"
594-
committeeVerifierConfig = """
595-
%s
596-
"""
597-
`, tomlConfig,
598-
)
599-
}
600-
601577
// launchCLNodes encapsulates the logic required to launch the core node. It may be better to wrap this in a service.
602578
// It returns the onchain public keys for each chain type for each CL node.
603579
func launchCLNodes(

0 commit comments

Comments
 (0)