diff --git a/go/ethadapter/erc20contractlib/erc20_contract_lib.go b/go/ethadapter/erc20contractlib/erc20_contract_lib.go index 20e25ef782..c23f3e27d7 100644 --- a/go/ethadapter/erc20contractlib/erc20_contract_lib.go +++ b/go/ethadapter/erc20contractlib/erc20_contract_lib.go @@ -20,7 +20,7 @@ type ERC20ContractLib interface { DecodeTx(tx *types.Transaction) ethadapter.L1Transaction // CreateDepositTx receives an common.L1Transaction and converts it to an eth transaction - CreateDepositTx(tx *ethadapter.L1DepositTx, nonce uint64) types.TxData + CreateDepositTx(tx *ethadapter.L1DepositTx) types.TxData } // erc20ContractLibImpl takes a mgmtContractAddr and processes multiple erc20ContractAddrs @@ -44,16 +44,15 @@ func NewERC20ContractLib(mgmtContractAddr *gethcommon.Address, contractAddrs ... } } -func (c *erc20ContractLibImpl) CreateDepositTx(tx *ethadapter.L1DepositTx, nonce uint64) types.TxData { +func (c *erc20ContractLibImpl) CreateDepositTx(tx *ethadapter.L1DepositTx) types.TxData { data, err := c.contractABI.Pack("transfer", &tx.To, tx.Amount) if err != nil { panic(err) } return &types.LegacyTx{ - Nonce: nonce, - To: tx.TokenContract, - Data: data, + To: tx.TokenContract, + Data: data, } } diff --git a/go/ethadapter/geth_rpc_client.go b/go/ethadapter/geth_rpc_client.go index 40858acdd7..8e935c2fb8 100644 --- a/go/ethadapter/geth_rpc_client.go +++ b/go/ethadapter/geth_rpc_client.go @@ -222,8 +222,8 @@ func (e *gethRPCClient) FetchLastBatchSeqNo(address gethcommon.Address) (*big.In return contract.LastBatchSeqNo(&bind.CallOpts{}) } -// EstimateGasAndGasPrice takes a txData type and overrides the Gas and Gas Price field with estimated values -func (e *gethRPCClient) EstimateGasAndGasPrice(txData types.TxData, from gethcommon.Address) (types.TxData, error) { +// PrepareTransactionToSend takes a txData type and overrides the From, Nonce, Gas and Gas Price field with current values +func (e *gethRPCClient) PrepareTransactionToSend(txData types.TxData, from gethcommon.Address, nonce uint64) (types.TxData, error) { unEstimatedTx := types.NewTx(txData) gasPrice, err := e.EthClient().SuggestGasPrice(context.Background()) if err != nil { @@ -241,7 +241,7 @@ func (e *gethRPCClient) EstimateGasAndGasPrice(txData types.TxData, from gethcom } return &types.LegacyTx{ - Nonce: unEstimatedTx.Nonce(), + Nonce: nonce, GasPrice: gasPrice, Gas: gasLimit, To: unEstimatedTx.To(), diff --git a/go/ethadapter/interface.go b/go/ethadapter/interface.go index 8e8a5690bb..fefb8298d2 100644 --- a/go/ethadapter/interface.go +++ b/go/ethadapter/interface.go @@ -36,7 +36,8 @@ type EthClient interface { CallContract(msg ethereum.CallMsg) ([]byte, error) // Runs the provided call message on the latest block. - EstimateGasAndGasPrice(txData types.TxData, from gethcommon.Address) (types.TxData, error) // Estimates the gas and the gas price for a given tx payload + // PrepareTransactionToSend updates the tx with from address, current nonce and current estimates for the gas and the gas price + PrepareTransactionToSend(txData types.TxData, from gethcommon.Address, nonce uint64) (types.TxData, error) FetchLastBatchSeqNo(address gethcommon.Address) (*big.Int, error) diff --git a/go/ethadapter/mgmtcontractlib/mgmt_contract_lib.go b/go/ethadapter/mgmtcontractlib/mgmt_contract_lib.go index 5433b6a395..63fd2f18b3 100644 --- a/go/ethadapter/mgmtcontractlib/mgmt_contract_lib.go +++ b/go/ethadapter/mgmtcontractlib/mgmt_contract_lib.go @@ -24,10 +24,10 @@ const methodBytesLen = 4 // MgmtContractLib provides methods for creating ethereum transactions by providing an L1Transaction, creating call // messages for call requests, and converting ethereum transactions into L1Transactions. type MgmtContractLib interface { - CreateRollup(t *ethadapter.L1RollupTx, nonce uint64) types.TxData - CreateRequestSecret(tx *ethadapter.L1RequestSecretTx, nonce uint64) types.TxData - CreateRespondSecret(tx *ethadapter.L1RespondSecretTx, nonce uint64, verifyAttester bool) types.TxData - CreateInitializeSecret(tx *ethadapter.L1InitializeSecretTx, nonce uint64) types.TxData + CreateRollup(t *ethadapter.L1RollupTx) types.TxData + CreateRequestSecret(tx *ethadapter.L1RequestSecretTx) types.TxData + CreateRespondSecret(tx *ethadapter.L1RespondSecretTx, verifyAttester bool) types.TxData + CreateInitializeSecret(tx *ethadapter.L1InitializeSecretTx) types.TxData GetHostAddresses() (ethereum.CallMsg, error) // DecodeTx receives a *types.Transaction and converts it to an common.L1Transaction @@ -98,7 +98,7 @@ func (c *contractLibImpl) DecodeTx(tx *types.Transaction) ethadapter.L1Transacti return nil } -func (c *contractLibImpl) CreateRollup(t *ethadapter.L1RollupTx, nonce uint64) types.TxData { +func (c *contractLibImpl) CreateRollup(t *ethadapter.L1RollupTx) types.TxData { decodedRollup, err := common.DecodeRollup(t.Rollup) if err != nil { panic(err) @@ -127,26 +127,24 @@ func (c *contractLibImpl) CreateRollup(t *ethadapter.L1RollupTx, nonce uint64) t } return &types.LegacyTx{ - Nonce: nonce, - To: c.addr, - Data: data, + To: c.addr, + Data: data, } } -func (c *contractLibImpl) CreateRequestSecret(tx *ethadapter.L1RequestSecretTx, nonce uint64) types.TxData { +func (c *contractLibImpl) CreateRequestSecret(tx *ethadapter.L1RequestSecretTx) types.TxData { data, err := c.contractABI.Pack(RequestSecretMethod, base64EncodeToString(tx.Attestation)) if err != nil { panic(err) } return &types.LegacyTx{ - Nonce: nonce, - To: c.addr, - Data: data, + To: c.addr, + Data: data, } } -func (c *contractLibImpl) CreateRespondSecret(tx *ethadapter.L1RespondSecretTx, nonce uint64, verifyAttester bool) types.TxData { +func (c *contractLibImpl) CreateRespondSecret(tx *ethadapter.L1RespondSecretTx, verifyAttester bool) types.TxData { data, err := c.contractABI.Pack( RespondSecretMethod, tx.AttesterID, @@ -160,13 +158,12 @@ func (c *contractLibImpl) CreateRespondSecret(tx *ethadapter.L1RespondSecretTx, panic(err) } return &types.LegacyTx{ - Nonce: nonce, - To: c.addr, - Data: data, + To: c.addr, + Data: data, } } -func (c *contractLibImpl) CreateInitializeSecret(tx *ethadapter.L1InitializeSecretTx, nonce uint64) types.TxData { +func (c *contractLibImpl) CreateInitializeSecret(tx *ethadapter.L1InitializeSecretTx) types.TxData { data, err := c.contractABI.Pack( InitializeSecretMethod, tx.AggregatorID, @@ -178,9 +175,8 @@ func (c *contractLibImpl) CreateInitializeSecret(tx *ethadapter.L1InitializeSecr panic(err) } return &types.LegacyTx{ - Nonce: nonce, - To: c.addr, - Data: data, + To: c.addr, + Data: data, } } diff --git a/go/host/host.go b/go/host/host.go index 3edf44a28c..bcb45b39cf 100644 --- a/go/host/host.go +++ b/go/host/host.go @@ -221,4 +221,8 @@ func (h *host) validateConfig() { if h.config.P2PPublicAddress == "" { h.logger.Crit("the host must specify a public P2P address") } + + if h.config.L1BlockTime == 0 { + h.logger.Crit("the host must specify an L1 block time") + } } diff --git a/go/host/l1/publisher.go b/go/host/l1/publisher.go index 1f1b3208a7..e392ccffea 100644 --- a/go/host/l1/publisher.go +++ b/go/host/l1/publisher.go @@ -21,13 +21,6 @@ import ( "github.com/pkg/errors" ) -const ( - // Attempts to broadcast the rollup transaction to the L1. Worst-case, equates to 7 seconds, plus time per request. - l1TxTriesRollup = 3 - // Attempts to send secret initialisation, request or response transactions to the L1. Worst-case, equates to 63 seconds, plus time per request. - l1TxTriesSecret = 7 -) - type Publisher struct { hostData host.Identity hostWallet wallet.Wallet // Wallet used to issue ethereum transactions @@ -95,18 +88,9 @@ func (p *Publisher) InitializeSecret(attestation *common.AttestationReport, encS InitialSecret: encSecret, HostAddress: p.hostData.P2PPublicAddress, } - initialiseSecretTx := p.mgmtContractLib.CreateInitializeSecret(l1tx, p.hostWallet.GetNonceAndIncrement()) - initialiseSecretTx, err = p.ethClient.EstimateGasAndGasPrice(initialiseSecretTx, p.hostWallet.Address()) - if err != nil { - p.hostWallet.SetNonce(p.hostWallet.GetNonce() - 1) - return err - } + initialiseSecretTx := p.mgmtContractLib.CreateInitializeSecret(l1tx) // we block here until we confirm a successful receipt. It is important this is published before the initial rollup. - err = p.signAndBroadcastL1Tx(initialiseSecretTx, l1TxTriesSecret, true) - if err != nil { - return err - } - return nil + return p.publishTransaction(initialiseSecretTx) } func (p *Publisher) RequestSecret(attestation *common.AttestationReport) (gethcommon.Hash, error) { @@ -129,14 +113,9 @@ func (p *Publisher) RequestSecret(attestation *common.AttestationReport) (gethco panic(errors.Wrap(err, "could not fetch head block")) } } - requestSecretTx := p.mgmtContractLib.CreateRequestSecret(l1tx, p.hostWallet.GetNonceAndIncrement()) - requestSecretTx, err = p.ethClient.EstimateGasAndGasPrice(requestSecretTx, p.hostWallet.Address()) - if err != nil { - p.hostWallet.SetNonce(p.hostWallet.GetNonce() - 1) - return gethcommon.Hash{}, err - } + requestSecretTx := p.mgmtContractLib.CreateRequestSecret(l1tx) // we wait until the secret req transaction has succeeded before we start polling for the secret - err = p.signAndBroadcastL1Tx(requestSecretTx, l1TxTriesSecret, true) + err = p.publishTransaction(requestSecretTx) if err != nil { return gethcommon.Hash{}, err } @@ -152,18 +131,17 @@ func (p *Publisher) PublishSecretResponse(secretResponse *common.ProducedSecretR HostAddress: secretResponse.HostAddress, } // todo (#1624) - l1tx.Sign(a.attestationPubKey) doesn't matter as the waitSecret will process a tx that was reverted - respondSecretTx := p.mgmtContractLib.CreateRespondSecret(l1tx, p.hostWallet.GetNonceAndIncrement(), false) - respondSecretTx, err := p.ethClient.EstimateGasAndGasPrice(respondSecretTx, p.hostWallet.Address()) - if err != nil { - p.hostWallet.SetNonce(p.hostWallet.GetNonce() - 1) - return err - } + respondSecretTx := p.mgmtContractLib.CreateRespondSecret(l1tx, false) p.logger.Info("Broadcasting secret response L1 tx.", "requester", secretResponse.RequesterID) + // fire-and-forget (track the receipt asynchronously) - err = p.signAndBroadcastL1Tx(respondSecretTx, l1TxTriesSecret, false) - if err != nil { - return errors.Wrap(err, "could not broadcast secret response L1 tx") - } + go func() { + err := p.publishTransaction(respondSecretTx) + if err != nil { + p.logger.Error("could not broadcast secret response L1 tx", log.ErrKey, err) + } + }() + return nil } @@ -219,16 +197,9 @@ func (p *Publisher) PublishRollup(producedRollup *common.ExtRollup) { return string(header) }}, log.RollupHashKey, producedRollup.Header.Hash(), "batches_len", len(producedRollup.BatchPayloads)) - rollupTx := p.mgmtContractLib.CreateRollup(tx, p.hostWallet.GetNonceAndIncrement()) - rollupTx, err = p.ethClient.EstimateGasAndGasPrice(rollupTx, p.hostWallet.Address()) - if err != nil { - // todo (#1624) - make rollup submission a separate workflow (design and implement the flow etc) - p.hostWallet.SetNonce(p.hostWallet.GetNonce() - 1) - p.logger.Error("could not estimate rollup tx", log.ErrKey, err) - return - } + rollupTx := p.mgmtContractLib.CreateRollup(tx) - err = p.signAndBroadcastL1Tx(rollupTx, l1TxTriesRollup, true) + err = p.publishTransaction(rollupTx) if err != nil { p.logger.Error("could not issue rollup tx", log.ErrKey, err) } else { @@ -268,69 +239,68 @@ func (p *Publisher) FetchLatestPeersList() ([]string, error) { return filteredHostAddresses, nil } -// `tries` is the number of times to attempt broadcasting the transaction. -// if awaitReceipt is true then this method will block and synchronously wait to check the receipt, otherwise it is fire -// and forget and the receipt tracking will happen in a separate go-routine -func (p *Publisher) signAndBroadcastL1Tx(tx types.TxData, tries uint64, awaitReceipt bool) error { - var err error - tx, err = p.ethClient.EstimateGasAndGasPrice(tx, p.hostWallet.Address()) - if err != nil { - return errors.Wrap(err, "could not estimate gas/gas price for L1 tx") - } - - signedTx, err := p.hostWallet.SignTransaction(tx) - if err != nil { - return err - } - - p.logger.Info("Host issuing l1 tx", log.TxKey, signedTx.Hash(), "size", signedTx.Size()/1024) - - err = retry.Do(func() error { - return p.ethClient.SendTransaction(signedTx) - }, retry.NewDoublingBackoffStrategy(time.Second, tries)) // doubling retry wait (3 tries = 7sec, 7 tries = 63sec) - if err != nil { - return fmt.Errorf("could not broadcast L1 tx after %d tries: %w", tries, err) - } - p.logger.Info("Successfully submitted tx to L1", "txHash", signedTx.Hash()) - - if awaitReceipt { - // block until receipt is found and then return - return p.waitForReceipt(signedTx.Hash()) - } +// publishTransaction will keep trying unless the L1 seems to be unavailable or the tx is otherwise rejected +// It is responsible for keeping the nonce accurate, according to the following rules: +// - Caller should not increment the wallet nonce before this method is called +// - This method will increment the wallet nonce only if the transaction is successfully broadcast +// - This method will continue to resend the tx using latest gas price until it is successfully broadcast or the L1 is unavailable/this service is shutdown +// - **ONLY** the L1 publisher service is publishing transactions for this wallet (to avoid nonce conflicts) +// todo (@matt) this method should take a context so we can try to cancel if the tx is no longer required +func (p *Publisher) publishTransaction(tx types.TxData) error { + // the nonce to be used for this tx attempt + nonce := p.hostWallet.GetNonceAndIncrement() + + // while the publisher service is still alive we keep trying to get the transaction into the L1 + for !p.hostStopper.IsStopping() { + // make sure an earlier tx hasn't been abandoned + if nonce > p.hostWallet.GetNonce() { + return errors.New("earlier transaction has failed to complete, we need to abort this transaction") + } + // update the tx gas price before each attempt + tx, err := p.ethClient.PrepareTransactionToSend(tx, p.hostWallet.Address(), nonce) + if err != nil { + p.hostWallet.SetNonce(nonce) // revert the wallet nonce because we failed to complete the transaction + return errors.Wrap(err, "could not estimate gas/gas price for L1 tx") + } - // else just watch for receipt asynchronously and log if it fails - go func() { - // todo (#1624) - consider how to handle the various ways that L1 transactions could fail to improve node operator QoL - err = p.waitForReceipt(signedTx.Hash()) + signedTx, err := p.hostWallet.SignTransaction(tx) if err != nil { - p.logger.Error("L1 transaction failed", log.ErrKey, err) + p.hostWallet.SetNonce(nonce) // revert the wallet nonce because we failed to complete the transaction + return errors.Wrap(err, "could not sign L1 tx") } - }() - return nil -} + p.logger.Info("Host issuing l1 tx", log.TxKey, signedTx.Hash(), "size", signedTx.Size()/1024) + err = p.ethClient.SendTransaction(signedTx) + if err != nil { + p.hostWallet.SetNonce(nonce) // revert the wallet nonce because we failed to complete the transaction + return errors.Wrap(err, "could not broadcast L1 tx") + } + p.logger.Info("Successfully submitted tx to L1", "txHash", signedTx.Hash()) + + var receipt *types.Receipt + // retry until receipt is found + err = retry.Do( + func() error { + receipt, err = p.ethClient.TransactionReceipt(signedTx.Hash()) + if err != nil { + return fmt.Errorf("could not get receipt for L1 tx=%s: %w", signedTx.Hash(), err) + } + return err + }, + retry.NewTimeoutStrategy(p.maxWaitForL1Receipt, p.retryIntervalForL1Receipt), + ) + if err != nil { + p.logger.Info("Receipt not found for transaction, we will re-attempt", log.ErrKey, err) + continue // try again on the same nonce, with updated gas price + } -func (p *Publisher) waitForReceipt(txHash common.TxHash) error { - var receipt *types.Receipt - var err error - err = retry.Do( - func() error { - receipt, err = p.ethClient.TransactionReceipt(txHash) - if err != nil { - // adds more info on the error - return fmt.Errorf("could not get receipt for L1 tx=%s: %w", txHash, err) - } - return err - }, - retry.NewTimeoutStrategy(p.maxWaitForL1Receipt, p.retryIntervalForL1Receipt), - ) - if err != nil { - return errors.Wrap(err, "receipt for L1 tx not found despite successful broadcast") - } + if err == nil && receipt.Status != types.ReceiptStatusSuccessful { + return fmt.Errorf("unsuccessful receipt found for published L1 transaction, status=%d", receipt.Status) + } - if err == nil && receipt.Status != types.ReceiptStatusSuccessful { - return fmt.Errorf("unsuccessful receipt found for published L1 transaction, status=%d", receipt.Status) + p.logger.Debug("L1 transaction successful receipt found.", log.TxKey, signedTx.Hash(), + log.BlockHeightKey, receipt.BlockNumber, log.BlockHashKey, receipt.BlockHash) + break } - p.logger.Debug("L1 transaction receipt found.", log.TxKey, txHash, log.BlockHeightKey, receipt.BlockNumber, log.BlockHashKey, receipt.BlockHash) return nil } diff --git a/integration/eth2network/eth2_network_test.go b/integration/eth2network/eth2_network_test.go index 96e99224a3..8d245e4a30 100644 --- a/integration/eth2network/eth2_network_test.go +++ b/integration/eth2network/eth2_network_test.go @@ -148,11 +148,10 @@ func txsAreMinted(t *testing.T, wallets []wallet.Wallet) { w := wallets[i] toAddr := datagenerator.RandomAddress() - estimatedTx, err := ethClient.EstimateGasAndGasPrice(&types.LegacyTx{ - Nonce: w.GetNonceAndIncrement(), + estimatedTx, err := ethClient.PrepareTransactionToSend(&types.LegacyTx{ To: &toAddr, Value: big.NewInt(100), - }, w.Address()) + }, w.Address(), w.GetNonceAndIncrement()) assert.Nil(t, err) signedTx, err := w.SignTransaction(estimatedTx) diff --git a/integration/ethereummock/erc20_contract_lib.go b/integration/ethereummock/erc20_contract_lib.go index a6d8520315..83d7cd6ac4 100644 --- a/integration/ethereummock/erc20_contract_lib.go +++ b/integration/ethereummock/erc20_contract_lib.go @@ -11,8 +11,8 @@ import ( type contractLib struct{} -func (c *contractLib) CreateDepositTx(tx *ethadapter.L1DepositTx, nonce uint64) types.TxData { - return encodeTx(tx, nonce, depositTxAddr) +func (c *contractLib) CreateDepositTx(tx *ethadapter.L1DepositTx) types.TxData { + return encodeTx(tx, depositTxAddr) } // Return only deposit transactions to the management contract diff --git a/integration/ethereummock/mgmt_contract_lib.go b/integration/ethereummock/mgmt_contract_lib.go index df44a17f41..f16f35f54d 100644 --- a/integration/ethereummock/mgmt_contract_lib.go +++ b/integration/ethereummock/mgmt_contract_lib.go @@ -55,20 +55,20 @@ func (m *mockContractLib) DecodeTx(tx *types.Transaction) ethadapter.L1Transacti return decodeTx(tx) } -func (m *mockContractLib) CreateRollup(tx *ethadapter.L1RollupTx, nonce uint64) types.TxData { - return encodeTx(tx, nonce, rollupTxAddr) +func (m *mockContractLib) CreateRollup(tx *ethadapter.L1RollupTx) types.TxData { + return encodeTx(tx, rollupTxAddr) } -func (m *mockContractLib) CreateRequestSecret(tx *ethadapter.L1RequestSecretTx, nonce uint64) types.TxData { - return encodeTx(tx, nonce, requestSecretTxAddr) +func (m *mockContractLib) CreateRequestSecret(tx *ethadapter.L1RequestSecretTx) types.TxData { + return encodeTx(tx, requestSecretTxAddr) } -func (m *mockContractLib) CreateRespondSecret(tx *ethadapter.L1RespondSecretTx, nonce uint64, _ bool) types.TxData { - return encodeTx(tx, nonce, storeSecretTxAddr) +func (m *mockContractLib) CreateRespondSecret(tx *ethadapter.L1RespondSecretTx, _ bool) types.TxData { + return encodeTx(tx, storeSecretTxAddr) } -func (m *mockContractLib) CreateInitializeSecret(tx *ethadapter.L1InitializeSecretTx, nonce uint64) types.TxData { - return encodeTx(tx, nonce, initializeSecretTxAddr) +func (m *mockContractLib) CreateInitializeSecret(tx *ethadapter.L1InitializeSecretTx) types.TxData { + return encodeTx(tx, initializeSecretTxAddr) } func (m *mockContractLib) GetHostAddresses() (ethereum.CallMsg, error) { @@ -114,7 +114,7 @@ func decodeTx(tx *types.Transaction) ethadapter.L1Transaction { return t } -func encodeTx(tx ethadapter.L1Transaction, nonce uint64, opType gethcommon.Address) types.TxData { +func encodeTx(tx ethadapter.L1Transaction, opType gethcommon.Address) types.TxData { var buf bytes.Buffer enc := gob.NewEncoder(&buf) @@ -125,8 +125,7 @@ func encodeTx(tx ethadapter.L1Transaction, nonce uint64, opType gethcommon.Addre // the mock implementation does not process contract calls // this uses the To address to distinguish between different contract calls / different l1 transactions return &types.LegacyTx{ - Nonce: nonce, - Data: buf.Bytes(), - To: &opType, + Data: buf.Bytes(), + To: &opType, } } diff --git a/integration/ethereummock/node.go b/integration/ethereummock/node.go index feb4626d06..d2f57548c3 100644 --- a/integration/ethereummock/node.go +++ b/integration/ethereummock/node.go @@ -86,8 +86,16 @@ type Node struct { logger gethlog.Logger } -func (m *Node) EstimateGasAndGasPrice(txData types.TxData, _ gethcommon.Address) (types.TxData, error) { - return txData, nil +func (m *Node) PrepareTransactionToSend(txData types.TxData, _ gethcommon.Address, nonce uint64) (types.TxData, error) { + tx := types.NewTx(txData) + return &types.LegacyTx{ + Nonce: nonce, + GasPrice: tx.GasPrice(), + Gas: tx.Gas(), + To: tx.To(), + Value: tx.Value(), + Data: tx.Data(), + }, nil } func (m *Node) SendTransaction(tx *types.Transaction) error { diff --git a/integration/manualtests/tx_test.go b/integration/manualtests/tx_test.go index f427ca980a..702167268d 100644 --- a/integration/manualtests/tx_test.go +++ b/integration/manualtests/tx_test.go @@ -68,10 +68,9 @@ func TestL1IssueContractInteractWaitReceipt(t *testing.T) { assert.Nil(t, err) l1Wallet.SetNonce(nonce) - estimatedTx, err := ethClient.EstimateGasAndGasPrice(&types.LegacyTx{ - Nonce: l1Wallet.GetNonceAndIncrement(), - Data: gethcommon.FromHex(storeContractBytecode), - }, l1Wallet.Address()) + estimatedTx, err := ethClient.PrepareTransactionToSend(&types.LegacyTx{ + Data: gethcommon.FromHex(storeContractBytecode), + }, l1Wallet.Address(), l1Wallet.GetNonceAndIncrement()) assert.Nil(t, err) signedTx, err := l1Wallet.SignTransaction(estimatedTx) @@ -114,11 +113,10 @@ func TestL1IssueTxWaitReceipt(t *testing.T) { assert.Nil(t, err) l1Wallet.SetNonce(nonce) - estimatedTx, err := ethClient.EstimateGasAndGasPrice(&types.LegacyTx{ - Nonce: l1Wallet.GetNonceAndIncrement(), + estimatedTx, err := ethClient.PrepareTransactionToSend(&types.LegacyTx{ To: &toAddr, Value: big.NewInt(100), - }, l1Wallet.Address()) + }, l1Wallet.Address(), l1Wallet.GetNonceAndIncrement()) assert.Nil(t, err) signedTx, err := l1Wallet.SignTransaction(estimatedTx) diff --git a/integration/noderunner/noderunner_test.go b/integration/noderunner/noderunner_test.go index 67a034f5fe..635ead7623 100644 --- a/integration/noderunner/noderunner_test.go +++ b/integration/noderunner/noderunner_test.go @@ -131,6 +131,7 @@ func createInMemoryNode(t *testing.T) (node.Node, gethcommon.Address) { node.WithL1WebsocketURL(fmt.Sprintf("ws://%s:%d", _localhost, _startPort+integration.DefaultGethWSPortOffset)), node.WithGenesis(true), node.WithProfiler(true), + node.WithL1BlockTime(1*time.Second), ) return NewInMemNode(nodeCfg), hostAddress diff --git a/integration/simulation/devnetwork/config.go b/integration/simulation/devnetwork/config.go index 6bbd11555d..cee4cc09b4 100644 --- a/integration/simulation/devnetwork/config.go +++ b/integration/simulation/devnetwork/config.go @@ -29,6 +29,7 @@ type ObscuroConfig struct { InitNumValidators int BatchInterval time.Duration RollupInterval time.Duration + L1BlockTime time.Duration } // DefaultDevNetwork provides an off-the-shelf default config for a sim network @@ -50,6 +51,7 @@ func DefaultDevNetwork() *InMemDevNetwork { InitNumValidators: 3, BatchInterval: 1 * time.Second, RollupInterval: 10 * time.Second, + L1BlockTime: 15 * time.Second, }, faucetLock: sync.Mutex{}, } @@ -86,7 +88,8 @@ func LiveL1DevNetwork(seqWallet wallet.Wallet, validatorWallets []wallet.Wallet, PortStart: integration.StartPortSimulationFullNetwork, InitNumValidators: len(validatorWallets), BatchInterval: 5 * time.Second, - RollupInterval: 1 * time.Minute, + RollupInterval: 3 * time.Minute, + L1BlockTime: 15 * time.Second, }, } } diff --git a/integration/simulation/devnetwork/node.go b/integration/simulation/devnetwork/node.go index 3b22912c43..5230023e1f 100644 --- a/integration/simulation/devnetwork/node.go +++ b/integration/simulation/devnetwork/node.go @@ -130,6 +130,7 @@ func (n *InMemNodeOperator) createHostContainer() *hostcontainer.HostContainer { DebugNamespaceEnabled: true, BatchInterval: n.config.BatchInterval, RollupInterval: n.config.RollupInterval, + L1BlockTime: n.config.L1BlockTime, } hostLogger := testlog.Logger().New(log.NodeIDKey, n.operatorIdx, log.CmpKey, log.HostCmp) diff --git a/integration/simulation/network/geth_utils.go b/integration/simulation/network/geth_utils.go index 027f6a76c7..7a85a319cf 100644 --- a/integration/simulation/network/geth_utils.go +++ b/integration/simulation/network/geth_utils.go @@ -161,10 +161,9 @@ func StopEth2Network(clients []ethadapter.EthClient, netw eth2network.Eth2Networ // DeployContract returns receipt of deployment // todo (@matt) - this should live somewhere else func DeployContract(workerClient ethadapter.EthClient, w wallet.Wallet, contractBytes []byte) (*types.Receipt, error) { - deployContractTx, err := workerClient.EstimateGasAndGasPrice(&types.LegacyTx{ - Nonce: w.GetNonceAndIncrement(), - Data: contractBytes, - }, w.Address()) + deployContractTx, err := workerClient.PrepareTransactionToSend(&types.LegacyTx{ + Data: contractBytes, + }, w.Address(), w.GetNonceAndIncrement()) if err != nil { w.SetNonce(w.GetNonce() - 1) return nil, err diff --git a/integration/simulation/simulation.go b/integration/simulation/simulation.go index 9146193903..44c0c05eb0 100644 --- a/integration/simulation/simulation.go +++ b/integration/simulation/simulation.go @@ -204,8 +204,8 @@ func (s *Simulation) prefundL1Accounts() { TokenContract: s.Params.Wallets.Tokens[testcommon.HOC].L1ContractAddress, Sender: &ownerAddr, } - tx := s.Params.ERC20ContractLib.CreateDepositTx(txData, tokenOwner.GetNonceAndIncrement()) - estimatedTx, err := ethClient.EstimateGasAndGasPrice(tx, tokenOwner.Address()) + tx := s.Params.ERC20ContractLib.CreateDepositTx(txData) + estimatedTx, err := ethClient.PrepareTransactionToSend(tx, tokenOwner.Address(), tokenOwner.GetNonceAndIncrement()) if err != nil { // ignore txs that are not able to be estimated/execute testlog.Logger().Error("unable to estimate tx", log.ErrKey, err) diff --git a/integration/smartcontract/debug_mgmt_contract_lib.go b/integration/smartcontract/debug_mgmt_contract_lib.go index de3fb1aaa9..b1f0f21909 100644 --- a/integration/smartcontract/debug_mgmt_contract_lib.go +++ b/integration/smartcontract/debug_mgmt_contract_lib.go @@ -41,10 +41,7 @@ func (d *debugMgmtContractLib) AwaitedIssueRollup(rollup common.ExtRollup, clien if err != nil { return err } - txData := d.CreateRollup( - ðadapter.L1RollupTx{Rollup: encodedRollup}, - w.GetNonceAndIncrement(), - ) + txData := d.CreateRollup(ðadapter.L1RollupTx{Rollup: encodedRollup}) issuedTx, receipt, err := w.AwaitedSignAndSendTransaction(client, txData) if err != nil { diff --git a/integration/smartcontract/debug_wallet.go b/integration/smartcontract/debug_wallet.go index e7f42b452c..55e3c26205 100644 --- a/integration/smartcontract/debug_wallet.go +++ b/integration/smartcontract/debug_wallet.go @@ -28,7 +28,7 @@ func newDebugWallet(w wallet.Wallet) *debugWallet { func (w *debugWallet) AwaitedSignAndSendTransaction(client ethadapter.EthClient, txData types.TxData) (*types.Transaction, *types.Receipt, error) { var err error - txData, err = client.EstimateGasAndGasPrice(txData, w.Address()) + txData, err = client.PrepareTransactionToSend(txData, w.Address(), w.GetNonceAndIncrement()) if err != nil { w.SetNonce(w.GetNonce() - 1) return nil, nil, err diff --git a/integration/smartcontract/smartcontracts_test.go b/integration/smartcontract/smartcontracts_test.go index 3a18a89097..a4c3abaee0 100644 --- a/integration/smartcontract/smartcontracts_test.go +++ b/integration/smartcontract/smartcontracts_test.go @@ -143,10 +143,7 @@ func nonAttestedNodesCannotCreateRollup(t *testing.T, mgmtContractLib *debugMgmt if err != nil { t.Error(err) } - txData := mgmtContractLib.CreateRollup( - ðadapter.L1RollupTx{Rollup: encodedRollup}, - w.GetNonceAndIncrement(), - ) + txData := mgmtContractLib.CreateRollup(ðadapter.L1RollupTx{Rollup: encodedRollup}) _, _, err = w.AwaitedSignAndSendTransaction(client, txData) if err == nil || !assert.Contains(t, err.Error(), "execution reverted") { @@ -161,7 +158,6 @@ func secretCannotBeInitializedTwice(t *testing.T, mgmtContractLib *debugMgmtCont ðadapter.L1InitializeSecretTx{ AggregatorID: &aggregatorID, }, - w.GetNonceAndIncrement(), ) _, receipt, err := w.AwaitedSignAndSendTransaction(client, txData) @@ -188,7 +184,6 @@ func secretCannotBeInitializedTwice(t *testing.T, mgmtContractLib *debugMgmtCont ðadapter.L1InitializeSecretTx{ AggregatorID: &aggregatorID, }, - w.GetNonceAndIncrement(), ) _, _, err = w.AwaitedSignAndSendTransaction(client, txData) @@ -212,7 +207,6 @@ func attestedNodesCreateRollup(t *testing.T, mgmtContractLib *debugMgmtContractL ðadapter.L1InitializeSecretTx{ AggregatorID: requesterID, }, - w.GetNonceAndIncrement(), ) _, receipt, err := w.AwaitedSignAndSendTransaction(client, txData) @@ -244,7 +238,6 @@ func nonAttestedNodesCannotAttest(t *testing.T, mgmtContractLib *debugMgmtContra ðadapter.L1InitializeSecretTx{ AggregatorID: &aggAID, }, - w.GetNonceAndIncrement(), ) _, receipt, err := w.AwaitedSignAndSendTransaction(client, txData) @@ -266,7 +259,6 @@ func nonAttestedNodesCannotAttest(t *testing.T, mgmtContractLib *debugMgmtContra ðadapter.L1RequestSecretTx{ Attestation: datagenerator.RandomBytes(10), }, - w.GetNonceAndIncrement(), ) _, receipt, err = w.AwaitedSignAndSendTransaction(client, txData) @@ -292,7 +284,6 @@ func nonAttestedNodesCannotAttest(t *testing.T, mgmtContractLib *debugMgmtContra RequesterID: aggBID, Secret: fakeSecret, }).Sign(aggCPrivateKey), - w.GetNonceAndIncrement(), true, ) @@ -308,7 +299,6 @@ func nonAttestedNodesCannotAttest(t *testing.T, mgmtContractLib *debugMgmtContra RequesterID: aggBID, AttesterID: aggAID, }).Sign(aggCPrivateKey), - w.GetNonceAndIncrement(), true, ) @@ -334,7 +324,6 @@ func newlyAttestedNodesCanAttest(t *testing.T, mgmtContractLib *debugMgmtContrac AggregatorID: &aggAID, InitialSecret: secretBytes, }, - w.GetNonceAndIncrement(), ) _, receipt, err := w.AwaitedSignAndSendTransaction(client, txData) @@ -363,7 +352,6 @@ func newlyAttestedNodesCanAttest(t *testing.T, mgmtContractLib *debugMgmtContrac ðadapter.L1RequestSecretTx{ Attestation: datagenerator.RandomBytes(10), }, - w.GetNonceAndIncrement(), ) _, receipt, err = w.AwaitedSignAndSendTransaction(client, txData) if err != nil { @@ -384,7 +372,6 @@ func newlyAttestedNodesCanAttest(t *testing.T, mgmtContractLib *debugMgmtContrac ðadapter.L1RequestSecretTx{ Attestation: datagenerator.RandomBytes(10), }, - w.GetNonceAndIncrement(), ) _, receipt, err = w.AwaitedSignAndSendTransaction(client, txData) @@ -402,7 +389,6 @@ func newlyAttestedNodesCanAttest(t *testing.T, mgmtContractLib *debugMgmtContrac RequesterID: aggCID, AttesterID: aggAID, }).Sign(aggAPrivateKey), - w.GetNonceAndIncrement(), true, ) _, receipt, err = w.AwaitedSignAndSendTransaction(client, txData) @@ -430,7 +416,6 @@ func newlyAttestedNodesCanAttest(t *testing.T, mgmtContractLib *debugMgmtContrac RequesterID: aggBID, AttesterID: aggCID, }).Sign(aggCPrivateKey), - w.GetNonceAndIncrement(), true, ) _, receipt, err = w.AwaitedSignAndSendTransaction(client, txData) @@ -471,7 +456,6 @@ func attestedNodeHostAddressesAreStored(t *testing.T, mgmtContractLib *debugMgmt InitialSecret: secretBytes, HostAddress: aggAHostAddr, }, - w.GetNonceAndIncrement(), ) _, receipt, err := w.AwaitedSignAndSendTransaction(client, txData) @@ -493,7 +477,6 @@ func attestedNodeHostAddressesAreStored(t *testing.T, mgmtContractLib *debugMgmt ðadapter.L1RequestSecretTx{ Attestation: datagenerator.RandomBytes(10), }, - w.GetNonceAndIncrement(), ) _, receipt, err = w.AwaitedSignAndSendTransaction(client, txData) if err != nil { @@ -508,7 +491,6 @@ func attestedNodeHostAddressesAreStored(t *testing.T, mgmtContractLib *debugMgmt ðadapter.L1RequestSecretTx{ Attestation: datagenerator.RandomBytes(10), }, - w.GetNonceAndIncrement(), ) _, receipt, err = w.AwaitedSignAndSendTransaction(client, txData) @@ -527,7 +509,6 @@ func attestedNodeHostAddressesAreStored(t *testing.T, mgmtContractLib *debugMgmt AttesterID: aggAID, HostAddress: aggBHostAddr, }).Sign(aggAPrivateKey), - w.GetNonceAndIncrement(), true, ) _, receipt, err = w.AwaitedSignAndSendTransaction(client, txData)