Skip to content

Commit

Permalink
Devnet Test for EIP1559 (erigontech#6938)
Browse files Browse the repository at this point in the history
**Current Problem**

When X transactions are created, with M transactions out of them having
`gasFeeCap` greater than the current `baseFeePerGas` for the block, and
N transactions having `gasFeeCap` lower, all X transactions get added to
the yellow pool (baseFee) in the txpool and they never get mined.
However when X transactions all having `gasFeeCap` higher than the
`baseFeePerGas` are created, they all get added to the green pool
(pending) in the txpool and thus get mined.

This phenomenon can be inspected in the
`signEIP1559TxsLowerAndHigherThanBaseFee2` function where the number of
transactions that should have `gasFeeCap` higher than and lower than the
current `baseFeePerGas` is specified in its parameter - `func
signEIP1559TxsLowerAndHigherThanBaseFee2(amountLower, amountHigher
int...`.
When `amountLower` is set as `0`, all transactions created from
`amountHigher` will be mined because they have `gasFeeCap` >
`baseFeePerGas`. When `amountLower` has a value > `0`, all the
transactions created (including transactions created with
`amountHigher`) will go to the yellow pool (baseFee) and thus do not get
mined.
  • Loading branch information
leonardchinonso authored Mar 2, 2023
1 parent 3a25fb4 commit 599fc24
Show file tree
Hide file tree
Showing 10 changed files with 282 additions and 97 deletions.
17 changes: 13 additions & 4 deletions cmd/devnet/commands/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,24 @@ func ExecuteAllMethods() {
//}
//fmt.Println()

// initiate a contract transaction
fmt.Println("INITIATING A CONTRACT TRANSACTION...")
_, err := callContractTx()
// USING DYNAMIC FEE
// send a token from the dev address to the recipient address
_, err := callSendTxWithDynamicFee(recipientAddress, models.DevAddress)
if err != nil {
fmt.Printf("callContractTx error: %v\n", err)
fmt.Printf("callSendTxWithDynamicFee error: %v\n", err)
return
}
fmt.Println()

// initiate a contract transaction
//fmt.Println("INITIATING A CONTRACT TRANSACTION...")
//_, err := callContractTx()
//if err != nil {
// fmt.Printf("callContractTx error: %v\n", err)
// return
//}
//fmt.Println()

fmt.Print("SEND SIGNAL TO QUIT ALL RUNNING NODES")
models.QuitNodeChan <- true
}
50 changes: 46 additions & 4 deletions cmd/devnet/commands/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import (
"fmt"

libcommon "github.com/ledgerwatch/erigon-lib/common"

"github.com/ledgerwatch/erigon/cmd/devnet/devnetutils"

"github.com/ledgerwatch/erigon/cmd/devnet/models"
"github.com/ledgerwatch/erigon/cmd/devnet/requests"
"github.com/ledgerwatch/erigon/cmd/devnet/services"
Expand Down Expand Up @@ -52,10 +50,49 @@ func callSendTx(value uint64, toAddr, fromAddr string) (*libcommon.Hash, error)
return hash, nil
}

func callSendTxWithDynamicFee(toAddr, fromAddr string) ([]*libcommon.Hash, error) {
// get the latest nonce for the next transaction
nonce, err := services.GetNonce(models.ReqId, libcommon.HexToAddress(fromAddr))
if err != nil {
fmt.Printf("failed to get latest nonce: %s\n", err)
return nil, err
}

lowerThanBaseFeeTxs, higherThanBaseFeeTxs, err := services.CreateManyEIP1559TransactionsRefWithBaseFee(toAddr, &nonce)
if err != nil {
fmt.Printf("failed CreateManyEIP1559TransactionsRefWithBaseFee: %s\n", err)
return nil, err
}

lowerThanBaseFeeHashlist, err := services.SendManyTransactions(lowerThanBaseFeeTxs)
if err != nil {
fmt.Printf("failed SendManyTransactions(lowerThanBaseFeeTxs): %s\n", err)
return nil, err
}

higherThanBaseFeeHashlist, err := services.SendManyTransactions(higherThanBaseFeeTxs)
if err != nil {
fmt.Printf("failed SendManyTransactions(higherThanBaseFeeTxs): %s\n", err)
return nil, err
}

services.CheckTxPoolContent(2, 0)

hashmap := make(map[libcommon.Hash]bool)
for _, hash := range higherThanBaseFeeHashlist {
hashmap[*hash] = true
}

if _, err = services.SearchReservesForTransactionHash(hashmap); err != nil {
return nil, fmt.Errorf("failed to call contract tx: %v", err)
}

return append(lowerThanBaseFeeHashlist, higherThanBaseFeeHashlist...), nil
}

func callContractTx() (*libcommon.Hash, error) {
// hashset to hold hashes for search after mining
hashes := make(map[libcommon.Hash]bool)

// get the latest nonce for the next transaction
nonce, err := services.GetNonce(models.ReqId, libcommon.HexToAddress(models.DevAddress))
if err != nil {
Expand All @@ -80,7 +117,7 @@ func callContractTx() (*libcommon.Hash, error) {
fmt.Printf("SUCCESS => Tx submitted, adding tx with hash %q to txpool\n", hash)
fmt.Println()

eventHash, err := services.EmitFallbackEvent(models.ReqId, subscriptionContract, transactOpts, address)
eventHash, err := services.EmitFallbackEvent(subscriptionContract, transactOpts)
if err != nil {
fmt.Printf("failed to emit events: %v\n", err)
return nil, err
Expand Down Expand Up @@ -109,3 +146,8 @@ func callContractTx() (*libcommon.Hash, error) {

return hash, nil
}

func makeEIP1559Checks() {
// run the check for baseFee effect twice

}
25 changes: 18 additions & 7 deletions cmd/devnet/devnetutils/utils.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
package devnetutils

import (
"crypto/rand"
"encoding/json"
"fmt"
"os/exec"
"strconv"
"strings"

libcommon "github.com/ledgerwatch/erigon-lib/common"

"github.com/ledgerwatch/erigon/cmd/devnet/models"
"github.com/ledgerwatch/erigon/cmd/rpctest/rpctest"
"github.com/ledgerwatch/erigon/common/hexutil"
"github.com/ledgerwatch/erigon/crypto"

"github.com/ledgerwatch/erigon/cmd/devnet/models"
"math/big"
"os/exec"
"strconv"
"strings"
)

// ClearDevDB cleans up the dev folder used for the operations
Expand Down Expand Up @@ -155,3 +154,15 @@ func GenerateTopic(signature string) []libcommon.Hash {
hashed := crypto.Keccak256([]byte(signature))
return []libcommon.Hash{libcommon.BytesToHash(hashed)}
}

// RandomNumberInRange returns a random number between min and max NOT inclusive
func RandomNumberInRange(min, max uint64) (uint64, error) {
diff := int64(max - min)

n, err := rand.Int(rand.Reader, big.NewInt(diff))
if err != nil {
return 0, err
}

return uint64(n.Int64() + int64(min)), nil
}
14 changes: 12 additions & 2 deletions cmd/devnet/models/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"

libcommon "github.com/ledgerwatch/erigon-lib/common"

"github.com/ledgerwatch/erigon/accounts/abi/bind/backends"
"github.com/ledgerwatch/erigon/cmd/rpctest/rpctest"
"github.com/ledgerwatch/erigon/common/hexutil"
Expand Down Expand Up @@ -39,6 +38,8 @@ const (
ConsoleVerbosityArg = "--log.console.verbosity"
// LogDirArg is the log.dir.path flag
LogDirArg = "--log.dir.path"
// TorrentPortArg is the --torrent.port flag argument
TorrentPortArg = "--torrent.port"
// Mine is the mine flag
Mine = "--mine"
// NoDiscover is the nodiscover flag
Expand All @@ -62,12 +63,14 @@ const (
ConsoleVerbosityParam = "0"
// LogDirParam is the log directory parameter for logging to disk
LogDirParam = "./cmd/devnet/debug_logs"
// TorrentPortParam is the port parameter for the second node
TorrentPortParam = "42070"
// PrivateApiParamMine is the private.api.addr parameter for the mining node
PrivateApiParamMine = "localhost:9090"
// PrivateApiParamNoMine is the private.api.addr parameter for the non-mining node
PrivateApiParamNoMine = "localhost:9091"
// HttpApiParam is the http.api default parameter for rpcdaemon
HttpApiParam = "admin,eth,erigon,web3,net,debug,trace,txpool,parity"
HttpApiParam = "admin,eth,erigon,web3,net,debug,trace,txpool,parity,ots"

// ErigonUrl is the default url for rpc connections
ErigonUrl = "http://localhost:8545"
Expand Down Expand Up @@ -95,6 +98,8 @@ const (
NonContractTx TransactionType = "non-contract"
// ContractTx is the transaction type for sending ether
ContractTx TransactionType = "contract"
// DynamicFee is the transaction type for dynamic fee
DynamicFee TransactionType = "dynamic-fee"

// SolContractMethodSignature is the function signature for the event in the solidity contract definition
SolContractMethodSignature = "SubscriptionEvent()"
Expand All @@ -107,13 +112,18 @@ const (
ETHSendRawTransaction RPCMethod = "eth_sendRawTransaction"
// ETHGetBlockByNumber represents the eth_getBlockByNumber method
ETHGetBlockByNumber RPCMethod = "eth_getBlockByNumber"
// ETHGetBlock represents the eth_getBlock method
ETHGetBlock RPCMethod = "eth_getBlock"
// ETHGetLogs represents the eth_getLogs method
ETHGetLogs RPCMethod = "eth_getLogs"
// AdminNodeInfo represents the admin_nodeInfo method
AdminNodeInfo RPCMethod = "admin_nodeInfo"
// TxpoolContent represents the txpool_content method
TxpoolContent RPCMethod = "txpool_content"

// OTSGetBlockDetails represents the ots_getBlockDetails method
OTSGetBlockDetails RPCMethod = "ots_getBlockDetails"

// ETHNewHeads represents the eth_newHeads sub method
ETHNewHeads SubMethod = "eth_newHeads"
)
Expand Down
3 changes: 2 additions & 1 deletion cmd/devnet/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,9 @@ func nonMiningNodeArgs(nodeNumber int, enode string) []string {
staticPeers, _ := models.ParameterFromArgument(models.StaticPeersArg, enode)
consoleVerbosity, _ := models.ParameterFromArgument(models.ConsoleVerbosityArg, models.ConsoleVerbosityParam)
logDir, _ := models.ParameterFromArgument(models.LogDirArg, models.LogDirParam+"/node_2")
torrentPort, _ := models.ParameterFromArgument(models.TorrentPortArg, models.TorrentPortParam)

return []string{models.BuildDirArg, dataDir, chainType, privateApiAddr, staticPeers, models.NoDiscover, consoleVerbosity, logDir}
return []string{models.BuildDirArg, dataDir, chainType, privateApiAddr, staticPeers, models.NoDiscover, consoleVerbosity, logDir, torrentPort}
}

// getEnode returns the enode of the mining node
Expand Down
26 changes: 26 additions & 0 deletions cmd/devnet/requests/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,32 @@ func GetBlockByNumber(reqId int, blockNum uint64, withTxs bool) (rpctest.EthBloc
return b, nil
}

func GetBlockByNumberDetails(reqId int, blockNum string, withTxs bool) (map[string]interface{}, error) {
reqGen := initialiseRequestGenerator(reqId)
var b struct {
rpctest.CommonResponse
Result interface{} `json:"result"`
}

req := reqGen.GetBlockByNumberI(blockNum, withTxs)

res := reqGen.Erigon(models.ETHGetBlockByNumber, req, &b)
if res.Err != nil {
return nil, fmt.Errorf("error getting block by number: %v", res.Err)
}

if b.Error != nil {
return nil, fmt.Errorf("error populating response object: %v", b.Error)
}

m, ok := b.Result.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("cannot convert type")
}

return m, nil
}

func GetTransactionCount(reqId int, address libcommon.Address, blockNum models.BlockNumber) (rpctest.EthGetTransactionCount, error) {
reqGen := initialiseRequestGenerator(reqId)
var b rpctest.EthGetTransactionCount
Expand Down
10 changes: 10 additions & 0 deletions cmd/devnet/requests/request_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ func (req *RequestGenerator) GetBlockByNumber(blockNum uint64, withTxs bool) str
return fmt.Sprintf(template, models.ETHGetBlockByNumber, blockNum, withTxs, req.reqID)
}

func (req *RequestGenerator) GetBlockByNumberI(blockNum string, withTxs bool) string {
const template = `{"jsonrpc":"2.0","method":%q,"params":["%s",%t],"id":%d}`
return fmt.Sprintf(template, models.ETHGetBlockByNumber, blockNum, withTxs, req.reqID)
}

func (req *RequestGenerator) GetLogs(fromBlock, toBlock uint64, address libcommon.Address) string {
const template = `{"jsonrpc":"2.0","method":%q,"params":[{"fromBlock":"0x%x","toBlock":"0x%x","address":"0x%x"}],"id":%d}`
return fmt.Sprintf(template, models.ETHGetLogs, fromBlock, toBlock, address, req.reqID)
Expand All @@ -103,6 +108,11 @@ func (req *RequestGenerator) TxpoolContent() string {
return fmt.Sprintf(template, models.TxpoolContent, req.reqID)
}

func (req *RequestGenerator) GetBlockDetails(blockNum string) string {
const template = `{"jsonrpc":"2.0","method":%q,"params":["%s"],"id":%d}`
return fmt.Sprintf(template, models.OTSGetBlockDetails, blockNum, req.reqID)
}

func (req *RequestGenerator) PingErigonRpc() rpctest.CallResult {
start := time.Now()
res := rpctest.CallResult{
Expand Down
Loading

0 comments on commit 599fc24

Please sign in to comment.