Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jesse/loadtest legacy mode #92

Merged
merged 30 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a19d196
default to dynamic tx with legacy flag as option
gatsbyz Jun 26, 2023
d2a5014
uncomment nonce
gatsbyz Jun 26, 2023
6e2285f
suggest gas tip cap and calculate fee cap
gatsbyz Jun 26, 2023
1322373
use london signer
gatsbyz Jun 26, 2023
c851d1f
remove test line
gatsbyz Jun 26, 2023
ac95579
only legacy mode control force gas price
gatsbyz Jun 26, 2023
105a1d6
pass in legacy flag to wisely force gas prices
gatsbyz Jun 26, 2023
0848f13
remove redundant option configure call & refractor
gatsbyz Jun 28, 2023
290803c
remove some redundant arguments
gatsbyz Jun 28, 2023
04d51bf
clean up
gatsbyz Jun 28, 2023
04e19a4
use transactOpts function to determine signer
gatsbyz Jun 28, 2023
48024aa
remove header stuff
gatsbyz Jun 28, 2023
08423e3
just use transact opts
gatsbyz Jun 28, 2023
2372100
push
gatsbyz Jun 28, 2023
2b8778c
minor fix: legacy mode and priority gas fee
gatsbyz Jun 28, 2023
404bc56
revert fuzz
gatsbyz Jun 28, 2023
7bca43b
variable name change for lint
gatsbyz Jun 28, 2023
ada49f5
remove error catch
gatsbyz Jun 29, 2023
3abfe68
gas tip price estimation only for non legacy
gatsbyz Jun 29, 2023
f822912
lint :)
gatsbyz Jun 29, 2023
b923b60
hello
gatsbyz Jun 29, 2023
da3148b
swap again
gatsbyz Jun 29, 2023
8f1a55e
real gucci
gatsbyz Jun 29, 2023
e5ca5dc
real fix
gatsbyz Jun 29, 2023
925470e
feat: adding tx type to monitor
praetoriansentry Jun 29, 2023
305577d
Jesse/loadtest chain id query (#95)
gatsbyz Jun 29, 2023
d48dadd
last changes for logic
gatsbyz Jun 29, 2023
9738186
gas price logic
gatsbyz Jun 29, 2023
ed0432d
remove empty if statement
gatsbyz Jun 30, 2023
938396a
1559 aware monitor variables (#97)
gatsbyz Jun 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 91 additions & 19 deletions cmd/loadtest/loadtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"crypto/ecdsa"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"math"
Expand Down Expand Up @@ -153,8 +154,6 @@ var LoadtestCmd = &cobra.Command{
Short: "A simple script for quickly running a load test",
Long: `Loadtest gives us a simple way to run a generic load test against an eth/EVM style json RPC endpoint`,
RunE: func(cmd *cobra.Command, args []string) error {
log.Debug().Msg("Starting Loadtest")

err := runLoadTest(cmd.Context())
if err != nil {
return err
Expand Down Expand Up @@ -236,16 +235,20 @@ type (
ForceContractDeploy *bool
ForceGasLimit *uint64
ForceGasPrice *uint64
ForcePriorityGasPrice *uint64
ShouldProduceSummary *bool
SummaryOutputMode *string
LegacyTransactionMode *bool

// Computed
CurrentGas *big.Int
CurrentNonce *uint64
ECDSAPrivateKey *ecdsa.PrivateKey
FromETHAddress *ethcommon.Address
ToETHAddress *ethcommon.Address
SendAmount *big.Int
CurrentGas *big.Int
CurrentGasTipCap *big.Int
CurrentNonce *uint64
ECDSAPrivateKey *ecdsa.PrivateKey
FromETHAddress *ethcommon.Address
ToETHAddress *ethcommon.Address
SendAmount *big.Int
BaseFee *big.Int

ToAvailAddress *gstypes.MultiAddress
FromAvailAddress *gssignature.KeyringPair
Expand All @@ -268,7 +271,7 @@ func init() {

// extended parameters
ltp.PrivateKey = LoadtestCmd.PersistentFlags().String("private-key", codeQualityPrivateKey, "The hex encoded private key that we'll use to sending transactions")
ltp.ChainID = LoadtestCmd.PersistentFlags().Uint64("chain-id", 1256, "The chain id for the transactions that we're going to send")
ltp.ChainID = LoadtestCmd.PersistentFlags().Uint64("chain-id", 0, "The chain id for the transactions that we're going to send")
ltp.ToAddress = LoadtestCmd.PersistentFlags().String("to-address", "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", "The address that we're going to send to")
ltp.ToRandom = LoadtestCmd.PersistentFlags().Bool("to-random", false, "When doing a transfer test, should we send to random addresses rather than DEADBEEFx5")
ltp.HexSendAmount = LoadtestCmd.PersistentFlags().String("send-amount", "0x38D7EA4C68000", "The amount of wei that we'll send every transaction")
Expand Down Expand Up @@ -302,9 +305,11 @@ r - random modes
ltp.ForceContractDeploy = LoadtestCmd.PersistentFlags().Bool("force-contract-deploy", false, "Some loadtest modes don't require a contract deployment. Set this flag to true to force contract deployments. This will still respect the --del-address and --il-address flags.")
ltp.ForceGasLimit = LoadtestCmd.PersistentFlags().Uint64("gas-limit", 0, "In environments where the gas limit can't be computed on the fly, we can specify it manually")
ltp.ForceGasPrice = LoadtestCmd.PersistentFlags().Uint64("gas-price", 0, "In environments where the gas price can't be estimated, we can specify it manually")
ltp.ForcePriorityGasPrice = LoadtestCmd.PersistentFlags().Uint64("priority-gas-price", 0, "Specify Gas Tip Price in the case of EIP-1559")
ltp.ShouldProduceSummary = LoadtestCmd.PersistentFlags().Bool("summarize", false, "Should we produce an execution summary after the load test has finished. If you're running a large loadtest, this can take a long time")
ltp.BatchSize = LoadtestCmd.PersistentFlags().Uint64("batch-size", 999, "Number of batches to perform at a time for receipt fetching. Default is 999 requests at a time.")
ltp.SummaryOutputMode = LoadtestCmd.PersistentFlags().String("output-mode", "text", "Format mode for summary output (json | text)")
ltp.LegacyTransactionMode = LoadtestCmd.PersistentFlags().Bool("legacy", false, "Send a legacy transaction instead of an EIP1559 transaction.")
inputLoadTestParams = *ltp

// TODO batch size
Expand All @@ -321,6 +326,16 @@ func initializeLoadTestParams(ctx context.Context, c *ethclient.Client) error {
}
log.Trace().Interface("gasprice", gas).Msg("Retreived current gas price")

if !*inputLoadTestParams.LegacyTransactionMode {
gasTipCap, _err := c.SuggestGasTipCap(ctx)
if _err != nil {
log.Error().Err(_err).Msg("Unable to retrieve gas tip cap")
return _err
}
log.Trace().Interface("gastipcap", gasTipCap).Msg("Retreived current gas tip cap")
inputLoadTestParams.CurrentGasTipCap = gasTipCap
}

privateKey, err := ethcrypto.HexToECDSA(*inputLoadTestParams.PrivateKey)
if err != nil {
log.Error().Err(err).Msg("Couldn't process the hex private key")
Expand Down Expand Up @@ -357,12 +372,37 @@ func initializeLoadTestParams(ctx context.Context, c *ethclient.Client) error {
return err
}

header, err := c.HeaderByNumber(ctx, nil)
if err != nil {
log.Error().Err(err).Msg("Unable to get header")
return err
}

chainID, err := c.ChainID(ctx)
if err != nil {
log.Error().Err(err).Msg("Unable to fetch chain ID")
return err
}
log.Trace().Uint64("chainID", chainID.Uint64()).Msg("Detected Chain ID")

if *inputLoadTestParams.LegacyTransactionMode && *inputLoadTestParams.ForcePriorityGasPrice > 0 {
log.Warn().Msg("Cannot set priority gas price in legacy mode")
}
if *inputLoadTestParams.ForceGasPrice < *inputLoadTestParams.ForcePriorityGasPrice {
log.Error().Msg("Max priority fee per gas higher than max fee per gas")
return errors.New("max priority fee per gas higher than max fee per gas")
}

inputLoadTestParams.ToETHAddress = &toAddr
inputLoadTestParams.SendAmount = amt
inputLoadTestParams.CurrentGas = gas
inputLoadTestParams.CurrentNonce = &nonce
inputLoadTestParams.ECDSAPrivateKey = privateKey
inputLoadTestParams.FromETHAddress = &ethAddress
if *inputLoadTestParams.ChainID == 0 {
*inputLoadTestParams.ChainID = chainID.Uint64()
}
inputLoadTestParams.BaseFee = header.BaseFee

rand.Seed(*inputLoadTestParams.Seed)

Expand Down Expand Up @@ -427,7 +467,6 @@ func runLoadTest(ctx context.Context) error {
}

} else {
log.Info().Msg("Starting Load Test")
loopFunc = func() error {
err = initializeLoadTestParams(ctx, ec)
if err != nil {
Expand Down Expand Up @@ -667,8 +706,6 @@ func mainLoop(ctx context.Context, c *ethclient.Client, rpc *ethrpc.Client) erro
}

tops.Nonce = new(big.Int).SetUint64(currentNonce)
tops = configureTransactOpts(tops)
tops.GasLimit = 10000000

_, err = erc20Contract.Mint(tops, metrics.UnitMegaether)
if err != nil {
Expand Down Expand Up @@ -720,8 +757,6 @@ func mainLoop(ctx context.Context, c *ethclient.Client, rpc *ethrpc.Client) erro
}

tops.Nonce = new(big.Int).SetUint64(currentNonce)
tops = configureTransactOpts(tops)
tops.GasLimit = 10000000

err = blockUntilSuccessful(ctx, c, func() error {
_, err = erc721Contract.MintBatch(tops, *ltp.FromETHAddress, new(big.Int).SetUint64(1))
Expand Down Expand Up @@ -952,8 +987,6 @@ func blockUntilSuccessful(ctx context.Context, c *ethclient.Client, f func() err
func loadtestTransaction(ctx context.Context, c *ethclient.Client, nonce uint64) (t1 time.Time, t2 time.Time, err error) {
ltp := inputLoadTestParams

gasPrice := ltp.CurrentGas

to := ltp.ToETHAddress
if *ltp.ToRandom {
to = getRandomAddress()
Expand All @@ -963,9 +996,34 @@ func loadtestTransaction(ctx context.Context, c *ethclient.Client, nonce uint64)
chainID := new(big.Int).SetUint64(*ltp.ChainID)
privateKey := ltp.ECDSAPrivateKey

gasLimit := uint64(21000)
tx := ethtypes.NewTransaction(nonce, *to, amount, gasLimit, gasPrice, nil)
stx, err := ethtypes.SignTx(tx, ethtypes.NewEIP155Signer(chainID), privateKey)
tops, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID)
if err != nil {
gatsbyz marked this conversation as resolved.
Show resolved Hide resolved
log.Error().Err(err).Msg("Unable create transaction signer")
return
}
tops.GasLimit = uint64(21000)
tops = configureTransactOpts(tops)

var tx *ethtypes.Transaction
if *ltp.LegacyTransactionMode {
tx = ethtypes.NewTransaction(nonce, *to, amount, tops.GasLimit, tops.GasPrice, nil)
} else {
gasTipCap := tops.GasTipCap
gasFeeCap := new(big.Int).Add(gasTipCap, ltp.BaseFee)
dynamicFeeTx := &ethtypes.DynamicFeeTx{
ChainID: chainID,
Nonce: nonce,
To: to,
Gas: tops.GasLimit,
GasFeeCap: gasFeeCap,
GasTipCap: gasTipCap,
Data: nil,
Value: amount,
}
tx = ethtypes.NewTx(dynamicFeeTx)
}

stx, err := tops.Signer(*ltp.FromETHAddress, tx)
if err != nil {
log.Error().Err(err).Msg("Unable to sign transaction")
return
Expand Down Expand Up @@ -1490,6 +1548,20 @@ func configureTransactOpts(tops *bind.TransactOpts) *bind.TransactOpts {
ltp := inputLoadTestParams
if ltp.ForceGasPrice != nil && *ltp.ForceGasPrice != 0 {
tops.GasPrice = big.NewInt(0).SetUint64(*ltp.ForceGasPrice)
} else {
tops.GasPrice = ltp.CurrentGas
}
if !*ltp.LegacyTransactionMode {
if ltp.ForceGasPrice != nil && *ltp.ForceGasPrice != 0 {
tops.GasPrice = big.NewInt(0).SetUint64(*ltp.ForceGasPrice)
} else {
tops.GasPrice = big.NewInt(0).Add(ltp.BaseFee, ltp.CurrentGasTipCap)
}
if ltp.ForcePriorityGasPrice != nil && *ltp.ForcePriorityGasPrice != 0 {
tops.GasTipCap = big.NewInt(0).SetUint64(*ltp.ForcePriorityGasPrice)
} else {
tops.GasTipCap = ltp.CurrentGasTipCap
}
}
if ltp.ForceGasLimit != nil && *ltp.ForceGasLimit != 0 {
tops.GasLimit = *ltp.ForceGasLimit
Expand Down
3 changes: 3 additions & 0 deletions metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,10 @@ func GetSimpleTxFields(tx rpctypes.PolyTransaction, chainID, baseFee *big.Int) [
fields = append(fields, fmt.Sprintf("Value: %s", tx.Value()))
fields = append(fields, fmt.Sprintf("Gas Limit: %d", tx.Gas()))
fields = append(fields, fmt.Sprintf("Gas Price: %s", tx.GasPrice()))
fields = append(fields, fmt.Sprintf("Gas Tip: %d", tx.MaxPriorityFeePerGas()))
fields = append(fields, fmt.Sprintf("Gas Fee: %d", tx.MaxFeePerGas()))
fields = append(fields, fmt.Sprintf("Nonce: %d", tx.Nonce()))
fields = append(fields, fmt.Sprintf("Type: %d", tx.Type()))
fields = append(fields, fmt.Sprintf("Data Len: %d", len(tx.Data())))
fields = append(fields, fmt.Sprintf("Data: %s", hex.EncodeToString(tx.Data())))

Expand Down
18 changes: 18 additions & 0 deletions rpctypes/rpctypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ type (
// gasPrice: QUANTITY - gas price provided by the sender in Wei.
GasPrice RawQuantityResponse `json:"gasPrice"`

// gas: QUANTITY - gas provided by the sender.
MaxPriorityFeePerGas RawQuantityResponse `json:"maxPriorityFeePerGas"`

// gas: QUANTITY - gas provided by the sender.
MaxFeePerGas RawQuantityResponse `json:"maxFeePerGas"`

// hash: DATA, 32 Bytes - hash of the transaction.
Hash RawData32Response `json:"hash"`

Expand Down Expand Up @@ -215,6 +221,9 @@ type (
Nonce() uint64
String() string
MarshalJSON() ([]byte, error)
Type() uint64
MaxPriorityFeePerGas() uint64
MaxFeePerGas() uint64
V() *big.Int
R() *big.Int
S() *big.Int
Expand Down Expand Up @@ -342,9 +351,18 @@ func (i *implPolyTransaction) GasPrice() *big.Int {
func (i *implPolyTransaction) Gas() uint64 {
return i.inner.Gas.ToUint64()
}
func (i *implPolyTransaction) MaxPriorityFeePerGas() uint64 {
return i.inner.MaxPriorityFeePerGas.ToUint64()
}
func (i *implPolyTransaction) MaxFeePerGas() uint64 {
return i.inner.MaxFeePerGas.ToUint64()
}
func (i *implPolyTransaction) Nonce() uint64 {
return i.inner.Nonce.ToUint64()
}
func (i *implPolyTransaction) Type() uint64 {
return i.inner.Type.ToUint64()
}
func (i *implPolyTransaction) Value() *big.Int {
return i.inner.Value.ToBigInt()
}
Expand Down