From 9b668e05d2726b27b0dd81150747328fdaf67195 Mon Sep 17 00:00:00 2001 From: Matt Curtis Date: Fri, 15 Sep 2023 14:09:19 +0100 Subject: [PATCH 1/2] Changes to support sepolia testing from IDE --- go/ethadapter/geth_rpc_client.go | 4 ++- go/host/enclave/guardian.go | 7 ++--- integration/networktest/env/dev_network.go | 8 ++--- integration/networktest/env/network_setup.go | 5 ++-- integration/networktest/runner.go | 2 +- .../helpful/spin_up_local_network_test.go | 13 ++++---- .../networktest/userwallet/userwallet.go | 2 +- integration/simulation/devnetwork/config.go | 10 +++++-- integration/simulation/devnetwork/live_l1.go | 30 ++++++++++++------- integration/simulation/devnetwork/node.go | 20 +++++-------- integration/simulation/network/geth_utils.go | 5 ++-- 11 files changed, 60 insertions(+), 46 deletions(-) diff --git a/go/ethadapter/geth_rpc_client.go b/go/ethadapter/geth_rpc_client.go index 8e935c2fb8..f48183a285 100644 --- a/go/ethadapter/geth_rpc_client.go +++ b/go/ethadapter/geth_rpc_client.go @@ -268,7 +268,9 @@ func (e *gethRPCClient) ReconnectIfClosed() error { // Alive tests the client func (e *gethRPCClient) Alive() bool { - _, err := e.client.BlockNumber(context.Background()) + ctx, cancel := context.WithTimeout(context.Background(), e.timeout) + defer cancel() + _, err := e.client.BlockNumber(ctx) if err != nil { e.logger.Error("Unable to fetch BlockNumber rpc endpoint - client connection is in error state") return false diff --git a/go/host/enclave/guardian.go b/go/host/enclave/guardian.go index 36c5e2b07b..8deda441fd 100644 --- a/go/host/enclave/guardian.go +++ b/go/host/enclave/guardian.go @@ -248,7 +248,6 @@ func (g *Guardian) provideSecret() error { // instead of requesting a secret, we generate one and broadcast it return g.generateAndBroadcastSecret() } - g.logger.Info("Requesting secret.") att, err := g.enclaveClient.Attestation() if err != nil { return fmt.Errorf("could not retrieve attestation from enclave. Cause: %w", err) @@ -301,7 +300,7 @@ func (g *Guardian) provideSecret() error { } func (g *Guardian) generateAndBroadcastSecret() error { - g.logger.Info("Node is genesis node. Broadcasting secret.") + g.logger.Info("Node is genesis node. Publishing secret to L1 management contract.") // Create the shared secret and submit it to the management contract for storage attestation, err := g.enclaveClient.Attestation() if err != nil { @@ -318,9 +317,9 @@ func (g *Guardian) generateAndBroadcastSecret() error { err = g.sl.L1Publisher().InitializeSecret(attestation, secret) if err != nil { - return errors.Wrap(err, "failed to initialise enclave secret") + return errors.Wrap(err, "failed to publish generated enclave secret") } - g.logger.Info("Node is genesis node. Secret was broadcast.") + g.logger.Info("Node is genesis node. Secret generation was published to L1.") g.state.OnSecretProvided() return nil } diff --git a/integration/networktest/env/dev_network.go b/integration/networktest/env/dev_network.go index ec1603eb6a..c28136c015 100644 --- a/integration/networktest/env/dev_network.go +++ b/integration/networktest/env/dev_network.go @@ -28,12 +28,12 @@ func (d *devNetworkEnv) Prepare() (networktest.NetworkConnector, func(), error) } func awaitNodesAvailable(nc networktest.NetworkConnector) error { - err := awaitHealthStatus(nc.GetSequencerNode().HostRPCAddress(), 30*time.Second) + err := awaitHealthStatus(nc.GetSequencerNode().HostRPCAddress(), 60*time.Second) if err != nil { return err } for i := 0; i < nc.NumValidators(); i++ { - err := awaitHealthStatus(nc.GetValidatorNode(i).HostRPCAddress(), 30*time.Second) + err := awaitHealthStatus(nc.GetValidatorNode(i).HostRPCAddress(), 60*time.Second) if err != nil { return err } @@ -67,6 +67,6 @@ func LocalDevNetwork() networktest.Environment { // LocalNetworkLiveL1 creates a local network that points to a live running L1. // Note: seqWallet and validatorWallets need funds. seqWallet is used to deploy the L1 contracts -func LocalNetworkLiveL1(seqWallet wallet.Wallet, validatorWallets []wallet.Wallet, l1RPCAddress string) networktest.Environment { - return &devNetworkEnv{inMemDevNetwork: devnetwork.LiveL1DevNetwork(seqWallet, validatorWallets, l1RPCAddress)} +func LocalNetworkLiveL1(seqWallet wallet.Wallet, validatorWallets []wallet.Wallet, l1RPCURLs []string) networktest.Environment { + return &devNetworkEnv{inMemDevNetwork: devnetwork.LiveL1DevNetwork(seqWallet, validatorWallets, l1RPCURLs)} } diff --git a/integration/networktest/env/network_setup.go b/integration/networktest/env/network_setup.go index f8ded0279c..05edc6fe77 100644 --- a/integration/networktest/env/network_setup.go +++ b/integration/networktest/env/network_setup.go @@ -25,10 +25,11 @@ func DevTestnet() networktest.Environment { return &testnetEnv{connector} } +// LongRunningLocalNetwork is a local network, the l1WSURL is optional (can be empty string), only required if testing L1 interactions func LongRunningLocalNetwork(l1WSURL string) networktest.Environment { connector := NewTestnetConnectorWithFaucetAccount( - "http://127.0.0.1:37800", - []string{"http://127.0.0.1:37801", "http://127.0.0.1:37802"}, + "ws://127.0.0.1:37900", + []string{"ws://127.0.0.1:37901"}, genesis.TestnetPrefundedPK, l1WSURL, ) diff --git a/integration/networktest/runner.go b/integration/networktest/runner.go index f692e166a7..cb95b718de 100644 --- a/integration/networktest/runner.go +++ b/integration/networktest/runner.go @@ -32,7 +32,7 @@ func Run(testName string, t *testing.T, env Environment, action Action) { if err != nil { t.Fatal(err) } - time.Sleep(2 * time.Second) // allow time for latest test transactions to propagate todo (@matt) consider how to configure this sleep + time.Sleep(20 * time.Second) // allow time for latest test transactions to propagate todo (@matt) make network speeds readable from env to configure this fmt.Println("Verifying test:", testName) err = action.Verify(ctx, network) if err != nil { diff --git a/integration/networktest/tests/helpful/spin_up_local_network_test.go b/integration/networktest/tests/helpful/spin_up_local_network_test.go index 73b1d01f70..7045d08886 100644 --- a/integration/networktest/tests/helpful/spin_up_local_network_test.go +++ b/integration/networktest/tests/helpful/spin_up_local_network_test.go @@ -21,11 +21,12 @@ import ( const ( _sepoliaChainID = 11155111 - // To run Sepolia network: update these details with a websocket RPC address and funded PKs - _sepoliaRPCAddress = "wss://sepolia.infura.io/ws/v3/" + SepoliaRPCAddress1 = "wss://sepolia.infura.io/ws/v3/" // seq + SepoliaRPCAddress2 = "wss://sepolia.infura.io/ws/v3/" // val + SepoliaRPCAddress3 = "wss://sepolia.infura.io/ws/v3/" // tester + _sepoliaSequencerPK = "" // account 0x _sepoliaValidator1PK = "" // account 0x - ) func TestRunLocalNetwork(t *testing.T) { @@ -45,14 +46,14 @@ func TestRunLocalNetworkAgainstSepolia(t *testing.T) { networktest.EnsureTestLogsSetUp("local-sepolia-network") l1DeployerWallet := wallet.NewInMemoryWalletFromConfig(_sepoliaSequencerPK, _sepoliaChainID, testlog.Logger()) - checkBalance("sequencer", l1DeployerWallet, _sepoliaRPCAddress) + checkBalance("sequencer", l1DeployerWallet, SepoliaRPCAddress1) val1Wallet := wallet.NewInMemoryWalletFromConfig(_sepoliaValidator1PK, _sepoliaChainID, testlog.Logger()) - checkBalance("validator1", val1Wallet, _sepoliaRPCAddress) + checkBalance("validator1", val1Wallet, SepoliaRPCAddress2) validatorWallets := []wallet.Wallet{val1Wallet} networktest.EnsureTestLogsSetUp("local-network-live-l1") - networkConnector, cleanUp, err := env.LocalNetworkLiveL1(l1DeployerWallet, validatorWallets, _sepoliaRPCAddress).Prepare() + networkConnector, cleanUp, err := env.LocalNetworkLiveL1(l1DeployerWallet, validatorWallets, []string{SepoliaRPCAddress1, SepoliaRPCAddress2}).Prepare() if err != nil { t.Fatal(err) } diff --git a/integration/networktest/userwallet/userwallet.go b/integration/networktest/userwallet/userwallet.go index 6fa1213243..8f86323e6a 100644 --- a/integration/networktest/userwallet/userwallet.go +++ b/integration/networktest/userwallet/userwallet.go @@ -24,7 +24,7 @@ import ( const ( _maxReceiptWaitTime = 30 * time.Second - _receiptPollInterval = 1 * time.Second + _receiptPollInterval = 1 * time.Second // todo (@matt) this should be configured using network timings provided by env ) // UserWallet implements wallet.Wallet so it can be used with the original Wallet code. diff --git a/integration/simulation/devnetwork/config.go b/integration/simulation/devnetwork/config.go index cee4cc09b4..dd62e511d2 100644 --- a/integration/simulation/devnetwork/config.go +++ b/integration/simulation/devnetwork/config.go @@ -1,6 +1,7 @@ package devnetwork import ( + "github.com/ethereum/go-ethereum/common" "math/big" "sync" "time" @@ -30,6 +31,7 @@ type ObscuroConfig struct { BatchInterval time.Duration RollupInterval time.Duration L1BlockTime time.Duration + SequencerID common.Address } // DefaultDevNetwork provides an off-the-shelf default config for a sim network @@ -52,12 +54,15 @@ func DefaultDevNetwork() *InMemDevNetwork { BatchInterval: 1 * time.Second, RollupInterval: 10 * time.Second, L1BlockTime: 15 * time.Second, + SequencerID: networkWallets.NodeWallets[0].Address(), }, faucetLock: sync.Mutex{}, } } -func LiveL1DevNetwork(seqWallet wallet.Wallet, validatorWallets []wallet.Wallet, rpcAddress string) *InMemDevNetwork { +// LiveL1DevNetwork provides a local obscuro network running on a live L1 +// Caller should provide a wallet per node and ideally an RPC URL per node (may not be necessary but can avoid conflicts, e.g. Infura seems to require an API key per connection) +func LiveL1DevNetwork(seqWallet wallet.Wallet, validatorWallets []wallet.Wallet, rpcURLs []string) *InMemDevNetwork { // setup the host and deployer wallets to be the prefunded wallets // create the L2 faucet wallet @@ -77,7 +82,7 @@ func LiveL1DevNetwork(seqWallet wallet.Wallet, validatorWallets []wallet.Wallet, deployWallet: seqWallet, // use the same wallet for deploying the contracts seqWallet: seqWallet, validatorWallets: validatorWallets, - rpcAddress: rpcAddress, + rpcURLs: rpcURLs, } return &InMemDevNetwork{ @@ -90,6 +95,7 @@ func LiveL1DevNetwork(seqWallet wallet.Wallet, validatorWallets []wallet.Wallet, BatchInterval: 5 * time.Second, RollupInterval: 3 * time.Minute, L1BlockTime: 15 * time.Second, + SequencerID: seqWallet.Address(), }, } } diff --git a/integration/simulation/devnetwork/live_l1.go b/integration/simulation/devnetwork/live_l1.go index 6e3ca03367..33f3e89122 100644 --- a/integration/simulation/devnetwork/live_l1.go +++ b/integration/simulation/devnetwork/live_l1.go @@ -12,9 +12,9 @@ import ( type liveL1Network struct { deployWallet wallet.Wallet // wallet that can deploy to the live L1 network - rpcAddress string + rpcURLs []string - client ethadapter.EthClient + clients []ethadapter.EthClient seqWallet wallet.Wallet validatorWallets []wallet.Wallet } @@ -22,20 +22,17 @@ type liveL1Network struct { func (l *liveL1Network) Prepare() { // nothing to do really, sanity check the L1 connection logger := testlog.Logger() - client, err := ethadapter.NewEthClientFromURL(l.rpcAddress, 20*time.Second, common.HexToAddress("0x0"), logger) - if err != nil { - panic("unable to create live L1 eth client, err=" + err.Error()) - } - l.client = client + l.prepareClients() + client := l.GetClient(0) blockNum, err := client.BlockNumber() if err != nil { panic(fmt.Sprintf("unable to fetch head block number for live L1 network, rpc=%s err=%s", - l.rpcAddress, err)) + l.rpcURLs[0], err)) } fmt.Println("Connected to L1 successfully", "currHeight", blockNum) logger.Info("Connected to L1 successfully", "currHeight", blockNum) - nonce, err := l.client.Nonce(l.deployWallet.Address()) + nonce, err := client.Nonce(l.deployWallet.Address()) if err != nil { panic(err) } @@ -50,6 +47,17 @@ func (l *liveL1Network) NumNodes() int { return 1 } -func (l *liveL1Network) GetClient(_ int) ethadapter.EthClient { - return l.client +func (l *liveL1Network) GetClient(i int) ethadapter.EthClient { + return l.clients[i%len(l.clients)] +} + +func (l *liveL1Network) prepareClients() { + l.clients = make([]ethadapter.EthClient, len(l.rpcURLs)) + for i, addr := range l.rpcURLs { + client, err := ethadapter.NewEthClientFromURL(addr, 20*time.Second, common.HexToAddress("0x0"), testlog.Logger()) + if err != nil { + panic(fmt.Sprintf("unable to create live L1 eth client, addr=%s err=%s", addr, err)) + } + l.clients[i] = client + } } diff --git a/integration/simulation/devnetwork/node.go b/integration/simulation/devnetwork/node.go index 5230023e1f..3a42bee64a 100644 --- a/integration/simulation/devnetwork/node.go +++ b/integration/simulation/devnetwork/node.go @@ -2,6 +2,7 @@ package devnetwork import ( "fmt" + gethcommon "github.com/ethereum/go-ethereum/common" "math/big" "os" @@ -13,7 +14,6 @@ import ( "github.com/obscuronet/go-obscuro/go/ethadapter/mgmtcontractlib" - gethcommon "github.com/ethereum/go-ethereum/common" gethlog "github.com/ethereum/go-ethereum/log" "github.com/obscuronet/go-obscuro/go/common" "github.com/obscuronet/go-obscuro/go/common/log" @@ -106,7 +106,7 @@ func (n *InMemNodeOperator) createHostContainer() *hostcontainer.HostContainer { p2pAddr := fmt.Sprintf("%s:%d", network.Localhost, p2pPort) hostConfig := &config.HostConfig{ - ID: getHostID(n.operatorIdx), + ID: n.l1Wallet.Address(), IsGenesis: n.nodeType == common.Sequencer, NodeType: n.nodeType, HasClientRPCHTTP: true, @@ -124,7 +124,7 @@ func (n *InMemNodeOperator) createHostContainer() *hostcontainer.HostContainer { L1ChainID: integration.EthereumChainID, ObscuroChainID: integration.ObscuroChainID, L1StartHash: n.l1Data.ObscuroStartBlock, - SequencerID: getHostID(0), + SequencerID: n.config.SequencerID, UseInMemoryDB: false, LevelDBPath: n.hostDBFilepath, DebugNamespaceEnabled: true, @@ -133,7 +133,7 @@ func (n *InMemNodeOperator) createHostContainer() *hostcontainer.HostContainer { L1BlockTime: n.config.L1BlockTime, } - hostLogger := testlog.Logger().New(log.NodeIDKey, n.operatorIdx, log.CmpKey, log.HostCmp) + hostLogger := testlog.Logger().New(log.NodeIDKey, n.l1Wallet.Address(), log.CmpKey, log.HostCmp) // create a socket P2P layer p2pLogger := hostLogger.New(log.CmpKey, log.P2PCmp) @@ -141,7 +141,7 @@ func (n *InMemNodeOperator) createHostContainer() *hostcontainer.HostContainer { nodeP2p := p2p.NewSocketP2PLayer(hostConfig, svcLocator, p2pLogger, nil) // create an enclave client - enclaveClient := enclaverpc.NewClient(hostConfig, testlog.Logger().New(log.NodeIDKey, n.operatorIdx)) + enclaveClient := enclaverpc.NewClient(hostConfig, testlog.Logger().New(log.NodeIDKey, n.l1Wallet.Address())) rpcServer := clientrpc.NewServer(hostConfig, n.logger) mgmtContractLib := mgmtcontractlib.NewMgmtContractLib(&hostConfig.ManagementContractAddress, n.logger) l1Repo := l1.NewL1Repository(n.l1Client, []gethcommon.Address{hostConfig.ManagementContractAddress, hostConfig.MessageBusAddress}, n.logger) @@ -149,7 +149,7 @@ func (n *InMemNodeOperator) createHostContainer() *hostcontainer.HostContainer { } func (n *InMemNodeOperator) createEnclaveContainer() *enclavecontainer.EnclaveContainer { - enclaveLogger := testlog.Logger().New(log.NodeIDKey, n.operatorIdx, log.CmpKey, log.EnclaveCmp) + enclaveLogger := testlog.Logger().New(log.NodeIDKey, n.l1Wallet.Address(), log.CmpKey, log.EnclaveCmp) enclavePort := n.config.PortStart + integration.DefaultEnclaveOffset + n.operatorIdx enclaveAddr := fmt.Sprintf("%s:%d", network.Localhost, enclavePort) @@ -157,8 +157,8 @@ func (n *InMemNodeOperator) createEnclaveContainer() *enclavecontainer.EnclaveCo hostAddr := fmt.Sprintf("%s:%d", network.Localhost, hostPort) enclaveConfig := &config.EnclaveConfig{ - HostID: getHostID(n.operatorIdx), - SequencerID: getHostID(0), + HostID: n.l1Wallet.Address(), + SequencerID: n.config.SequencerID, HostAddress: hostAddr, Address: enclaveAddr, NodeType: n.nodeType, @@ -241,7 +241,3 @@ func NewInMemNodeOperator(operatorIdx int, config ObscuroConfig, nodeType common hostDBFilepath: levelDBPath, } } - -func getHostID(nodeIdx int) gethcommon.Address { - return gethcommon.BigToAddress(big.NewInt(int64(nodeIdx))) -} diff --git a/integration/simulation/network/geth_utils.go b/integration/simulation/network/geth_utils.go index 7a85a319cf..c82f62906b 100644 --- a/integration/simulation/network/geth_utils.go +++ b/integration/simulation/network/geth_utils.go @@ -181,6 +181,7 @@ func DeployContract(workerClient ethadapter.EthClient, w wallet.Wallet, contract var start time.Time var receipt *types.Receipt + // todo (@matt) these timings should be driven by the L2 batch times and L1 block times for start = time.Now(); time.Since(start) < 80*time.Second; time.Sleep(2 * time.Second) { receipt, err = workerClient.TransactionReceipt(signedTx.Hash()) if err == nil && receipt != nil { @@ -191,10 +192,10 @@ func DeployContract(workerClient ethadapter.EthClient, w wallet.Wallet, contract return receipt, nil } - testlog.Logger().Info(fmt.Sprintf("Contract deploy tx has not been mined into a block after %s...", time.Since(start))) + testlog.Logger().Info(fmt.Sprintf("Contract deploy tx (%s) has not been mined into a block after %s...", signedTx.Hash(), time.Since(start))) } - return nil, fmt.Errorf("failed to mine contract deploy tx into a block after %s. Aborting", time.Since(start)) + return nil, fmt.Errorf("failed to mine contract deploy tx (%s) into a block after %s. Aborting", signedTx.Hash(), time.Since(start)) } func CreateEthClientConnection(id int64, port uint) ethadapter.EthClient { From 900be22e8f817f12744ddc9693c732e3eb402eea Mon Sep 17 00:00:00 2001 From: Matt Curtis Date: Fri, 15 Sep 2023 14:16:46 +0100 Subject: [PATCH 2/2] lint --- integration/simulation/devnetwork/config.go | 3 ++- integration/simulation/devnetwork/node.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/integration/simulation/devnetwork/config.go b/integration/simulation/devnetwork/config.go index dd62e511d2..ec72cbc8ac 100644 --- a/integration/simulation/devnetwork/config.go +++ b/integration/simulation/devnetwork/config.go @@ -1,11 +1,12 @@ package devnetwork import ( - "github.com/ethereum/go-ethereum/common" "math/big" "sync" "time" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/obscuronet/go-obscuro/go/enclave/genesis" "github.com/obscuronet/go-obscuro/go/wallet" diff --git a/integration/simulation/devnetwork/node.go b/integration/simulation/devnetwork/node.go index 3a42bee64a..7c3322367c 100644 --- a/integration/simulation/devnetwork/node.go +++ b/integration/simulation/devnetwork/node.go @@ -2,10 +2,11 @@ package devnetwork import ( "fmt" - gethcommon "github.com/ethereum/go-ethereum/common" "math/big" "os" + gethcommon "github.com/ethereum/go-ethereum/common" + "github.com/obscuronet/go-obscuro/go/host/l1" "github.com/obscuronet/go-obscuro/go/host"