From ae1655caef511a7b160ab474d06a562352201950 Mon Sep 17 00:00:00 2001
From: leonardchinonso <36096513+leonardchinonso@users.noreply.github.com>
Date: Wed, 23 Mar 2022 15:26:33 +0100
Subject: [PATCH] Feature/automate devnet tool nonce (#3754)

* Added eth_getTransactionCount to the devnet tool

* Fixed lint errors

* Fixed lint

* Fixed compilation error
---
 cmd/devnettest/commands/account.go  |  2 +-
 cmd/devnettest/commands/block.go    | 17 +++++++++++++----
 cmd/devnettest/requests/requests.go | 17 ++++++++++++++++-
 cmd/devnettest/services/account.go  | 19 +++++++++++++++++--
 cmd/devnettest/services/block.go    | 15 ++++++++++++---
 5 files changed, 59 insertions(+), 11 deletions(-)

diff --git a/cmd/devnettest/commands/account.go b/cmd/devnettest/commands/account.go
index aed9d2bcda..a6d32a01cb 100644
--- a/cmd/devnettest/commands/account.go
+++ b/cmd/devnettest/commands/account.go
@@ -64,7 +64,7 @@ var getTransactionCountCmd = &cobra.Command{
 			defer services.ClearDevDB()
 		}
 		address := common.HexToAddress(addr)
-		if err := requests.GetTransactionCount(reqId, address, blockNum); err != nil {
+		if err := requests.GetTransactionCountCmd(reqId, address, blockNum); err != nil {
 			fmt.Printf("could not get transaction count: %v\n", err)
 		}
 	},
diff --git a/cmd/devnettest/commands/block.go b/cmd/devnettest/commands/block.go
index 3b67dabed3..34dbc3633d 100644
--- a/cmd/devnettest/commands/block.go
+++ b/cmd/devnettest/commands/block.go
@@ -1,6 +1,7 @@
 package commands
 
 import (
+	"context"
 	"fmt"
 
 	"github.com/ledgerwatch/erigon/cmd/devnettest/requests"
@@ -11,7 +12,6 @@ import (
 var (
 	sendAddr    string
 	sendValue   uint64
-	nonce       uint64
 	searchBlock bool
 	txType      string
 )
@@ -22,7 +22,6 @@ func init() {
 
 	sendTxCmd.Flags().StringVar(&sendAddr, "addr", "", "String address to send to")
 	sendTxCmd.Flags().Uint64Var(&sendValue, "value", 0, "Uint64 Value to send")
-	sendTxCmd.Flags().Uint64Var(&nonce, "nonce", 0, "Uint64 nonce")
 	sendTxCmd.Flags().BoolVar(&searchBlock, "search-block", false, "Boolean look for tx in mined blocks")
 
 	rootCmd.AddCommand(sendTxCmd)
@@ -50,12 +49,16 @@ var sendTxCmd = &cobra.Command{
 			defer services.ClearDevDB()
 		}
 
-		nonce = services.GetNonce(nonce)
+		nonce, err := services.GetNonce(reqId)
+		if err != nil {
+			fmt.Printf("failed to get latest nonce: %v\n", err)
+			return
+		}
 
 		// subscriptionContract is the handler to the contract for further operations
 		signedTx, address, subscriptionContract, transactOpts, err := services.CreateTransaction(txType, sendAddr, sendValue, nonce, searchBlock)
 		if err != nil {
-			fmt.Printf("failed to deploy subscription: %v\n", err)
+			fmt.Printf("failed to create transaction: %v\n", err)
 			return
 		}
 
@@ -78,6 +81,12 @@ var sendTxCmd = &cobra.Command{
 				fmt.Printf("failed to emit events: %v\n", err)
 				return
 			}
+		} else {
+			err := services.ApplyTransaction(context.Background(), *signedTx)
+			if err != nil {
+				fmt.Printf("failed to apply transaction: %v\n", err)
+				return
+			}
 		}
 	},
 }
diff --git a/cmd/devnettest/requests/requests.go b/cmd/devnettest/requests/requests.go
index 4968908e0e..daaac7ddee 100644
--- a/cmd/devnettest/requests/requests.go
+++ b/cmd/devnettest/requests/requests.go
@@ -127,7 +127,7 @@ func GetLogs(reqId int, fromBlock, toBlock uint64, address common.Address) error
 	return nil
 }
 
