github.com/smartcontractkit/chainlink-testing-framework/libs@v0.0.0-20240227141906-ec710b4eb1a3/docker/test_env/cmd/internal/start_test_env_commands.go (about)

     1  package internal
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	defaultlog "log"
     7  	"os"
     8  	"os/signal"
     9  	"strings"
    10  	"syscall"
    11  
    12  	"github.com/rs/zerolog"
    13  	"github.com/spf13/cobra"
    14  	flag "github.com/spf13/pflag"
    15  	"github.com/testcontainers/testcontainers-go"
    16  
    17  	"github.com/smartcontractkit/chainlink-testing-framework/libs/docker/test_env"
    18  	"github.com/smartcontractkit/chainlink-testing-framework/libs/logging"
    19  )
    20  
    21  var StartTestEnvCmd = &cobra.Command{
    22  	Use:   "start-test-env",
    23  	Short: "Start local test environment",
    24  }
    25  
    26  var startPrivateChain = &cobra.Command{
    27  	Use:   "private-chain",
    28  	Short: "Private chain with 1 node",
    29  	RunE:  startPrivateEthChainE,
    30  }
    31  
    32  const (
    33  	Flag_ConsensusType        = "consensus-type"
    34  	Flag_ConsensusLayer       = "consensus-layer"
    35  	Flag_ExecutionLayer       = "execution-layer"
    36  	Flag_WaitForFinalization  = "wait-for-finalization"
    37  	Flag_ChainID              = "chain-id"
    38  	Flag_ExecutionClientImage = "execution-layer-image"
    39  	Flag_ConsensucClientImage = "consensus-client-image"
    40  	Flag_ValidatorImage       = "validator-image"
    41  )
    42  
    43  func init() {
    44  	StartTestEnvCmd.AddCommand(startPrivateChain)
    45  
    46  	StartTestEnvCmd.PersistentFlags().StringP(
    47  		Flag_ConsensusType,
    48  		"t",
    49  		"pos",
    50  		"consensus type (pow or pos)",
    51  	)
    52  
    53  	StartTestEnvCmd.PersistentFlags().StringP(
    54  		Flag_ConsensusLayer,
    55  		"l",
    56  		"prysm",
    57  		"consensus layer (prysm)",
    58  	)
    59  
    60  	StartTestEnvCmd.PersistentFlags().StringP(
    61  		Flag_ExecutionLayer,
    62  		"e",
    63  		"geth",
    64  		"execution layer (geth, nethermind, besu or erigon)",
    65  	)
    66  
    67  	StartTestEnvCmd.PersistentFlags().BoolP(
    68  		Flag_WaitForFinalization,
    69  		"w",
    70  		false,
    71  		"wait for finalization of at least 1 epoch (might take up to 5 mintues)",
    72  	)
    73  
    74  	StartTestEnvCmd.PersistentFlags().IntP(
    75  		Flag_ChainID,
    76  		"c",
    77  		1337,
    78  		"chain id",
    79  	)
    80  
    81  	StartTestEnvCmd.PersistentFlags().String(
    82  		Flag_ExecutionClientImage,
    83  		"",
    84  		"custom Docker image for execution layer client",
    85  	)
    86  
    87  	StartTestEnvCmd.PersistentFlags().String(
    88  		Flag_ConsensucClientImage,
    89  		"",
    90  		"custom Docker image for consensus layer client",
    91  	)
    92  
    93  	StartTestEnvCmd.PersistentFlags().String(
    94  		Flag_ValidatorImage,
    95  		"",
    96  		"custom Docker image for validator",
    97  	)
    98  
    99  	// Set default log level for non-testcontainer code
   100  	zerolog.SetGlobalLevel(zerolog.InfoLevel)
   101  
   102  	// Discard testcontainers logs
   103  	testcontainers.Logger = defaultlog.New(io.Discard, "", defaultlog.LstdFlags)
   104  }
   105  
   106  func startPrivateEthChainE(cmd *cobra.Command, args []string) error {
   107  	log := logging.GetTestLogger(nil)
   108  	flags := cmd.Flags()
   109  
   110  	consensusType, err := flags.GetString(Flag_ConsensusType)
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	consensusType = strings.ToLower(consensusType)
   116  
   117  	if consensusType != "pos" && consensusType != "pow" {
   118  		return fmt.Errorf("invalid consensus type: %s. use 'pow' or 'pos'", consensusType)
   119  	}
   120  
   121  	consensusLayer, err := flags.GetString(Flag_ConsensusLayer)
   122  	if err != nil {
   123  		return err
   124  	}
   125  
   126  	consensusLayer = strings.ToLower(consensusLayer)
   127  
   128  	if consensusLayer != "" && consensusLayer != "prysm" {
   129  		return fmt.Errorf("invalid consensus layer: %s. use 'prysm'", consensusLayer)
   130  	}
   131  
   132  	if consensusLayer != "" && consensusType == "pow" {
   133  		log.Warn().Msg("consensus layer was set, but it has no sense for a PoW conensus. Ignoring it")
   134  	}
   135  
   136  	executionLayer, err := flags.GetString(Flag_ExecutionLayer)
   137  	if err != nil {
   138  		return err
   139  	}
   140  
   141  	executionLayer = strings.ToLower(executionLayer)
   142  	switch executionLayer {
   143  	case "geth", "nethermind", "besu", "erigon":
   144  	default:
   145  		return fmt.Errorf("invalid execution layer: %s. use 'geth', 'nethermind', 'besu' or 'erigon'", executionLayer)
   146  	}
   147  
   148  	waitForFinalization, err := flags.GetBool(Flag_WaitForFinalization)
   149  	if err != nil {
   150  		return err
   151  	}
   152  
   153  	chainId, err := flags.GetInt(Flag_ChainID)
   154  	if err != nil {
   155  		return err
   156  	}
   157  
   158  	consensusLayerToUse := test_env.ConsensusLayer(consensusLayer)
   159  	if consensusLayer != "" && consensusType == "pow" {
   160  		consensusLayerToUse = ""
   161  	}
   162  
   163  	customDockerImages, err := getCustomImages(flags)
   164  	if err != nil {
   165  		return err
   166  	}
   167  
   168  	builder := test_env.NewEthereumNetworkBuilder()
   169  	builder = *builder.WithConsensusType(test_env.ConsensusType(consensusType)).
   170  		WithConsensusLayer(consensusLayerToUse).
   171  		WithExecutionLayer(test_env.ExecutionLayer(executionLayer)).
   172  		WithEthereumChainConfig(test_env.EthereumChainConfig{
   173  			ValidatorCount: 8,
   174  			SlotsPerEpoch:  2,
   175  			SecondsPerSlot: 6,
   176  			ChainID:        chainId,
   177  		})
   178  
   179  	if waitForFinalization {
   180  		builder = *builder.WithWaitingForFinalization()
   181  	}
   182  
   183  	if len(customDockerImages) > 0 {
   184  		builder = *builder.WithCustomDockerImages(customDockerImages)
   185  	}
   186  
   187  	cfg, err := builder.
   188  		Build()
   189  
   190  	log.Info().Str("chain", cfg.Describe()).Msg("Starting private chain")
   191  
   192  	if err != nil {
   193  		return err
   194  	}
   195  
   196  	_, eth2, err := cfg.Start()
   197  
   198  	if err != nil {
   199  		return err
   200  	}
   201  	log.Info().Msg("---------- Private chain is ready ----------")
   202  	log.Info().Msgf("Public RPC WS URLs: %v", eth2.PublicWsUrls())
   203  	log.Info().Msgf("Public RPC HTTP URLs: %v", eth2.PublicHttpUrls())
   204  
   205  	err = cfg.Save()
   206  	if err != nil {
   207  		return err
   208  	}
   209  
   210  	handleExitSignal()
   211  
   212  	return nil
   213  }
   214  
   215  func handleExitSignal() {
   216  	// Create a channel to receive exit signals
   217  	exitChan := make(chan os.Signal, 1)
   218  	signal.Notify(exitChan, os.Interrupt, syscall.SIGTERM)
   219  
   220  	log := logging.GetTestLogger(nil)
   221  	log.Info().Msg("Press Ctrl+C to destroy the test environment")
   222  
   223  	// Block until an exit signal is received
   224  	<-exitChan
   225  }
   226  
   227  func getCustomImages(flags *flag.FlagSet) (map[test_env.ContainerType]string, error) {
   228  	customImages := make(map[test_env.ContainerType]string)
   229  	executionClientImage, err := flags.GetString(Flag_ExecutionClientImage)
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  
   234  	if executionClientImage != "" {
   235  		customImages[test_env.ContainerType_Besu] = executionClientImage
   236  		customImages[test_env.ContainerType_Erigon] = executionClientImage
   237  		customImages[test_env.ContainerType_Geth] = executionClientImage
   238  		customImages[test_env.ContainerType_Nethermind] = executionClientImage
   239  	}
   240  
   241  	consensusClientImage, err := flags.GetString(Flag_ConsensucClientImage)
   242  	if err != nil {
   243  		return nil, err
   244  	}
   245  
   246  	if consensusClientImage != "" {
   247  		customImages[test_env.ContainerType_PrysmBeacon] = consensusClientImage
   248  	}
   249  
   250  	validatorImage, err := flags.GetString(Flag_ValidatorImage)
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  
   255  	if validatorImage != "" {
   256  		customImages[test_env.ContainerType_PrysmVal] = validatorImage
   257  	}
   258  
   259  	return customImages, nil
   260  }