mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-19 00:54:12 +00:00
415cf86250
This branch is intended to allow the devnet to be used for testing multiple consents types beyond the default clique. It is initially being used to test Bor consensus for polygon. It also has the following refactoring: ### 1. Network configuration The two node arg building functions miningNodeArgs and nonMiningNodeArgs have been replaced with a configuration struct which is used to configure: ```go network := &node.Network{ DataDir: dataDir, Chain: networkname.DevChainName, //Chain: networkname.BorDevnetChainName, Logger: logger, BasePrivateApiAddr: "localhost:9090", BaseRPCAddr: "localhost:8545", Nodes: []node.NetworkNode{ &node.Miner{}, &node.NonMiner{}, }, } ``` and start multiple nodes ```go network.Start() ``` Network start will create a network of nodes ensuring that all nodes are configured with non clashing network ports set via command line arguments on start-up. ### 2. Request Routing The `RequestRouter` has been updated to take a 'target' rather than using a static dispatcher which routes to a single node on the network. Each node in the network has its own request generator so command and services have more flexibility in request routing and `ExecuteAllMethods` currently takes the `node.Network` as an argument and can pick which node (node 0 for the moment) to send requests to.
311 lines
11 KiB
Go
311 lines
11 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"math/big"
|
|
"time"
|
|
|
|
"github.com/holiman/uint256"
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/log/v3"
|
|
|
|
"github.com/ledgerwatch/erigon/accounts/abi/bind"
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/contracts"
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/devnetutils"
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/models"
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/node"
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/requests"
|
|
"github.com/ledgerwatch/erigon/core/types"
|
|
"github.com/ledgerwatch/erigon/params"
|
|
"github.com/ledgerwatch/erigon/rpc"
|
|
)
|
|
|
|
const gasPrice = 912_345_678
|
|
const gasAmount = 875_000_000
|
|
|
|
var (
|
|
signer = types.LatestSigner(params.AllCliqueProtocolChanges)
|
|
)
|
|
|
|
func CreateManyEIP1559TransactionsRefWithBaseFee(node *node.Node, addr string, startingNonce *uint64, logger log.Logger) ([]*types.Transaction, []*types.Transaction, error) {
|
|
toAddress := libcommon.HexToAddress(addr)
|
|
|
|
baseFeePerGas, err := BaseFeeFromBlock(node, logger)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed BaseFeeFromBlock: %v", err)
|
|
}
|
|
|
|
logger.Info("BaseFeePerGas", "val", baseFeePerGas)
|
|
|
|
lowerBaseFeeTransactions, higherBaseFeeTransactions, err := signEIP1559TxsLowerAndHigherThanBaseFee2(1, 1, baseFeePerGas, startingNonce, toAddress, logger)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed signEIP1559TxsLowerAndHigherThanBaseFee2: %v", err)
|
|
}
|
|
|
|
return lowerBaseFeeTransactions, higherBaseFeeTransactions, nil
|
|
}
|
|
|
|
func CreateManyEIP1559TransactionsRefWithBaseFee2(node *node.Node, addr string, startingNonce *uint64, logger log.Logger) ([]*types.Transaction, []*types.Transaction, error) {
|
|
toAddress := libcommon.HexToAddress(addr)
|
|
|
|
baseFeePerGas, err := BaseFeeFromBlock(node, logger)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed BaseFeeFromBlock: %v", err)
|
|
}
|
|
|
|
logger.Info("BaseFeePerGas2", "val", baseFeePerGas)
|
|
|
|
lowerBaseFeeTransactions, higherBaseFeeTransactions, err := signEIP1559TxsLowerAndHigherThanBaseFee2(100, 100, baseFeePerGas, startingNonce, toAddress, logger)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed signEIP1559TxsLowerAndHigherThanBaseFee2: %v", err)
|
|
}
|
|
|
|
return lowerBaseFeeTransactions, higherBaseFeeTransactions, nil
|
|
}
|
|
|
|
// CreateTransaction creates a transaction depending on the type of transaction being passed
|
|
func CreateTransaction(txType models.TransactionType, addr string, value, nonce uint64) (*types.Transaction, libcommon.Address, *contracts.Subscription, *bind.TransactOpts, error) {
|
|
switch txType {
|
|
case models.NonContractTx:
|
|
tx, address, err := createNonContractTx(addr, value, nonce)
|
|
if err != nil {
|
|
return nil, libcommon.Address{}, nil, nil, fmt.Errorf("failed to create non-contract transaction: %v", err)
|
|
}
|
|
return tx, address, nil, nil, nil
|
|
case models.ContractTx:
|
|
return createContractTx(nonce)
|
|
default:
|
|
return nil, libcommon.Address{}, nil, nil, models.ErrInvalidTransactionType
|
|
}
|
|
}
|
|
|
|
// createNonContractTx returns a signed transaction and the recipient address
|
|
func createNonContractTx(addr string, value, nonce uint64) (*types.Transaction, libcommon.Address, error) {
|
|
toAddress := libcommon.HexToAddress(addr)
|
|
|
|
// create a new transaction using the parameters to send
|
|
transaction := types.NewTransaction(nonce, toAddress, uint256.NewInt(value), params.TxGas, uint256.NewInt(gasPrice), nil)
|
|
|
|
// sign the transaction using the developer 0signed private key
|
|
signedTx, err := types.SignTx(transaction, *signer, models.DevSignedPrivateKey)
|
|
if err != nil {
|
|
return nil, libcommon.Address{}, fmt.Errorf("failed to sign non-contract transaction: %v", err)
|
|
}
|
|
|
|
return &signedTx, toAddress, nil
|
|
}
|
|
|
|
func signEIP1559TxsLowerAndHigherThanBaseFee2(amountLower, amountHigher int, baseFeePerGas uint64, nonce *uint64, toAddress libcommon.Address, logger log.Logger) ([]*types.Transaction, []*types.Transaction, error) {
|
|
higherBaseFeeTransactions, err := signEIP1559TxsHigherThanBaseFee(amountHigher, baseFeePerGas, nonce, toAddress, logger)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed signEIP1559TxsHigherThanBaseFee: %v", err)
|
|
}
|
|
|
|
lowerBaseFeeTransactions, err := signEIP1559TxsLowerThanBaseFee(amountLower, baseFeePerGas, nonce, toAddress, logger)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed signEIP1559TxsLowerThanBaseFee: %v", err)
|
|
}
|
|
|
|
return lowerBaseFeeTransactions, higherBaseFeeTransactions, nil
|
|
}
|
|
|
|
// signEIP1559TxsLowerThanBaseFee creates n number of transactions with gasFeeCap lower than baseFeePerGas
|
|
func signEIP1559TxsLowerThanBaseFee(n int, baseFeePerGas uint64, nonce *uint64, toAddress libcommon.Address, logger log.Logger) ([]*types.Transaction, error) {
|
|
var signedTransactions []*types.Transaction
|
|
|
|
var (
|
|
minFeeCap = baseFeePerGas - 300_000_000
|
|
maxFeeCap = (baseFeePerGas - 100_000_000) + 1 // we want the value to be inclusive in the random number generation, hence the addition of 1
|
|
)
|
|
|
|
for i := 0; i < n; i++ {
|
|
gasFeeCap, err := devnetutils.RandomNumberInRange(minFeeCap, maxFeeCap)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
value, err := devnetutils.RandomNumberInRange(0, 100_000)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
transaction := types.NewEIP1559Transaction(*signer.ChainID(), *nonce, toAddress, uint256.NewInt(value), uint64(210_000), uint256.NewInt(gasPrice), new(uint256.Int), uint256.NewInt(gasFeeCap), nil)
|
|
|
|
logger.Info("LOWER", "transaction", i, "nonce", transaction.Nonce, "value", transaction.Value, "feecap", transaction.FeeCap)
|
|
|
|
signedTransaction, err := types.SignTx(transaction, *signer, models.DevSignedPrivateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
signedTransactions = append(signedTransactions, &signedTransaction)
|
|
*nonce++
|
|
}
|
|
|
|
return signedTransactions, nil
|
|
}
|
|
|
|
// signEIP1559TxsHigherThanBaseFee creates amount number of transactions with gasFeeCap higher than baseFeePerGas
|
|
func signEIP1559TxsHigherThanBaseFee(n int, baseFeePerGas uint64, nonce *uint64, toAddress libcommon.Address, logger log.Logger) ([]*types.Transaction, error) {
|
|
var signedTransactions []*types.Transaction
|
|
|
|
var (
|
|
minFeeCap = baseFeePerGas
|
|
maxFeeCap = (baseFeePerGas + 100_000_000) + 1 // we want the value to be inclusive in the random number generation, hence the addition of 1
|
|
)
|
|
|
|
for i := 0; i < n; i++ {
|
|
gasFeeCap, err := devnetutils.RandomNumberInRange(minFeeCap, maxFeeCap)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
value, err := devnetutils.RandomNumberInRange(0, 100_000)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
transaction := types.NewEIP1559Transaction(*signer.ChainID(), *nonce, toAddress, uint256.NewInt(value), uint64(210_000), uint256.NewInt(gasPrice), new(uint256.Int), uint256.NewInt(gasFeeCap), nil)
|
|
|
|
logger.Info("HIGHER", "transaction", i, "nonce", transaction.Nonce, "value", transaction.Value, "feecap", transaction.FeeCap)
|
|
|
|
signedTransaction, err := types.SignTx(transaction, *signer, models.DevSignedPrivateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
signedTransactions = append(signedTransactions, &signedTransaction)
|
|
*nonce++
|
|
}
|
|
|
|
return signedTransactions, nil
|
|
}
|
|
|
|
// createContractTx creates and signs a transaction using the developer address, returns the contract and the signed transaction
|
|
func createContractTx(nonce uint64) (*types.Transaction, libcommon.Address, *contracts.Subscription, *bind.TransactOpts, error) {
|
|
// initialize transactOpts
|
|
transactOpts, err := initializeTransactOps(nonce)
|
|
if err != nil {
|
|
return nil, libcommon.Address{}, nil, nil, fmt.Errorf("failed to initialize transactOpts: %v", err)
|
|
}
|
|
|
|
// deploy the contract and get the contract handler
|
|
address, txToSign, subscriptionContract, err := contracts.DeploySubscription(transactOpts, models.ContractBackend)
|
|
if err != nil {
|
|
return nil, libcommon.Address{}, nil, nil, fmt.Errorf("failed to deploy subscription: %v", err)
|
|
}
|
|
|
|
// sign the transaction with the private key
|
|
signedTx, err := types.SignTx(txToSign, *signer, models.DevSignedPrivateKey)
|
|
if err != nil {
|
|
return nil, libcommon.Address{}, nil, nil, fmt.Errorf("failed to sign tx: %v", err)
|
|
}
|
|
|
|
return &signedTx, address, subscriptionContract, transactOpts, nil
|
|
}
|
|
|
|
// initializeTransactOps initializes the transactOpts object for a contract transaction
|
|
func initializeTransactOps(nonce uint64) (*bind.TransactOpts, error) {
|
|
var chainID = big.NewInt(1337)
|
|
|
|
transactOpts, err := bind.NewKeyedTransactorWithChainID(models.DevSignedPrivateKey, chainID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot create transactor with chainID %d, error: %v", chainID, err)
|
|
}
|
|
|
|
transactOpts.GasLimit = uint64(200_000)
|
|
transactOpts.GasPrice = big.NewInt(880_000_000)
|
|
transactOpts.Nonce = big.NewInt(int64(nonce)) // TODO: Get Nonce from account automatically
|
|
|
|
return transactOpts, nil
|
|
}
|
|
|
|
// txHashInBlock checks if the block with block number has the transaction hash in its list of transactions
|
|
func txHashInBlock(client *rpc.Client, hashmap map[libcommon.Hash]bool, blockNumber string, txToBlockMap map[libcommon.Hash]string, logger log.Logger) (uint64, int, error) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel() // releases the resources held by the context
|
|
|
|
var (
|
|
currBlock models.Block
|
|
numFound int
|
|
)
|
|
err := client.CallContext(ctx, &currBlock, string(requests.Methods.ETHGetBlockByNumber), blockNumber, false)
|
|
if err != nil {
|
|
return uint64(0), 0, fmt.Errorf("failed to get block by number: %v", err)
|
|
}
|
|
|
|
for _, txnHash := range currBlock.Transactions {
|
|
// check if tx is in the hash set and remove it from the set if it is present
|
|
if _, ok := hashmap[txnHash]; ok {
|
|
numFound++
|
|
logger.Info("SUCCESS => Tx included into block", "txHash", txnHash, "blockNum", blockNumber)
|
|
// add the block number as an entry to the map
|
|
txToBlockMap[txnHash] = blockNumber
|
|
delete(hashmap, txnHash)
|
|
if len(hashmap) == 0 {
|
|
return requests.HexToInt(blockNumber), numFound, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
return uint64(0), 0, nil
|
|
}
|
|
|
|
// EmitFallbackEvent emits an event from the contract using the fallback method
|
|
func EmitFallbackEvent(node *node.Node, subContract *contracts.Subscription, opts *bind.TransactOpts, logger log.Logger) (*libcommon.Hash, error) {
|
|
logger.Info("EMITTING EVENT FROM FALLBACK...")
|
|
|
|
// adding one to the nonce before initiating another transaction
|
|
opts.Nonce.Add(opts.Nonce, big.NewInt(1))
|
|
|
|
tx, err := subContract.Fallback(opts, []byte{})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to emit event from fallback: %v", err)
|
|
}
|
|
|
|
signedTx, err := types.SignTx(tx, *signer, models.DevSignedPrivateKey)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to sign fallback transaction: %v", err)
|
|
}
|
|
|
|
hash, err := node.SendTransaction(&signedTx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to send fallback transaction: %v", err)
|
|
}
|
|
|
|
return hash, nil
|
|
}
|
|
|
|
func BaseFeeFromBlock(node *node.Node, logger log.Logger) (uint64, error) {
|
|
var val uint64
|
|
res, err := node.GetBlockByNumberDetails("latest", false)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to get base fee from block: %v\n", err)
|
|
}
|
|
|
|
if v, ok := res["baseFeePerGas"]; !ok {
|
|
return val, fmt.Errorf("baseFeePerGas field missing from response")
|
|
} else {
|
|
val = requests.HexToInt(v.(string))
|
|
}
|
|
|
|
return val, err
|
|
}
|
|
|
|
func SendManyTransactions(node *node.Node, signedTransactions []*types.Transaction, logger log.Logger) ([]*libcommon.Hash, error) {
|
|
logger.Info("Sending multiple transactions to the txpool...")
|
|
hashes := make([]*libcommon.Hash, len(signedTransactions))
|
|
|
|
for idx, tx := range signedTransactions {
|
|
hash, err := node.SendTransaction(tx)
|
|
if err != nil {
|
|
logger.Error("failed SendTransaction", "error", err)
|
|
return nil, err
|
|
}
|
|
hashes[idx] = hash
|
|
}
|
|
|
|
return hashes, nil
|
|
}
|