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

     1  package test_env
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/ethereum/go-ethereum/accounts/keystore"
    14  	"github.com/ethereum/go-ethereum/common"
    15  	"github.com/ethereum/go-ethereum/ethclient"
    16  	"github.com/google/uuid"
    17  	"github.com/rs/zerolog"
    18  	"github.com/rs/zerolog/log"
    19  	tc "github.com/testcontainers/testcontainers-go"
    20  	tcwait "github.com/testcontainers/testcontainers-go/wait"
    21  
    22  	"github.com/smartcontractkit/chainlink-testing-framework/libs/blockchain"
    23  	"github.com/smartcontractkit/chainlink-testing-framework/libs/docker"
    24  	"github.com/smartcontractkit/chainlink-testing-framework/libs/logging"
    25  	"github.com/smartcontractkit/chainlink-testing-framework/libs/mirror"
    26  	"github.com/smartcontractkit/chainlink-testing-framework/libs/utils/templates"
    27  	"github.com/smartcontractkit/chainlink-testing-framework/libs/utils/testcontext"
    28  )
    29  
    30  const (
    31  	TX_NON_DEV_GETH_WS_PORT = "8546"
    32  	BOOTNODE_PORT           = "30301"
    33  )
    34  
    35  var (
    36  	FundingAddresses = map[string]string{
    37  		"f39fd6e51aad88f6f4ce6ab8827279cfffb92266": `{"address":"f39fd6e51aad88f6f4ce6ab8827279cfffb92266","crypto":{"cipher":"aes-128-ctr","ciphertext":"c36afd6e60b82d6844530bd6ab44dbc3b85a53e826c3a7f6fc6a75ce38c1e4c6","cipherparams":{"iv":"f69d2bb8cd0cb6274535656553b61806"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"80d5f5e38ba175b6b89acfc8ea62a6f163970504af301292377ff7baafedab53"},"mac":"f2ecec2c4d05aacc10eba5235354c2fcc3776824f81ec6de98022f704efbf065"},"id":"e5c124e9-e280-4b10-a27b-d7f3e516b408","version":3}`,
    38  		"70997970c51812dc3a010c7d01b50e0d17dc79c8": `{"address":"70997970c51812dc3a010c7d01b50e0d17dc79c8","crypto":{"cipher":"aes-128-ctr","ciphertext":"f8183fa00bc112645d3e23e29a233e214f7c708bf49d72750c08af88ad76c980","cipherparams":{"iv":"796d08e3e1f71bde89ed826abda96cda"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"03c864a22a1f7b06b1da12d8b93e024ac144f898285907c58b2abc135fc8a35c"},"mac":"5fe91b1a1821c0d9f85dfd582354ead9612e9a7e9adc38b06a2beff558c119ac"},"id":"d2cab765-5e30-42ae-bb91-f090d9574fae","version":3}`,
    39  		"3c44cdddb6a900fa2b585dd299e03d12fa4293bc": `{"address":"3c44cdddb6a900fa2b585dd299e03d12fa4293bc","crypto":{"cipher":"aes-128-ctr","ciphertext":"2cd6ab87086c47f343f2c4d957eace7986f3b3c87fc35a2aafbefb57a06d9f1c","cipherparams":{"iv":"4e16b6cd580866c1aa642fb4d7312c9b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"0cabde93877f6e9a59070f9992f7a01848618263124835c90d4d07a0041fc57c"},"mac":"94b7776ea95b0ecd8406c7755acf17b389b7ebe489a8942e32082dfdc1f04f57"},"id":"ade1484b-a3bb-426f-9223-a1f5e3bde2e8","version":3}`,
    40  		"90f79bf6eb2c4f870365e785982e1f101e93b906": `{"address":"90f79bf6eb2c4f870365e785982e1f101e93b906","crypto":{"cipher":"aes-128-ctr","ciphertext":"15144214d323871e00f7b205368128061c91b77a27b7deec935f8f5b734f0d42","cipherparams":{"iv":"bb22ba8051ef9f60abded7a9f4f2c6ae"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"07331ef3035567c00830b4e50d5dd68bc877974b4ce38cd42fef755be01556c9"},"mac":"2294eacadaf2761851814451d8c7dcca20a606a0344335d98f09403aba4e82ca"},"id":"96af8cc7-97e1-4bba-8968-632b034986c2","version":3}`,
    41  		"15d34aaf54267db7d7c367839aaf71a00a2c6a65": `{"address":"15d34aaf54267db7d7c367839aaf71a00a2c6a65","crypto":{"cipher":"aes-128-ctr","ciphertext":"057878284a6c74d3ad99910adddd6b477b383837dbf2280efea585f0f0fdb012","cipherparams":{"iv":"e6eab29d60b526f305f8d47badf48687"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"dfdca8066d2486da5cb9a909d03744e2a8c6537930271e85e7cd8a5d952c0f22"},"mac":"f8352be41c9a06d69111ca4d8fcff0eef079b68b1173cad99803538991716c5d"},"id":"a35bb452-0d57-42d5-8d25-5a00a40a4db8","version":3}`,
    42  		"9965507d1a55bcc2695c58ba16fb37d819b0a4dc": `{"address":"9965507d1a55bcc2695c58ba16fb37d819b0a4dc","crypto":{"cipher":"aes-128-ctr","ciphertext":"5a73201500307c6aa98edd44d962b344a893768331454a61595ec848e738e9d2","cipherparams":{"iv":"5282de2b3e2b305019a2fed5c62f3383"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"6ad001831d097f175fff7d6cf61301e9620b32afd9a7a6437e6030af14576a96"},"mac":"0a55eddbd13c713aa8b8c4106b2fb62bc1d1e18e7177207a444f83a4d8426ed5"},"id":"27aed2b2-cb94-4d37-8819-b15219187bb5","version":3}`,
    43  		"976ea74026e726554db657fa54763abd0c3a0aa9": `{"address":"976ea74026e726554db657fa54763abd0c3a0aa9","crypto":{"cipher":"aes-128-ctr","ciphertext":"a6edf11e81b38e60a549696236cb9efc026e87adc45a9521ea7b2c45a2a9fbb9","cipherparams":{"iv":"82f4c79cd4b28a8585a9c78d758f832b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"87400e16ecc320dadff85eccbf4dbaaea2dd91e50047e4aa391799bb319c1fd8"},"mac":"80c83dad05998db6c673a97096fcfad54636458f4a3c82483686b253f8cc9b69"},"id":"fc7d7694-6206-48fc-bb25-36b523f90df6","version":3}`,
    44  		"14dc79964da2c08b23698b3d3cc7ca32193d9955": `{"address":"14dc79964da2c08b23698b3d3cc7ca32193d9955","crypto":{"cipher":"aes-128-ctr","ciphertext":"410f258bc8b12a0250cba22cbc5e413534fcf90bf322ced6943189ad9e43b4b9","cipherparams":{"iv":"1dd6077a8bee9b3bf2ca90e6abc8a237"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"5d3358bf99bbcb82354f40e5501abf4336bc141ee05d8feed4fbe7eb8c08c917"},"mac":"9cd959fa1e8129a8deb86e0264ec81d6cde79b5a19ae259b7d00543c9037908a"},"id":"689d7ad2-fe46-4c09-9c2a-a50e607989b8","version":3}`,
    45  		"23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f": `{"address":"23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f","crypto":{"cipher":"aes-128-ctr","ciphertext":"13dccac740314edea20d44e6f3592575bbcb739ec5892d635326cff3c386eb86","cipherparams":{"iv":"bf42d811cd41fa97ddcae3425f8c3211"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d2fa67cbb5e86d5bf9a90e27b8747bac493614b45778d43e9da1c14e06b2401d"},"mac":"7d2797cf344704d8f36265238d3938e06952c78ab7dfcbac53dc7f472c93d933"},"id":"4c8e899e-80f0-4417-9b1e-c5e29049f1e7","version":3}`,
    46  		"a0ee7a142d267c1f36714e4a8f75612f20a79720": `{"address":"a0ee7a142d267c1f36714e4a8f75612f20a79720","crypto":{"cipher":"aes-128-ctr","ciphertext":"56bc8766f47aeafae74eea333e1e890a3776d7fae6c48cbdbffb270655ce050d","cipherparams":{"iv":"a66129e6a110b3ddf93b4355aa147c58"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"15c4e8bcc80920139eb236d91194825f1fce27dd2af281e0f2752d8a5dbc48bd"},"mac":"db01e720866ce8bb7897dfc7773e064003ad53429a79732ee769cf6d02273570"},"id":"87b2d76f-1b70-4e4f-8b2a-5d1915c1177c","version":3}`,
    47  		"bcd4042de499d14e55001ccbb24a551f3b954096": `{"address":"bcd4042de499d14e55001ccbb24a551f3b954096","crypto":{"cipher":"aes-128-ctr","ciphertext":"e455eda6e38d246c03b930f845adfc8721ca75e9f47135cd4c18dbc3e5c5440a","cipherparams":{"iv":"0b1a0a24acc1ad25b0f170f751c2cb27"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"69f324ed0787794878bf5f84d4dbbc70dec1274cad666399edc48640605f64c8"},"mac":"f07da09c460a69f943f5639545d2b3f72c1e9789f0421ad41d3078ea3db12c96"},"id":"7ec7bb3c-c486-4785-a4fc-f8f4b2fc7764","version":3}`,
    48  		"71be63f3384f5fb98995898a86b02fb2426c5788": `{"address":"71be63f3384f5fb98995898a86b02fb2426c5788","crypto":{"cipher":"aes-128-ctr","ciphertext":"4194377a05fd3d13e0a3155dad974a003fe5f7a3b5acb35d7d97c50daa8990d4","cipherparams":{"iv":"607670778baf62b1e86394cf1980487a"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d63b890ad7f4fcc857681faabe9319dffc53893966ef0810bf64c4f319b0ffc5"},"mac":"bfaf924959e65c8030ece259d52ed52d5d21bd74f1a67ae545d4bb289a479e16"},"id":"0c6af842-384f-49b6-b5b7-199a1e05486b","version":3}`,
    49  	}
    50  )
    51  
    52  type PrivateGethChain struct {
    53  	PrimaryNode    *NonDevGethNode
    54  	Nodes          []*NonDevGethNode
    55  	NetworkConfig  *blockchain.EVMNetwork
    56  	DockerNetworks []string
    57  }
    58  
    59  func NewPrivateGethChain(networkCfg *blockchain.EVMNetwork, dockerNetworks []string) PrivateChain {
    60  	evmChain := &PrivateGethChain{
    61  		NetworkConfig:  networkCfg,
    62  		DockerNetworks: dockerNetworks,
    63  	}
    64  	evmChain.PrimaryNode = NewNonDevGethNode(dockerNetworks, networkCfg)
    65  	evmChain.Nodes = []*NonDevGethNode{evmChain.PrimaryNode}
    66  	return evmChain
    67  }
    68  
    69  func (p *PrivateGethChain) WithTestInstance(t *testing.T) *PrivateGethChain {
    70  	p.PrimaryNode.l = logging.GetTestLogger(t)
    71  	return p
    72  }
    73  
    74  func (p *PrivateGethChain) GetPrimaryNode() NonDevNode {
    75  	return p.PrimaryNode
    76  }
    77  
    78  func (p *PrivateGethChain) GetNodes() []NonDevNode {
    79  	nodes := make([]NonDevNode, 0)
    80  	for _, node := range p.Nodes {
    81  		nodes = append(nodes, node)
    82  	}
    83  	return nodes
    84  }
    85  
    86  func (p *PrivateGethChain) GetNetworkConfig() *blockchain.EVMNetwork {
    87  	return p.NetworkConfig
    88  }
    89  
    90  func (p *PrivateGethChain) GetDockerNetworks() []string {
    91  	return p.DockerNetworks
    92  }
    93  
    94  type gethTxNodeConfig struct {
    95  	networkCfg       *blockchain.EVMNetwork
    96  	chainId          string
    97  	bootnodeInitPath string
    98  	genesisPath      string
    99  	rootPath         string
   100  	keystorePath     string
   101  	initPath         string
   102  	bootNodeURL      string
   103  	accountAddr      string
   104  }
   105  
   106  type NonDevGethNode struct {
   107  	EnvComponent
   108  	Config          gethTxNodeConfig
   109  	ExternalHttpUrl string
   110  	InternalHttpUrl string
   111  	ExternalWsUrl   string
   112  	InternalWsUrl   string
   113  	EVMClient       blockchain.EVMClient
   114  	EthClient       *ethclient.Client
   115  	t               *testing.T
   116  	l               zerolog.Logger
   117  }
   118  
   119  func NewNonDevGethNode(networks []string, networkCfg *blockchain.EVMNetwork) *NonDevGethNode {
   120  	return &NonDevGethNode{
   121  		Config: gethTxNodeConfig{
   122  			chainId:    strconv.FormatInt(networkCfg.ChainID, 10),
   123  			networkCfg: networkCfg,
   124  		},
   125  		EnvComponent: EnvComponent{
   126  			ContainerName: fmt.Sprintf("%s-%s",
   127  				strings.ReplaceAll(networkCfg.Name, " ", "_"), uuid.NewString()[0:3]),
   128  			Networks: networks,
   129  		},
   130  		l: log.Logger,
   131  	}
   132  }
   133  
   134  func (g *NonDevGethNode) GetInternalHttpUrl() string {
   135  	return g.InternalHttpUrl
   136  }
   137  
   138  func (g *NonDevGethNode) GetInternalWsUrl() string {
   139  	return g.InternalWsUrl
   140  }
   141  
   142  func (g *NonDevGethNode) GetEVMClient() blockchain.EVMClient {
   143  	return g.EVMClient
   144  }
   145  
   146  func (g *NonDevGethNode) WithTestInstance(t *testing.T) NonDevNode {
   147  	g.t = t
   148  	g.l = logging.GetTestLogger(t)
   149  	return g
   150  }
   151  
   152  func (g *NonDevGethNode) createMountDirs() error {
   153  	initScriptFile, err := os.CreateTemp("", "init_script")
   154  	if err != nil {
   155  		return err
   156  	}
   157  	_, err = initScriptFile.WriteString(templates.InitNonDevGethScript)
   158  	if err != nil {
   159  		return err
   160  	}
   161  	g.Config.initPath = initScriptFile.Name()
   162  
   163  	bootinitScriptFile, err := os.CreateTemp("", "bootnode_init_script")
   164  	if err != nil {
   165  		return err
   166  	}
   167  	_, err = bootinitScriptFile.WriteString(templates.BootnodeScript)
   168  	if err != nil {
   169  		return err
   170  	}
   171  	g.Config.bootnodeInitPath = bootinitScriptFile.Name()
   172  
   173  	keystorePath, err := os.MkdirTemp("", "keystore")
   174  	if err != nil {
   175  		return err
   176  	}
   177  	g.Config.keystorePath = keystorePath
   178  
   179  	// Create keystore and ethereum account
   180  	ks := keystore.NewKeyStore(g.Config.keystorePath, keystore.StandardScryptN, keystore.StandardScryptP)
   181  	account, err := ks.NewAccount("")
   182  	if err != nil {
   183  		return err
   184  	}
   185  	g.Config.accountAddr = account.Address.Hex()
   186  	addr := strings.Replace(account.Address.Hex(), "0x", "", 1)
   187  	FundingAddresses[addr] = ""
   188  	signerBytes, err := hex.DecodeString(addr)
   189  	if err != nil {
   190  		fmt.Println("Error decoding signer address:", err)
   191  		return err
   192  	}
   193  
   194  	zeroBytes := make([]byte, 32)                      // Create 32 zero bytes
   195  	extradata := append(zeroBytes, signerBytes...)     // Concatenate zero bytes and signer address
   196  	extradata = append(extradata, make([]byte, 65)...) // Concatenate 65 more zero bytes
   197  
   198  	fmt.Printf("Encoded extradata: 0x%s\n", hex.EncodeToString(extradata))
   199  
   200  	i := 1
   201  	var accounts []string
   202  	for addr, v := range FundingAddresses {
   203  		if v == "" {
   204  			continue
   205  		}
   206  		f, err := os.Create(fmt.Sprintf("%s/%s", g.Config.keystorePath, fmt.Sprintf("key%d", i)))
   207  		if err != nil {
   208  			return err
   209  		}
   210  		_, err = f.WriteString(v)
   211  		if err != nil {
   212  			return err
   213  		}
   214  		i++
   215  		accounts = append(accounts, addr)
   216  	}
   217  	err = os.WriteFile(g.Config.keystorePath+"/password.txt", []byte(""), 0600)
   218  	if err != nil {
   219  		return err
   220  	}
   221  
   222  	genesisJsonStr, err := templates.BuildGenesisJsonForNonDevChain(g.Config.chainId, accounts, fmt.Sprintf("0x%s", hex.EncodeToString(extradata)))
   223  	if err != nil {
   224  		return err
   225  	}
   226  	f, err := os.CreateTemp("", "genesis_json")
   227  	if err != nil {
   228  		return err
   229  	}
   230  	defer f.Close()
   231  	_, err = f.WriteString(genesisJsonStr)
   232  	if err != nil {
   233  		return err
   234  	}
   235  
   236  	g.Config.genesisPath = f.Name()
   237  
   238  	configDir, err := os.MkdirTemp("", "config")
   239  	if err != nil {
   240  		return err
   241  	}
   242  	g.Config.rootPath = configDir
   243  
   244  	return nil
   245  }
   246  
   247  func (g *NonDevGethNode) Start() error {
   248  	err := g.createMountDirs()
   249  	if err != nil {
   250  		return err
   251  	}
   252  
   253  	l := logging.GetTestContainersGoTestLogger(g.t)
   254  	bncr, err := g.getBootNodeContainerRequest()
   255  	if err != nil {
   256  		return err
   257  	}
   258  	bootNode, err := docker.StartContainerWithRetry(g.l, tc.GenericContainerRequest{
   259  		ContainerRequest: bncr,
   260  		Reuse:            true,
   261  		Started:          true,
   262  		Logger:           l,
   263  	})
   264  	if err != nil {
   265  		return err
   266  	}
   267  	host, err := bootNode.Host(testcontext.Get(g.t))
   268  	if err != nil {
   269  		return err
   270  	}
   271  	r, err := bootNode.CopyFileFromContainer(testcontext.Get(g.t), "/root/.ethereum/bootnodes")
   272  	if err != nil {
   273  		return err
   274  	}
   275  	defer r.Close()
   276  	b, err := io.ReadAll(r)
   277  	if err != nil {
   278  		return err
   279  	}
   280  	g.Config.bootNodeURL = fmt.Sprintf("enode://%s@%s:0?discport=%s", strings.TrimSpace(string(b)), host, BOOTNODE_PORT)
   281  
   282  	cr, err := g.getGethContainerRequest()
   283  	if err != nil {
   284  		return err
   285  	}
   286  	ct, err := docker.StartContainerWithRetry(g.l, tc.GenericContainerRequest{
   287  		ContainerRequest: cr,
   288  		Reuse:            true,
   289  		Started:          true,
   290  	})
   291  	if err != nil {
   292  		return err
   293  	}
   294  	g.Container = ct
   295  	return nil
   296  }
   297  
   298  func (g *NonDevGethNode) ConnectToClient() error {
   299  	ct := g.Container
   300  	if ct == nil {
   301  		return fmt.Errorf("container not started")
   302  	}
   303  	host, err := GetHost(testcontext.Get(g.t), ct)
   304  	if err != nil {
   305  		return err
   306  	}
   307  	port := NatPort(TX_GETH_HTTP_PORT)
   308  	httpPort, err := ct.MappedPort(testcontext.Get(g.t), port)
   309  	if err != nil {
   310  		return err
   311  	}
   312  	wsPort, err := ct.MappedPort(testcontext.Get(g.t), NatPort(TX_NON_DEV_GETH_WS_PORT))
   313  	if err != nil {
   314  		return err
   315  	}
   316  
   317  	g.ExternalHttpUrl = fmt.Sprintf("http://%s:%s", host, httpPort.Port())
   318  	g.InternalHttpUrl = fmt.Sprintf("http://%s:%s", g.ContainerName, TX_GETH_HTTP_PORT)
   319  	g.ExternalWsUrl = fmt.Sprintf("ws://%s:%s", host, wsPort.Port())
   320  	g.InternalWsUrl = fmt.Sprintf("ws://%s:%s", g.ContainerName, TX_NON_DEV_GETH_WS_PORT)
   321  
   322  	networkConfig := g.Config.networkCfg
   323  	networkConfig.URLs = []string{g.ExternalWsUrl}
   324  	networkConfig.HTTPURLs = []string{g.ExternalHttpUrl}
   325  
   326  	ec, err := blockchain.NewEVMClientFromNetwork(*networkConfig, g.l)
   327  	if err != nil {
   328  		return err
   329  	}
   330  	at, err := ec.BalanceAt(testcontext.Get(g.t), common.HexToAddress("0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266"))
   331  	if err != nil {
   332  		return err
   333  	}
   334  	fmt.Printf("balance: %s\n", at.String())
   335  	g.EVMClient = ec
   336  	// to make sure all the pending txs are done
   337  	err = ec.WaitForEvents()
   338  	if err != nil {
   339  		return err
   340  	}
   341  	switch val := ec.(type) {
   342  	case *blockchain.EthereumMultinodeClient:
   343  		ethClient, ok := val.Clients[0].(*blockchain.EthereumClient)
   344  		if !ok {
   345  			return fmt.Errorf("could not get blockchain.EthereumClient from %+v", val)
   346  		}
   347  		g.EthClient = ethClient.Client
   348  	default:
   349  		return fmt.Errorf("%+v not supported for geth", val)
   350  	}
   351  	if err != nil {
   352  		return err
   353  	}
   354  	return nil
   355  }
   356  
   357  func (g *NonDevGethNode) getBootNodeContainerRequest() (tc.ContainerRequest, error) {
   358  	bootNodeImage, err := mirror.GetImage("ethereum/client-go:alltools")
   359  	if err != nil {
   360  		return tc.ContainerRequest{}, err
   361  	}
   362  	return tc.ContainerRequest{
   363  		Name:         g.ContainerName + "-bootnode",
   364  		Image:        bootNodeImage,
   365  		Networks:     g.Networks,
   366  		ExposedPorts: []string{"30301/udp"},
   367  		WaitingFor: tcwait.ForLog("New local node record").
   368  			WithStartupTimeout(999 * time.Second).
   369  			WithPollInterval(1 * time.Second),
   370  		Cmd: []string{"sh", "./root/boot_init.sh"},
   371  		Files: []tc.ContainerFile{
   372  			{
   373  				HostFilePath:      g.Config.bootnodeInitPath,
   374  				ContainerFilePath: "/root/boot_init.sh",
   375  				FileMode:          0644,
   376  			},
   377  		},
   378  		Mounts: tc.ContainerMounts{
   379  			tc.ContainerMount{
   380  				Source: tc.GenericBindMountSource{
   381  					HostPath: g.Config.rootPath,
   382  				},
   383  				Target: "/root/.ethereum/",
   384  			},
   385  		},
   386  	}, nil
   387  }
   388  func (g *NonDevGethNode) getGethContainerRequest() (tc.ContainerRequest, error) {
   389  	gethImage, err := mirror.GetImage("ethereum/client-go:v")
   390  	if err != nil {
   391  		return tc.ContainerRequest{}, err
   392  	}
   393  	return tc.ContainerRequest{
   394  		Name:  g.ContainerName,
   395  		Image: gethImage,
   396  		ExposedPorts: []string{
   397  			NatPortFormat(TX_GETH_HTTP_PORT),
   398  			NatPortFormat(TX_NON_DEV_GETH_WS_PORT),
   399  			"30303/tcp", "30303/udp"},
   400  		Networks: g.Networks,
   401  		WaitingFor: tcwait.ForAll(
   402  			NewHTTPStrategy("/", NatPort(TX_GETH_HTTP_PORT)),
   403  			tcwait.ForLog("WebSocket enabled"),
   404  			NewWebSocketStrategy(NatPort(TX_NON_DEV_GETH_WS_PORT), g.l),
   405  		),
   406  		Entrypoint: []string{"/bin/sh", "./root/init.sh",
   407  			"--http.vhosts=*",
   408  			"--nousb", "--metrics", "--nocompaction", "--syncmode", "full",
   409  			"--gcmode", "archive",
   410  			fmt.Sprintf("--bootnodes=%s", g.Config.bootNodeURL),
   411  			"--http",
   412  			"--http.corsdomain", "*",
   413  			"--http.api", "admin,debug,web3,eth,txpool,personal,clique,miner,net",
   414  			"--http.addr", "0.0.0.0",
   415  			fmt.Sprintf("--http.port=%s", TX_GETH_HTTP_PORT),
   416  			"--ws",
   417  			"--ws.origins", "*",
   418  			"--ws.api", "admin,debug,web3,eth,txpool,personal,clique,miner,net",
   419  			"--ws.addr", "0.0.0.0",
   420  			fmt.Sprintf("--ws.port=%s", TX_NON_DEV_GETH_WS_PORT),
   421  			"--unlock", g.Config.accountAddr,
   422  			"--mine",
   423  			"--miner.etherbase", g.Config.accountAddr,
   424  			"--miner.extradata", "tx",
   425  			"--miner.gasprice", "1",
   426  			"--miner.gaslimit", "400000000000000",
   427  			"--miner.extradata", "tx",
   428  			fmt.Sprintf("--networkid=%s", g.Config.chainId),
   429  			"--allow-insecure-unlock",
   430  			"--password", "/root/.ethereum/keystore/password.txt",
   431  			"--verbosity=5",
   432  			"--rpc.allow-unprotected-txs",
   433  			"--rpc.gascap", "0",
   434  			"--rpc.txfeecap", "0",
   435  		},
   436  		Files: []tc.ContainerFile{
   437  			{
   438  				HostFilePath:      g.Config.initPath,
   439  				ContainerFilePath: "/root/init.sh",
   440  				FileMode:          0644,
   441  			},
   442  			{
   443  				HostFilePath:      g.Config.genesisPath,
   444  				ContainerFilePath: "/root/genesis.json",
   445  				FileMode:          0644,
   446  			},
   447  		},
   448  		Mounts: tc.ContainerMounts{
   449  			tc.ContainerMount{
   450  				Source: tc.GenericBindMountSource{
   451  					HostPath: g.Config.keystorePath,
   452  				},
   453  				Target: "/root/.ethereum/keystore/",
   454  			},
   455  			tc.ContainerMount{
   456  				Source: tc.GenericBindMountSource{
   457  					HostPath: g.Config.rootPath,
   458  				},
   459  				Target: "/root/.ethereum/",
   460  			},
   461  		},
   462  	}, nil
   463  }