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

     1  package test_env
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/google/uuid"
    11  	"github.com/rs/zerolog"
    12  
    13  	tc "github.com/testcontainers/testcontainers-go"
    14  	tcwait "github.com/testcontainers/testcontainers-go/wait"
    15  
    16  	"github.com/smartcontractkit/chainlink-testing-framework/libs/blockchain"
    17  	"github.com/smartcontractkit/chainlink-testing-framework/libs/docker"
    18  	"github.com/smartcontractkit/chainlink-testing-framework/libs/logging"
    19  	"github.com/smartcontractkit/chainlink-testing-framework/libs/mirror"
    20  )
    21  
    22  type Nethermind struct {
    23  	EnvComponent
    24  	ExternalHttpUrl      string
    25  	InternalHttpUrl      string
    26  	ExternalWsUrl        string
    27  	InternalWsUrl        string
    28  	InternalExecutionURL string
    29  	ExternalExecutionURL string
    30  	generatedDataHostDir string
    31  	consensusLayer       ConsensusLayer
    32  	l                    zerolog.Logger
    33  	t                    *testing.T
    34  }
    35  
    36  func NewNethermind(networks []string, generatedDataHostDir string, consensusLayer ConsensusLayer, opts ...EnvComponentOption) (*Nethermind, error) {
    37  	// currently it uses 1.25.1
    38  	dockerImage, err := mirror.GetImage("nethermind/nethermind:1")
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	parts := strings.Split(dockerImage, ":")
    44  	g := &Nethermind{
    45  		EnvComponent: EnvComponent{
    46  			ContainerName:    fmt.Sprintf("%s-%s", "nethermind", uuid.NewString()[0:8]),
    47  			Networks:         networks,
    48  			ContainerImage:   parts[0],
    49  			ContainerVersion: parts[1],
    50  		},
    51  		generatedDataHostDir: generatedDataHostDir,
    52  		consensusLayer:       consensusLayer,
    53  		l:                    logging.GetTestLogger(nil),
    54  	}
    55  	for _, opt := range opts {
    56  		opt(&g.EnvComponent)
    57  	}
    58  	return g, nil
    59  }
    60  
    61  func (g *Nethermind) WithTestInstance(t *testing.T) ExecutionClient {
    62  	g.l = logging.GetTestLogger(t)
    63  	g.t = t
    64  	return g
    65  }
    66  
    67  func (g *Nethermind) StartContainer() (blockchain.EVMNetwork, error) {
    68  	r, err := g.getContainerRequest(g.Networks)
    69  	if err != nil {
    70  		return blockchain.EVMNetwork{}, err
    71  	}
    72  
    73  	l := logging.GetTestContainersGoTestLogger(g.t)
    74  	ct, err := docker.StartContainerWithRetry(g.l, tc.GenericContainerRequest{
    75  		ContainerRequest: *r,
    76  		Reuse:            true,
    77  		Started:          true,
    78  		Logger:           l,
    79  	})
    80  	if err != nil {
    81  		return blockchain.EVMNetwork{}, fmt.Errorf("cannot start nethermind container: %w", err)
    82  	}
    83  
    84  	host, err := GetHost(context.Background(), ct)
    85  	if err != nil {
    86  		return blockchain.EVMNetwork{}, err
    87  	}
    88  	if err != nil {
    89  		return blockchain.EVMNetwork{}, err
    90  	}
    91  	httpPort, err := ct.MappedPort(context.Background(), NatPort(TX_GETH_HTTP_PORT))
    92  	if err != nil {
    93  		return blockchain.EVMNetwork{}, err
    94  	}
    95  	wsPort, err := ct.MappedPort(context.Background(), NatPort(TX_GETH_WS_PORT))
    96  	if err != nil {
    97  		return blockchain.EVMNetwork{}, err
    98  	}
    99  	executionPort, err := ct.MappedPort(context.Background(), NatPort(ETH2_EXECUTION_PORT))
   100  	if err != nil {
   101  		return blockchain.EVMNetwork{}, err
   102  	}
   103  
   104  	g.Container = ct
   105  	g.ExternalHttpUrl = FormatHttpUrl(host, httpPort.Port())
   106  	g.InternalHttpUrl = FormatHttpUrl(g.ContainerName, TX_GETH_HTTP_PORT)
   107  	g.ExternalWsUrl = FormatWsUrl(host, wsPort.Port())
   108  	g.InternalWsUrl = FormatWsUrl(g.ContainerName, TX_GETH_WS_PORT)
   109  	g.InternalExecutionURL = FormatHttpUrl(g.ContainerName, ETH2_EXECUTION_PORT)
   110  	g.ExternalExecutionURL = FormatHttpUrl(host, executionPort.Port())
   111  
   112  	networkConfig := blockchain.SimulatedEVMNetwork
   113  	networkConfig.Name = fmt.Sprintf("Simulated Eth2 (nethermind + %s)", g.consensusLayer)
   114  	networkConfig.URLs = []string{g.ExternalWsUrl}
   115  	networkConfig.HTTPURLs = []string{g.ExternalHttpUrl}
   116  
   117  	g.l.Info().Str("containerName", g.ContainerName).
   118  		Msg("Started Nethermind container")
   119  
   120  	return networkConfig, nil
   121  }
   122  
   123  func (g *Nethermind) GetInternalExecutionURL() string {
   124  	return g.InternalExecutionURL
   125  }
   126  
   127  func (g *Nethermind) GetExternalExecutionURL() string {
   128  	return g.ExternalExecutionURL
   129  }
   130  
   131  func (g *Nethermind) GetInternalHttpUrl() string {
   132  	return g.InternalHttpUrl
   133  }
   134  
   135  func (g *Nethermind) GetInternalWsUrl() string {
   136  	return g.InternalWsUrl
   137  }
   138  
   139  func (g *Nethermind) GetExternalHttpUrl() string {
   140  	return g.ExternalHttpUrl
   141  }
   142  
   143  func (g *Nethermind) GetExternalWsUrl() string {
   144  	return g.ExternalWsUrl
   145  }
   146  
   147  func (g *Nethermind) GetContainerName() string {
   148  	return g.ContainerName
   149  }
   150  
   151  func (g *Nethermind) GetContainer() *tc.Container {
   152  	return &g.Container
   153  }
   154  
   155  func (g *Nethermind) getContainerRequest(networks []string) (*tc.ContainerRequest, error) {
   156  	return &tc.ContainerRequest{
   157  		Name:            g.ContainerName,
   158  		Image:           g.GetImageWithVersion(),
   159  		Networks:        networks,
   160  		AlwaysPullImage: true,
   161  		// ImagePlatform: "linux/x86_64",  //don't even try this on Apple Silicon, the node won't start due to .NET error
   162  		ExposedPorts: []string{NatPortFormat(TX_GETH_HTTP_PORT), NatPortFormat(TX_GETH_WS_PORT), NatPortFormat(ETH2_EXECUTION_PORT)},
   163  		WaitingFor: tcwait.ForAll(
   164  			tcwait.ForLog("Nethermind initialization completed").
   165  				WithStartupTimeout(120 * time.Second).
   166  				WithPollInterval(1 * time.Second),
   167  		),
   168  		Cmd: []string{
   169  			"--datadir=/nethermind",
   170  			"--config=none.cfg",
   171  			fmt.Sprintf("--Init.ChainSpecPath=%s/chainspec.json", GENERATED_DATA_DIR_INSIDE_CONTAINER),
   172  			"--Init.DiscoveryEnabled=false",
   173  			"--Init.WebSocketsEnabled=true",
   174  			fmt.Sprintf("--JsonRpc.WebSocketsPort=%s", TX_GETH_WS_PORT),
   175  			"--JsonRpc.Enabled=true",
   176  			"--JsonRpc.EnabledModules=net,eth,consensus,subscribe,web3,admin",
   177  			"--JsonRpc.Host=0.0.0.0",
   178  			fmt.Sprintf("--JsonRpc.Port=%s", TX_GETH_HTTP_PORT),
   179  			"--JsonRpc.EngineHost=0.0.0.0",
   180  			"--JsonRpc.EnginePort=" + ETH2_EXECUTION_PORT,
   181  			fmt.Sprintf("--JsonRpc.JwtSecretFile=%s", JWT_SECRET_FILE_LOCATION_INSIDE_CONTAINER),
   182  			fmt.Sprintf("--KeyStore.KeyStoreDirectory=%s", KEYSTORE_DIR_LOCATION_INSIDE_CONTAINER),
   183  			"--KeyStore.BlockAuthorAccount=0x123463a4b065722e99115d6c222f267d9cabb524",
   184  			"--KeyStore.UnlockAccounts=0x123463a4b065722e99115d6c222f267d9cabb524",
   185  			fmt.Sprintf("--KeyStore.PasswordFiles=%s", ACCOUNT_PASSWORD_FILE_INSIDE_CONTAINER),
   186  			"--Network.MaxActivePeers=0",
   187  			"--Network.OnlyStaticPeers=true",
   188  			"--HealthChecks.Enabled=true", // default slug /health
   189  		},
   190  		Mounts: tc.ContainerMounts{
   191  			tc.ContainerMount{
   192  				Source: tc.GenericBindMountSource{
   193  					HostPath: g.generatedDataHostDir,
   194  				},
   195  				Target: tc.ContainerMountTarget(GENERATED_DATA_DIR_INSIDE_CONTAINER),
   196  			},
   197  		},
   198  		LifecycleHooks: []tc.ContainerLifecycleHooks{
   199  			{
   200  				PostStarts: g.PostStartsHooks,
   201  				PostStops:  g.PostStopsHooks,
   202  			},
   203  		},
   204  	}, nil
   205  }
   206  
   207  func (g *Nethermind) WaitUntilChainIsReady(ctx context.Context, waitTime time.Duration) error {
   208  	waitForFirstBlock := tcwait.NewLogStrategy("Improved post-merge block").WithPollInterval(1 * time.Second).WithStartupTimeout(waitTime)
   209  	return waitForFirstBlock.WaitUntilReady(ctx, *g.GetContainer())
   210  }
   211  
   212  func (g *Nethermind) GetContainerType() ContainerType {
   213  	return ContainerType_Nethermind
   214  }