Skip to content

Commit

Permalink
Merge branch 'main' into feat/contract-signature-encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
IdrisHanafi authored Jan 2, 2024
2 parents 560f741 + 0b50d8d commit a059254
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 85 deletions.
7 changes: 5 additions & 2 deletions cmd/loadtest/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ type (
ContractAddress *string
ContractCallData *string
ContractCallPayable *bool
InscriptionContent *string

// Computed
CurrentGasPrice *big.Int
Expand Down Expand Up @@ -242,7 +243,8 @@ r - random modes
v3 - UniswapV3 swaps
R - total recall
rpc - call random rpc methods
cc, contract-call - call a contract method`)
cc, contract-call - call a contract method
inscription - sending inscription transactions`)
ltp.Function = LoadtestCmd.Flags().Uint64P("function", "f", 1, "A specific function to be called if running with `--mode f` or a specific precompiled contract when running with `--mode a`")
ltp.ByteCount = LoadtestCmd.Flags().Uint64P("byte-count", "b", 1024, "If we're in store mode, this controls how many bytes we'll try to store in our contract")
ltp.LtAddress = LoadtestCmd.Flags().String("lt-address", "", "The address of a pre-deployed load test contract")
Expand All @@ -252,7 +254,8 @@ cc, contract-call - call a contract method`)
ltp.RecallLength = LoadtestCmd.Flags().Uint64("recall-blocks", 50, "The number of blocks that we'll attempt to fetch for recall")
ltp.ContractAddress = LoadtestCmd.Flags().String("contract-address", "", "The address of the contract that will be used in `--mode contract-call`. This must be paired up with `--mode contract-call` and `--calldata`")
ltp.ContractCallData = LoadtestCmd.Flags().String("calldata", "", "The hex encoded calldata passed in. The format is function signature + arguments encoded together. This must be paired up with `--mode contract-call` and `--contract-address`")
ltp.ContractCallPayable = LoadtestCmd.Flags().Bool("contract-call-payable", false, "Use this flag if the `--function-sig` is a `payable` function, the value amount passed will be from `--eth-amount`. This must be paired up with `--mode contract-call` and `--contract-address`")
ltp.ContractCallPayable = LoadtestCmd.Flags().Bool("contract-call-payable", false, "Use this flag if the function is payable, the value amount passed will be from `--eth-amount`. This must be paired up with `--mode contract-call` and `--contract-address`")
ltp.InscriptionContent = LoadtestCmd.Flags().String("inscription-content", `data:,{"p":"erc-20","op":"mint","tick":"TEST","amt":"1"}`, "The inscription content that will be encoded as calldata. This must be paired up with `--mode inscription`")

inputLoadTestParams = *ltp

Expand Down
101 changes: 94 additions & 7 deletions cmd/loadtest/loadtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const (
loadTestModeRecall
loadTestModeRPC
loadTestModeContractCall
loadTestModeInscription
loadTestModeUniswapV3

codeQualitySeed = "code code code code code code code code code code code quality"
Expand Down Expand Up @@ -96,6 +97,8 @@ func characterToLoadTestMode(mode string) (loadTestMode, error) {
return loadTestModeRPC, nil
case "cc", "contract-call":
return loadTestModeContractCall, nil
case "inscription":
return loadTestModeInscription, nil
default:
return 0, fmt.Errorf("unrecognized load test mode: %s", mode)
}
Expand Down Expand Up @@ -616,6 +619,8 @@ func mainLoop(ctx context.Context, c *ethclient.Client, rpc *ethrpc.Client) erro
startReq, endReq, tErr = loadTestRPC(ctx, c, myNonceValue, indexedActivity)
case loadTestModeContractCall:
startReq, endReq, tErr = loadTestContractCall(ctx, c, myNonceValue)
case loadTestModeInscription:
startReq, endReq, tErr = loadTestInscription(ctx, c, myNonceValue)
default:
log.Error().Str("mode", mode.String()).Msg("We've arrived at a load test mode that we don't recognize")
}
Expand Down Expand Up @@ -1276,18 +1281,100 @@ func loadTestContractCall(ctx context.Context, c *ethclient.Client, nonce uint64
log.Error().Err(err).Msg("Unable to decode calldata string")
return
}
estimateInput := ethereum.CallMsg{
From: *ltp.FromETHAddress,
To: to,
Value: amount,
Data: calldata,

if tops.GasLimit == 0 {
estimateInput := ethereum.CallMsg{
From: tops.From,
To: to,
Value: amount,
GasPrice: tops.GasPrice,
GasTipCap: tops.GasTipCap,
GasFeeCap: tops.GasFeeCap,
Data: calldata,
}
tops.GasLimit, err = c.EstimateGas(ctx, estimateInput)
if err != nil {
log.Error().Err(err).Msg("Unable to estimate gas for transaction. Manually setting gas-limit might be required")
return
}
}

var tx *ethtypes.Transaction
if *ltp.LegacyTransactionMode {
tx = ethtypes.NewTx(&ethtypes.LegacyTx{
Nonce: nonce,
To: to,
Value: amount,
Gas: tops.GasLimit,
GasPrice: gasPrice,
Data: calldata,
})
} else {
tx = ethtypes.NewTx(&ethtypes.DynamicFeeTx{
ChainID: chainID,
Nonce: nonce,
To: to,
Gas: tops.GasLimit,
GasFeeCap: gasPrice,
GasTipCap: gasTipCap,
Data: calldata,
Value: amount,
})
}
log.Trace().Interface("tx", tx).Msg("Contract call data")

stx, err := tops.Signer(*ltp.FromETHAddress, tx)
if err != nil {
log.Error().Err(err).Msg("Unable to sign transaction")
return
}

t1 = time.Now()
defer func() { t2 = time.Now() }()
if *ltp.CallOnly {
_, err = c.CallContract(ctx, txToCallMsg(stx), nil)
} else {
err = c.SendTransaction(ctx, stx)
}
tops.GasLimit, err = c.EstimateGas(ctx, estimateInput)
return
}

func loadTestInscription(ctx context.Context, c *ethclient.Client, nonce uint64) (t1 time.Time, t2 time.Time, err error) {
ltp := inputLoadTestParams

to := ltp.FromETHAddress

chainID := new(big.Int).SetUint64(*ltp.ChainID)
privateKey := ltp.ECDSAPrivateKey

tops, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID)
if err != nil {
log.Error().Err(err).Msg("Unable to estimate gas for transaction")
log.Error().Err(err).Msg("Unable create transaction signer")
return
}

amount := big.NewInt(0)
tops = configureTransactOpts(tops)
gasPrice, gasTipCap := getSuggestedGasPrices(ctx, c)

calldata := []byte(*ltp.InscriptionContent)
if tops.GasLimit == 0 {
estimateInput := ethereum.CallMsg{
From: tops.From,
To: to,
Value: amount,
GasPrice: tops.GasPrice,
GasTipCap: tops.GasTipCap,
GasFeeCap: tops.GasFeeCap,
Data: calldata,
}
tops.GasLimit, err = c.EstimateGas(ctx, estimateInput)
if err != nil {
log.Error().Err(err).Msg("Unable to estimate gas for transaction. Manually setting gas-limit might be required")
return
}
}

var tx *ethtypes.Transaction
if *ltp.LegacyTransactionMode {
tx = ethtypes.NewTx(&ethtypes.LegacyTx{
Expand Down
7 changes: 4 additions & 3 deletions cmd/loadtest/loadtestmode_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 24 additions & 8 deletions cmd/monitor/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,16 @@ const (
)

func monitor(ctx context.Context) error {
// Dial rpc.
rpc, err := ethrpc.DialContext(ctx, rpcUrl)
if err != nil {
log.Error().Err(err).Msg("Unable to dial rpc")
return err
}
ec := ethclient.NewClient(rpc)
if _, err = ec.BlockNumber(ctx); err != nil {
return err
}

// Check if batch requests are supported.
if err = checkBatchRequestsSupport(ctx, ec.Client()); err != nil {
Expand All @@ -98,7 +102,11 @@ func monitor(ctx context.Context) error {

ms := new(monitorStatus)
ms.BlocksLock.Lock()
ms.BlockCache, _ = lru.New(blockCacheLimit)
ms.BlockCache, err = lru.New(blockCacheLimit)
if err != nil {
log.Error().Err(err).Msg("Failed to create new LRU cache")
return err
}
ms.BlocksLock.Unlock()

ms.ChainID = big.NewInt(0)
Expand All @@ -109,6 +117,11 @@ func monitor(ctx context.Context) error {
isUiRendered := false
errChan := make(chan error)
go func() {
defer func() {
if r := recover(); r != nil {
log.Error().Msg(fmt.Sprintf("Recovered in f: %v", r))
}
}()
select {
case <-ctx.Done(): // listens for a cancellation signal
return // exit the goroutine when the context is done
Expand Down Expand Up @@ -192,7 +205,7 @@ func fetchBlocks(ctx context.Context, ec *ethclient.Client, ms *monitorStatus, r
}
observedPendingTxs = append(observedPendingTxs, historicalDataPoint{SampleTime: time.Now(), SampleValue: float64(cs.PendingCount)})
if len(observedPendingTxs) > maxDataPoints {
observedPendingTxs = observedPendingTxs[1:]
observedPendingTxs = observedPendingTxs[len(observedPendingTxs)-maxDataPoints:]
}

log.Debug().Uint64("PeerCount", cs.PeerCount).Uint64("ChainID", cs.ChainID.Uint64()).Uint64("HeadBlock", cs.HeadBlock).Uint64("GasPrice", cs.GasPrice.Uint64()).Msg("Fetching blocks")
Expand Down Expand Up @@ -225,10 +238,13 @@ func fetchBlocks(ctx context.Context, ec *ethclient.Client, ms *monitorStatus, r
}

func (ms *monitorStatus) getBlockRange(ctx context.Context, from, to *big.Int, rpc *ethrpc.Client) error {
ms.BlocksLock.Lock()
blms := make([]ethrpc.BatchElem, 0)
for i := new(big.Int).Set(from); i.Cmp(to) <= 0; i.Add(i, big.NewInt(1)) {
if _, found := ms.BlockCache.Get(i.String()); found {

for i := new(big.Int).Set(from); i.Cmp(to) <= 0; i.Add(i, one) {
ms.BlocksLock.RLock()
_, found := ms.BlockCache.Get(i.String())
ms.BlocksLock.RUnlock()
if found {
continue
}
r := new(rpctypes.RawBlockResponse)
Expand All @@ -239,7 +255,6 @@ func (ms *monitorStatus) getBlockRange(ctx context.Context, from, to *big.Int, r
Error: nil,
})
}
ms.BlocksLock.Unlock()

if len(blms) == 0 {
return nil
Expand Down Expand Up @@ -362,6 +377,7 @@ func setUISkeleton() (blockTable *widgets.List, grid *ui.Grid, blockGrid *ui.Gri

func renderMonitorUI(ctx context.Context, ec *ethclient.Client, ms *monitorStatus, rpc *ethrpc.Client) error {
if err := ui.Init(); err != nil {
log.Error().Err(err).Msg("Failed to initialize UI")
return err
}
defer ui.Close()
Expand Down Expand Up @@ -412,7 +428,7 @@ func renderMonitorUI(ctx context.Context, ec *ethclient.Client, ms *monitorStatu
fromBlockNumber.SetInt64(0) // We cannot have block numbers less than 0.
}
renderedBlocksTemp := make([]rpctypes.PolyBlock, 0, windowSize)
ms.BlocksLock.Lock()
ms.BlocksLock.RLock()
for i := new(big.Int).Set(fromBlockNumber); i.Cmp(toBlockNumber) <= 0; i.Add(i, big.NewInt(1)) {
if block, ok := ms.BlockCache.Get(i.String()); ok {
renderedBlocksTemp = append(renderedBlocksTemp, block.(rpctypes.PolyBlock))
Expand All @@ -421,7 +437,7 @@ func renderMonitorUI(ctx context.Context, ec *ethclient.Client, ms *monitorStatu
log.Warn().Str("blockNumber", i.String()).Msg("Block should be in cache but is not")
}
}
ms.BlocksLock.Unlock()
ms.BlocksLock.RUnlock()
renderedBlocks = renderedBlocksTemp

termUi.h0.Text = fmt.Sprintf("Height: %s\nTime: %s", ms.HeadBlock.String(), time.Now().Format("02 Jan 06 15:04:05 MST"))
Expand Down
Loading

0 comments on commit a059254

Please sign in to comment.