-func GetTransactionCount(reqId int, address common.Address, blockNum string) error {
+func GetTransactionCountCmd(reqId int, address common.Address, blockNum string) error {
 	reqGen := initialiseRequestGenerator(reqId)
 	var b rpctest.EthGetTransactionCount
 
@@ -147,3 +147,18 @@ func GetTransactionCount(reqId int, address common.Address, blockNum string) err
 	fmt.Printf("Nonce: %v\n", s)
 	return nil
 }
+
+func GetTransactionCount(reqId int, address common.Address, blockNum string) (rpctest.EthGetTransactionCount, error) {
+	reqGen := initialiseRequestGenerator(reqId)
+	var b rpctest.EthGetTransactionCount
+
+	if res := reqGen.Erigon("eth_getTransactionCount", reqGen.getTransactionCount(address, blockNum), &b); res.Err != nil {
+		return b, fmt.Errorf("error getting transaction count: %v\n", res.Err)
+	}
+
+	if b.Error != nil {
+		return b, fmt.Errorf("error populating response object: %v", b.Error)
+	}
+
+	return b, nil
+}
diff --git a/cmd/devnettest/services/account.go b/cmd/devnettest/services/account.go
index d907a1649c..4e907fa012 100644
--- a/cmd/devnettest/services/account.go
+++ b/cmd/devnettest/services/account.go
@@ -1,5 +1,20 @@
 package services
 
-func GetNonce(nonce uint64) uint64 {
-	return nonce
+import (
+	"fmt"
+	"github.com/ledgerwatch/erigon/cmd/devnettest/requests"
+	"github.com/ledgerwatch/erigon/common"
+)
+
+// GetNonce fetches the latest nonce of the developer account by making an JSONRPC request
+func GetNonce(reqId int) (uint64, error) {
+	blockNum := "latest"
+	address := common.HexToAddress(devAddress)
+
+	res, err := requests.GetTransactionCount(reqId, address, blockNum)
+	if err != nil {
+		return 0, fmt.Errorf("failed to get transaction count for address 0x%x: %v", address, err)
+	}
+
+	return uint64(res.Result), nil
 }
diff --git a/cmd/devnettest/services/block.go b/cmd/devnettest/services/block.go
index bd86b5d393..0ea4246244 100644
--- a/cmd/devnettest/services/block.go
+++ b/cmd/devnettest/services/block.go
@@ -28,6 +28,9 @@ const (
 var (
 	devnetSignPrivateKey, _ = crypto.HexToECDSA("26e86e45f6fc45ec6e2ecd128cec80fa1d1505e5507dcd2ae58c3130a7a97b48")
 	signer                  = types.LatestSigner(params.AllCliqueProtocolChanges)
+	devAddress              = "67b1d87101671b127f5f8714789C7192f7ad340e"
+	gspec                   = core.DeveloperGenesisBlock(uint64(0), common.HexToAddress(devAddress))
+	contractBackend         = backends.NewSimulatedBackendWithConfig(gspec.Alloc, gspec.Config, 1_000_000)
 )
 
 type Block struct {
@@ -60,9 +63,6 @@ func createNonContractTx(addr string, value, nonce uint64) (*types.Transaction,
 
 // createContractTx creates and signs a transaction using the developer address, returns the contract and the signed transaction
 func createContractTx(nonce uint64) (*types.Transaction, common.Address, *contracts.Subscription, *bind.TransactOpts, error) {
-	gspec := core.DeveloperGenesisBlock(uint64(0), common.HexToAddress("67b1d87101671b127f5f8714789C7192f7ad340e"))
-	contractBackend := backends.NewSimulatedBackendWithConfig(gspec.Alloc, gspec.Config, 1_000_000)
-
 	// initialize transactOpts
 	transactOpts, err := initializeTransactOps(nonce)
 	if err != nil {
@@ -212,6 +212,15 @@ func EmitEventAndGetLogs(reqId int, subContract *contracts.Subscription, opts *b
 	return nil
 }
 
+func ApplyTransaction(ctx context.Context, tx types.Transaction) error {
+	err := contractBackend.SendTransaction(ctx, tx)
+	if err != nil {
+		return fmt.Errorf("failed to send transaction: %v", err)
+	}
+	contractBackend.Commit()
+	return nil
+}
+
 // ClearDevDB cleans up the dev folder used for the operations
 func ClearDevDB() {
 	fmt.Printf("Clearing ~/dev\n")
-- 
GitLab