diff --git a/client/asset/eth/eth.go b/client/asset/eth/eth.go index c68876c623..b33444c0bb 100644 --- a/client/asset/eth/eth.go +++ b/client/asset/eth/eth.go @@ -596,7 +596,6 @@ func createWallet(createWalletParams *asset.CreateWalletParams, skipConnect bool return errors.New("no providers specified") } endpoints := strings.Split(providerDef, providerDelimiter) - n := len(endpoints) // TODO: This procedure may actually work for walletTypeGeth too. ks := keystore.NewKeyStore(filepath.Join(walletDir, "keystore"), keystore.LightScryptN, keystore.LightScryptP) @@ -607,36 +606,9 @@ func createWallet(createWalletParams *asset.CreateWalletParams, skipConnect bool } if !skipConnect { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - - var unknownEndpoints []string - - for _, endpoint := range endpoints { - known, compliant := providerIsCompliant(endpoint) - if known && !compliant { - return fmt.Errorf("provider %q is known to have an insufficient API for DEX", endpoint) - } else if !known { - unknownEndpoints = append(unknownEndpoints, endpoint) - } - } - - if len(unknownEndpoints) > 0 && createWalletParams.Net == dex.Mainnet { - providers, err := connectProviders(ctx, unknownEndpoints, createWalletParams.Logger, big.NewInt(chainIDs[createWalletParams.Net]), createWalletParams.Net) - if err != nil { - return err - } - defer func() { - for _, p := range providers { - p.ec.Close() - } - }() - if len(providers) != n { - return fmt.Errorf("Could not connect to all providers") - } - if err := checkProvidersCompliance(ctx, walletDir, providers, createWalletParams.Logger); err != nil { - return err - } + if err := createAndCheckProviders(context.Background(), walletDir, endpoints, + createWalletParams.Net, createWalletParams.Logger); err != nil { + return fmt.Errorf("create and check providers problem: %v", err) } } return importKeyToKeyStore(ks, priv, createWalletParams.Pass) @@ -893,7 +865,8 @@ func (w *ETHWallet) Reconfigure(ctx context.Context, cfg *asset.WalletConfig, cu } if rpc, is := w.node.(*multiRPCClient); is { - if err := rpc.reconfigure(ctx, cfg.Settings); err != nil { + walletDir := getWalletDir(w.dir, w.net) + if err := rpc.reconfigure(ctx, cfg.Settings, walletDir); err != nil { return false, err } } diff --git a/client/asset/eth/multirpc.go b/client/asset/eth/multirpc.go index 0b975ba474..2d3f518ce9 100644 --- a/client/asset/eth/multirpc.go +++ b/client/asset/eth/multirpc.go @@ -84,12 +84,13 @@ type provider struct { // host is the domain and tld of the provider, and is used as a identifier // in logs and as a unique, path- and subdomain-independent ID for e.g. map // keys. - host string - ec *combinedRPCClient - ws bool - net dex.Network - tipCapV atomic.Value // *cachedTipCap - stop func() + host string + endpointAddr string + ec *combinedRPCClient + ws bool + net dex.Network + tipCapV atomic.Value // *cachedTipCap + stop func() // tip tracks the best known header as well as any error encountered tip struct { @@ -395,8 +396,8 @@ func newMultiRPCClient(dir string, endpoints []string, log dex.Logger, cfg *para // connectProviders attempts to connect to the list of endpoints, returning a // list of providers that were successfully connected. It is not an error for a -// connection to fail. The caller can infer failed connections from the length -// and contents of the returned provider list. +// connection to fail, unless all endpoints fail. The caller can infer failed +// connections from the length and contents of the returned provider list. func connectProviders(ctx context.Context, endpoints []string, log dex.Logger, chainID *big.Int, net dex.Network) ([]*provider, error) { providers := make([]*provider, 0, len(endpoints)) var success bool @@ -409,12 +410,12 @@ func connectProviders(ctx context.Context, endpoints []string, log dex.Logger, c } }() - // addEnpoint only returns errors that should be propagated immediately. + // addEndpoint only returns errors that should be propagated immediately. addEndpoint := func(endpoint string) error { // Give ourselves a limited time to resolve a connection. timedCtx, cancel := context.WithTimeout(ctx, defaultRequestTimeout) defer cancel() - // First try to get a websocket connection. Websockets have a header + // First try to get a websocket connection. WebSockets have a header // feed, so are much preferred to http connections. So much so, that // we'll do some path inspection here and make an attempt to find a // websocket server, even if the user requested http. @@ -510,9 +511,10 @@ func connectProviders(ctx context.Context, endpoints []string, log dex.Logger, c } p := &provider{ - host: host, - ws: sub != nil, - net: net, + host: host, + endpointAddr: endpoint, + ws: sub != nil, + net: net, ec: &combinedRPCClient{ Client: ec, rpc: rpcClient, @@ -634,12 +636,93 @@ func (m *multiRPCClient) voidUnusedNonce() { m.lastNonce.stamp = time.Time{} } -func (m *multiRPCClient) reconfigure(ctx context.Context, settings map[string]string) error { +// createAndCheckProviders creates and connects to providers. It checks that +// unknown providers have a sufficient api to trade and saves good providers to +// file. One bad provider or connect problem will cause this to error. +func createAndCheckProviders(ctx context.Context, walletDir string, endpoints []string, net dex.Network, + log dex.Logger) error { + var localCP map[string]bool + path := filepath.Join(walletDir, "compliant-providers.json") + b, err := os.ReadFile(path) + if err == nil { + if err := json.Unmarshal(b, &localCP); err != nil { + log.Warnf("Couldn't parse compliant providers file: %v", err) + } + } else if !errors.Is(err, os.ErrNotExist) { + log.Warnf("Error reading providers file: %v", err) + } + if localCP == nil { + localCP = make(map[string]bool) + } + + var writeLocalCP bool + + var unknownEndpoints []string + for _, p := range endpoints { + d := domain(p) + if localCP[d] { + continue + } + writeLocalCP = true + localCP[d] = true + if _, known := compliantProviders[d]; !known { + unknownEndpoints = append(unknownEndpoints, p) + } + } + + if len(unknownEndpoints) > 0 { + providersErr := func(providers []*provider) error { + // Remove connected providers from the unknown endpoints for + // printing. + for i := len(unknownEndpoints) - 1; i >= 0; i-- { + for _, p := range providers { + if p.endpointAddr == unknownEndpoints[i] { + unknownEndpoints = append(unknownEndpoints[:i], unknownEndpoints[i+1:]...) + break + } + } + } + return fmt.Errorf("could not connect to the following providers: %v", strings.Join(unknownEndpoints, " ")) + } + + providers, err := connectProviders(ctx, unknownEndpoints, log, big.NewInt(chainIDs[net]), net) + if err != nil { + return fmt.Errorf("%v: %v", providersErr(providers), err) + } + defer func() { + for _, p := range providers { + p.shutdown() + } + }() + if len(providers) != len(unknownEndpoints) { + return providersErr(providers) + } + if err := checkProvidersCompliance(ctx, providers, net, log); err != nil { + return err + } + } + if writeLocalCP { + // All unknown providers were checked. + b, err := json.Marshal(localCP) + if err != nil { + return err + } + if err := os.WriteFile(path, b, 0644); err != nil { + log.Errorf("Failed to write compliant providers file: %v", err) + } + } + return nil +} + +func (m *multiRPCClient) reconfigure(ctx context.Context, settings map[string]string, walletDir string) error { providerDef := settings[providersKey] if len(providerDef) == 0 { return errors.New("no providers specified") } endpoints := strings.Split(providerDef, " ") + if err := createAndCheckProviders(ctx, walletDir, endpoints, m.net, m.log); err != nil { + return fmt.Errorf("create and check providers problem: %v", err) + } providers, err := connectProviders(ctx, endpoints, m.log, m.chainID, m.net) if err != nil { return err @@ -1294,7 +1377,7 @@ const ( providerBlast = "blastapi.io" // Non-compliant providers - providerCloudflareETH = "cloudflare-eth.com" // "SuggestGasTipCap" error: Method not found + // providerCloudflareETH = "cloudflare-eth.com" // "SuggestGasTipCap" error: Method not found ) var compliantProviders = map[string]struct{}{ @@ -1310,19 +1393,6 @@ var compliantProviders = map[string]struct{}{ providerBlast: {}, } -var nonCompliantProviders = map[string]struct{}{ - providerCloudflareETH: {}, -} - -func providerIsCompliant(addr string) (known, compliant bool) { - addr = domain(addr) - if _, known = compliantProviders[addr]; known { - return true, true - } - _, known = nonCompliantProviders[addr] - return known, false -} - type rpcTest struct { name string f func(context.Context, *provider) error @@ -1330,17 +1400,57 @@ type rpcTest struct { // newCompatibilityTests returns a list of RPC tests to run to determine API // compatibility. -func newCompatibilityTests(cb bind.ContractBackend, log slog.Logger) []*rpcTest { +func newCompatibilityTests(cb bind.ContractBackend, net dex.Network, log slog.Logger) []*rpcTest { var ( // Vitalik's address from https://twitter.com/VitalikButerin/status/1050126908589887488 mainnetAddr = common.HexToAddress("0xab5801a7d398351b8be11c439e05c5b3259aec9b") mainnetUSDC = common.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48") mainnetTxHash = common.HexToHash("0xea1a717af9fad5702f189d6f760bb9a5d6861b4ee915976fe7732c0c95cd8a0e") mainnetBlockHash = common.HexToHash("0x44ebd6f66b4fd546bccdd700869f6a433ef9a47e296a594fa474228f86eeb353") + + testnetAddr = common.HexToAddress("0x8879F72728C5eaf5fB3C55e6C3245e97601FBa32") + testnetUSDC = common.HexToAddress("0x07865c6E87B9F70255377e024ace6630C1Eaa37F") + testnetTxHash = common.HexToHash("0x4e1d455f7eac7e3a5f7c1e0989b637002755eaee3a262f90b0f3aef1f1c4dcf0") + testnetBlockHash = common.HexToHash("0x8896021c2666303a85b7e4a6a6f2b075bc705d4e793bf374cd44b83bca23ef9a") + + simnetAddr = common.HexToAddress("18d65fb8d60c1199bb1ad381be47aa692b482605") + addr, usdc common.Address + txHash, blockHash common.Hash ) - if log == nil { // Logging detail is for testing. - log = slog.Disabled + + switch net { + case dex.Mainnet: + addr = mainnetAddr + usdc = mainnetUSDC + txHash = mainnetTxHash + blockHash = mainnetBlockHash + case dex.Testnet: + addr = testnetAddr + usdc = testnetUSDC + txHash = testnetTxHash + blockHash = testnetBlockHash + case dex.Simnet: + addr = simnetAddr + var ( + tDir = filepath.Join(os.Getenv("HOME"), "dextest", "eth") + tTxHashFile = filepath.Join(tDir, "test_tx_hash.txt") + tBlockHashFile = filepath.Join(tDir, "test_block10_hash.txt") + tContractFile = filepath.Join(tDir, "test_token_contract_address.txt") + ) + readIt := func(path string) string { + b, err := os.ReadFile(path) + if err != nil { + log.Errorf("Problem reading simnet testing file: %v", err) + } + return strings.TrimRight(string(b), "\r\n") + } + usdc = common.HexToAddress(readIt(tContractFile)) + txHash = common.HexToHash(readIt(tTxHashFile)) + blockHash = common.HexToHash(readIt(tBlockHashFile)) + default: + log.Errorf("Unknown net %v in compatibility tests. Testing data not initiated.", net) } + return []*rpcTest{ { name: "HeaderByNumber", @@ -1352,21 +1462,21 @@ func newCompatibilityTests(cb bind.ContractBackend, log slog.Logger) []*rpcTest { name: "HeaderByHash", f: func(ctx context.Context, p *provider) error { - _, err := p.ec.HeaderByHash(ctx, mainnetBlockHash) + _, err := p.ec.HeaderByHash(ctx, blockHash) return err }, }, { name: "TransactionReceipt", f: func(ctx context.Context, p *provider) error { - _, err := p.ec.TransactionReceipt(ctx, mainnetTxHash) + _, err := p.ec.TransactionReceipt(ctx, txHash) return err }, }, { name: "PendingNonceAt", f: func(ctx context.Context, p *provider) error { - _, err := p.ec.PendingNonceAt(ctx, mainnetAddr) + _, err := p.ec.PendingNonceAt(ctx, addr) return err }, }, @@ -1384,18 +1494,18 @@ func newCompatibilityTests(cb bind.ContractBackend, log slog.Logger) []*rpcTest { name: "BalanceAt", f: func(ctx context.Context, p *provider) error { - bal, err := p.ec.BalanceAt(ctx, mainnetAddr, nil) + bal, err := p.ec.BalanceAt(ctx, addr, nil) if err != nil { return err } - log.Infof("#### Vitalik's balance retrieved: %.9f", float64(dexeth.WeiToGwei(bal))/1e9) + log.Infof("#### Balance retrieved: %.9f", float64(dexeth.WeiToGwei(bal))/1e9) return nil }, }, { name: "CodeAt", f: func(ctx context.Context, p *provider) error { - code, err := p.ec.CodeAt(ctx, mainnetUSDC, nil) + code, err := p.ec.CodeAt(ctx, usdc, nil) if err != nil { return err } @@ -1406,14 +1516,14 @@ func newCompatibilityTests(cb bind.ContractBackend, log slog.Logger) []*rpcTest { name: "CallContract(balanceOf)", f: func(ctx context.Context, p *provider) error { - caller, err := erc20.NewIERC20(mainnetUSDC, cb) + caller, err := erc20.NewIERC20(usdc, cb) if err != nil { return err } bal, err := caller.BalanceOf(&bind.CallOpts{ - From: mainnetAddr, + From: addr, Context: ctx, - }, mainnetAddr) + }, addr) if err != nil { return err } @@ -1438,7 +1548,7 @@ func newCompatibilityTests(cb bind.ContractBackend, log slog.Logger) []*rpcTest { name: "PendingNonceAt", f: func(ctx context.Context, p *provider) error { - n, err := p.ec.PendingNonceAt(ctx, mainnetAddr) + n, err := p.ec.PendingNonceAt(ctx, addr) if err != nil { return err } @@ -1449,7 +1559,7 @@ func newCompatibilityTests(cb bind.ContractBackend, log slog.Logger) []*rpcTest { name: "getRPCTransaction", f: func(ctx context.Context, p *provider) error { - rpcTx, err := getRPCTransaction(ctx, p, mainnetTxHash) + rpcTx, err := getRPCTransaction(ctx, p, txHash) if err != nil { return err } @@ -1473,49 +1583,22 @@ func domain(host string) string { return parts[n-2] + "." + parts[n-1] } -// checkProvidersCompliance verifies that a provider supports the API that DEX +// checkProvidersCompliance verifies that providers support the API that DEX // requires by sending a series of requests and verifying the responses. If a // provider is found to be compliant, their domain name is added to a list and -// stored in a file on disk, so that future checks can be short-circuited. -func checkProvidersCompliance(ctx context.Context, walletDir string, providers []*provider, log dex.Logger) error { - var compliantProviders map[string]bool - path := filepath.Join(walletDir, "compliant-providers.json") - b, err := os.ReadFile(path) - if err == nil { - if err := json.Unmarshal(b, &compliantProviders); err != nil { - log.Warn("Couldn't parse compliant providers file") - } - } - if compliantProviders == nil { - compliantProviders = make(map[string]bool) - } - - n := len(compliantProviders) - +// stored in a file on disk so that future checks can be short-circuited. +func checkProvidersCompliance(ctx context.Context, providers []*provider, net dex.Network, log slog.Logger) error { for _, p := range providers { - if compliantProviders[domain(p.host)] { - continue - } - - if known, _ := providerIsCompliant(p.host); !known { - // Need to run API tests on this endpoint. - for _, t := range newCompatibilityTests(p.ec, nil /* logger is for testing only */) { - if err := t.f(ctx, p); err != nil { - log.Errorf("RPC Provider @ %q has a non-compliant API: %v", err) - return fmt.Errorf("RPC Provider @ %q has a non-compliant API", p.host) - } + // Need to run API tests on this endpoint. + for _, t := range newCompatibilityTests(p.ec, net, log) { + ctx, cancel := context.WithTimeout(ctx, defaultRequestTimeout) + err := t.f(ctx, p) + cancel() + if err != nil { + return fmt.Errorf("RPC Provider @ %q has a non-compliant API: %v", p.host, err) } - compliantProviders[domain(p.host)] = true } } - - if len(compliantProviders) != n { - b, _ /* c'mon */ := json.Marshal(compliantProviders) - if err := os.WriteFile(path, b, 0644); err != nil { - log.Errorf("Failed to write compliant providers file: %v", err) - } - } - return nil } diff --git a/client/asset/eth/multirpc_live_test.go b/client/asset/eth/multirpc_live_test.go index fcfeb16b35..f72e1f6768 100644 --- a/client/asset/eth/multirpc_live_test.go +++ b/client/asset/eth/multirpc_live_test.go @@ -267,7 +267,7 @@ func TestRPC(t *testing.T) { t.Fatalf("connect error: %v", err) } - for _, tt := range newCompatibilityTests(cl, cl.log) { + for _, tt := range newCompatibilityTests(cl, dex.Mainnet, cl.log) { tStart := time.Now() if err := cl.withAny(ctx, tt.f); err != nil { t.Fatalf("%q: %v", tt.name, err) @@ -297,15 +297,13 @@ func TestFreeServers(t *testing.T) { if err := cl.connect(ctx); err != nil { return fmt.Errorf("connect error: %v", err) } - return cl.withAny(ctx, func(ctx context.Context, p *provider) error { - for _, tt := range newCompatibilityTests(cl, cl.log) { - if err := tt.f(ctx, p); err != nil { - return fmt.Errorf("%q error: %v", tt.name, err) - } - fmt.Printf("#### %q passed %q \n", endpoint, tt.name) + for _, tt := range newCompatibilityTests(cl, dex.Mainnet, cl.log) { + if err := cl.withAny(ctx, tt.f); err != nil { + return fmt.Errorf("%q error: %v", tt.name, err) } - return nil - }) + fmt.Printf("#### %q passed %q \n", endpoint, tt.name) + } + return nil } passes, fails := make([]string, 0), make(map[string]error, 0) @@ -326,20 +324,26 @@ func TestFreeServers(t *testing.T) { func TestMainnetCompliance(t *testing.T) { providerFile := readProviderFile(t, dex.Mainnet) - dir, _ := os.MkdirTemp("", "") + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() log := dex.StdOutLogger("T", dex.LevelTrace) providers, err := connectProviders(ctx, providerFile.Providers, log, big.NewInt(chainIDs[dex.Mainnet]), dex.Mainnet) if err != nil { t.Fatal(err) } - err = checkProvidersCompliance(ctx, dir, providers, log) + err = checkProvidersCompliance(ctx, providers, dex.Mainnet, log) if err != nil { t.Fatal(err) } } func tRPCClient(dir string, seed []byte, endpoints []string, net dex.Network, skipConnect bool) (*multiRPCClient, error) { + wDir := getWalletDir(dir, net) + err := os.MkdirAll(wDir, 0755) + if err != nil { + return nil, fmt.Errorf("os.Mkdir error: %w", err) + } log := dex.StdOutLogger("T", dex.LevelTrace) if err := createWallet(&asset.CreateWalletParams{ Type: walletTypeRPC, diff --git a/client/cmd/dexcctl/simnet-setup.sh b/client/cmd/dexcctl/simnet-setup.sh index 88bada74fe..3dea0ca851 100755 --- a/client/cmd/dexcctl/simnet-setup.sh +++ b/client/cmd/dexcctl/simnet-setup.sh @@ -48,7 +48,8 @@ fi if [ $ETH_ON -eq 0 ]; then echo configuring Eth and dextt.eth wallets - ./dexcctl -p abc -p "" --simnet newwallet 60 rpc "" "{\"providers\":\"${HOME}/dextest/eth/alpha/node/geth.ipc\"}" + # Connecting to the simnet beta node over WebSocket. + ./dexcctl -p abc -p "" --simnet newwallet 60 rpc "" "{\"providers\":\"ws://localhost:38559\"}" ./dexcctl -p abc -p "" --simnet newwallet 60000 rpc fi diff --git a/dex/testing/eth/create-node.sh b/dex/testing/eth/create-node.sh index ee2857e908..209166b820 100755 --- a/dex/testing/eth/create-node.sh +++ b/dex/testing/eth/create-node.sh @@ -15,6 +15,9 @@ ADDRESS_JSON_FILE_NAME=$9 NODE_KEY=${10} SYNC_MODE=${11} AUTHRPC_PORT=${12} +HTTP_PORT=${13} +WS_PORT=${14} +WS_MODULES=${15} GROUP_DIR="${NODES_ROOT}/${NAME}" MINE_JS="${GROUP_DIR}/mine.js" @@ -30,11 +33,6 @@ geth --datadir="${NODE_DIR}" \$* EOF chmod +x "${NODES_ROOT}/harness-ctl/${NAME}" -HTTP_OPT="" -if [ "$NAME" = "delta" ]; then - HTTP_OPT="--http --http.port ${DELTA_HTTP_PORT} --ws --ws.port ${DELTA_WS_PORT} --ws.api \"db,eth,net,web3,personal,txpool,admin\"" -fi - # Write mine script if CHAIN_ADDRESS is present. if [ "${CHAIN_ADDRESS}" != "_" ]; then # The mining script may end up mining more or less blocks than specified. @@ -137,8 +135,10 @@ if [ "${SYNC_MODE}" = "snap" ]; then tmux send-keys -t "$TMUX_WIN_ID" "${NODES_ROOT}/harness-ctl/${NAME} --nodiscover " \ "--config ${NODE_DIR}/eth.conf --unlock ${CHAIN_ADDRESS} " \ "--password ${GROUP_DIR}/password --light.serve 25 --datadir.ancient " \ - "${NODE_DIR}/geth-ancient --verbosity 5 --vmdebug 2>&1 | tee " \ - "${NODE_DIR}/${NAME}.log" C-m + "${NODE_DIR}/geth-ancient --verbosity 5 --vmdebug --http --http.port " \ + "${HTTP_PORT} --ws --ws.port ${WS_PORT} --ws.api " \ + "${WS_MODULES} --allow-insecure-unlock " \ + "2>&1 | tee ${NODE_DIR}/${NAME}.log" C-m else # Start the eth node listening restricted to localhost and our custom diff --git a/dex/testing/eth/harness.sh b/dex/testing/eth/harness.sh index a8b2229ffd..384f4b57bf 100755 --- a/dex/testing/eth/harness.sh +++ b/dex/testing/eth/harness.sh @@ -20,6 +20,9 @@ ALPHA_NODE_KEY="71d810d39333296b518c846a3e49eca55f998fd7994998bb3e5048567f2f073c ALPHA_ENODE="897c84f6e4f18195413c1d02927e6a4093f5e7574b52bdec6f20844c4f1f6dd3f16036a9e600bd8681ab50fd8dd144df4a6ba9dd8722bb578a86aaa8222c964f" ALPHA_NODE_PORT="30304" ALPHA_AUTHRPC_PORT="8552" +ALPHA_HTTP_PORT="38556" +ALPHA_WS_PORT="38557" +ALPHA_WS_MODULES="eth" # BETA_ADDRESS="4f8ef3892b65ed7fc356ff473a2ef2ae5ec27a06" BETA_ADDRESS_JSON_FILE_NAME="UTC--2021-01-27T08-20-58.179642501Z--4f8ef3892b65ed7fc356ff473a2ef2ae5ec27a06" @@ -28,6 +31,9 @@ BETA_NODE_KEY="0f3f23a0f14202da009bd59a96457098acea901986629e54d5be1eea32fc404a" BETA_ENODE="b1d3e358ee5c9b268e911f2cab47bc12d0e65c80a6d2b453fece34facc9ac3caed14aa3bc7578166bb08c5bc9719e5a2267ae14e0b42da393f4d86f6d5829061" BETA_NODE_PORT="30305" BETA_AUTHRPC_PORT="8553" +BETA_HTTP_PORT="38558" +BETA_WS_PORT="38559" +BETA_WS_MODULES="eth,txpool" GAMMA_ADDRESS="41293c2032bac60aa747374e966f79f575d42379" GAMMA_ADDRESS_JSON_FILE_NAME="UTC--2021-03-01T02-12-42.714340074Z--41293c2032bac60aa747374e966f79f575d42379" @@ -44,8 +50,6 @@ DELTA_NODE_KEY="725394672587b34bbf15580c59e5199c75c2c7e998ba8df3cb38cc4347d46e2b DELTA_ENODE="ca414c361d1a38716170923e4900d9dc9203dbaf8fdcaee73e1f861df9fdf20a1453b76fd218c18bc6f3c7e13cbca0b3416af02a53b8e31188faa45aab398d1c" DELTA_NODE_PORT="30307" DELTA_AUTHRPC_PORT="8555" -export DELTA_HTTP_PORT="38556" -export DELTA_WS_PORT="38557" # TESTING_ADDRESS is used by the client's internal node. TESTING_ADDRESS="b6de8bb5ed28e6be6d671975cad20c03931be981" @@ -264,23 +268,25 @@ echo "Starting simnet alpha node" "${HARNESS_DIR}/create-node.sh" "$SESSION:1" "alpha" "$ALPHA_NODE_PORT" \ "$CHAIN_ADDRESS" "$PASSWORD" "$CHAIN_ADDRESS_JSON" \ "$CHAIN_ADDRESS_JSON_FILE_NAME" "$ALPHA_ADDRESS_JSON" "$ALPHA_ADDRESS_JSON_FILE_NAME" \ - "$ALPHA_NODE_KEY" "snap" "$ALPHA_AUTHRPC_PORT" + "$ALPHA_NODE_KEY" "snap" "$ALPHA_AUTHRPC_PORT" "$ALPHA_HTTP_PORT" "$ALPHA_WS_PORT" \ + "$ALPHA_WS_MODULES" echo "Starting simnet beta node" "${HARNESS_DIR}/create-node.sh" "$SESSION:2" "beta" "$BETA_NODE_PORT" \ "$CHAIN_ADDRESS" "$PASSWORD" "$CHAIN_ADDRESS_JSON" \ "$CHAIN_ADDRESS_JSON_FILE_NAME" "$BETA_ADDRESS_JSON" "$BETA_ADDRESS_JSON_FILE_NAME" \ - "$BETA_NODE_KEY" "snap" "$BETA_AUTHRPC_PORT" + "$BETA_NODE_KEY" "snap" "$BETA_AUTHRPC_PORT" "$BETA_HTTP_PORT" "$BETA_WS_PORT" \ + "$BETA_WS_MODULES" echo "Starting simnet gamma node" "${HARNESS_DIR}/create-node.sh" "$SESSION:3" "gamma" "$GAMMA_NODE_PORT" \ "_" "_" "_" "_" "$GAMMA_ADDRESS_JSON" "$GAMMA_ADDRESS_JSON_FILE_NAME" \ - "$GAMMA_NODE_KEY" "light" "$GAMMA_AUTHRPC_PORT" + "$GAMMA_NODE_KEY" "light" "$GAMMA_AUTHRPC_PORT" "_" "_" "_" echo "Starting simnet delta node" "${HARNESS_DIR}/create-node.sh" "$SESSION:4" "delta" "$DELTA_NODE_PORT" \ "_" "_" "_" "_" "$DELTA_ADDRESS_JSON" "$DELTA_ADDRESS_JSON_FILE_NAME" \ - "$DELTA_NODE_KEY" "light" "$DELTA_AUTHRPC_PORT" + "$DELTA_NODE_KEY" "light" "$DELTA_AUTHRPC_PORT" "_" "_" "_" sleep 1 @@ -305,7 +311,11 @@ SEND_AMT=5000000000000000000000 echo "Sending 5000 eth to delta and gamma and testing." "${NODES_ROOT}/harness-ctl/alpha" "attach --preload ${NODES_ROOT}/harness-ctl/send.js --exec send(\"${ALPHA_ADDRESS}\",\"${GAMMA_ADDRESS}\",${SEND_AMT})" "${NODES_ROOT}/harness-ctl/alpha" "attach --preload ${NODES_ROOT}/harness-ctl/send.js --exec send(\"${ALPHA_ADDRESS}\",\"${DELTA_ADDRESS}\",${SEND_AMT})" -"${NODES_ROOT}/harness-ctl/alpha" "attach --preload ${NODES_ROOT}/harness-ctl/send.js --exec send(\"${ALPHA_ADDRESS}\",\"${TESTING_ADDRESS}\",${SEND_AMT})" +TEST_TX_HASH=$("${NODES_ROOT}/harness-ctl/alpha" "attach --preload ${NODES_ROOT}/harness-ctl/send.js --exec send(\"${ALPHA_ADDRESS}\",\"${TESTING_ADDRESS}\",${SEND_AMT})" | sed 's/"//g') +echo "ETH transaction to use in tests is ${TEST_TX_HASH}. Saving to ${NODES_ROOT}/test_tx_hash.txt" +cat > "${NODES_ROOT}/test_tx_hash.txt" < "${NODES_ROOT}/test_block10_hash.txt" <