Update for testing with Merge fixturenet. #11
@ -10,8 +10,8 @@
|
||||
gasFeeCap = "1000000007" # gasFeeCap to use for the deployment txs - env: $ETH_DEPLOYMENT_GAS_FEE_CAP
|
||||
|
||||
[contractSpammer]
|
||||
frequency = 10 # how often to send a transaction (in milliseconds) - env: $ETH_CALL_FREQ
|
||||
totalNumber = 5000 # total number of transactions to send (per sender) - env: $ETH_CALL_TOTAL_NUMBER
|
||||
frequency = 0 # how often to send a transaction (in milliseconds) - env: $ETH_CALL_FREQ
|
||||
totalNumber = 500000 # total number of transactions to send (per sender) - env: $ETH_CALL_TOTAL_NUMBER
|
||||
abiPath = "sol/build/Test.abi" # path to the abi file for the contract we are calling - env: $ETH_CALL_ABI_PATH
|
||||
# NOTE: we expect to be calling a method such as Put(address addr, uint256 val) where the first argument is an
|
||||
# integer than we can increment to store values at new locations in the contract trie (to grow it) and
|
||||
@ -22,8 +22,8 @@
|
||||
gasFeeCap = "1000000007" # gasFeeCap to use for the eth call txs - env: $ETH_CALL_GAS_FEE_CAP
|
||||
|
||||
[sendSpammer]
|
||||
frequency = 50 # how often to send a transaction (in milliseconds) - env: $ETH_SEND_FREQ
|
||||
totalNumber = 1000 # total number of transactions to send (per sender) - env: $ETH_SEND_TOTAL_NUMBER
|
||||
frequency = 0 # how often to send a transaction (in milliseconds) - env: $ETH_SEND_FREQ
|
||||
totalNumber = 100000 # total number of transactions to send (per sender) - env: $ETH_SEND_TOTAL_NUMBER
|
||||
amount = "10000" # amount of wei (1x10^-18 ETH) to send in each tx (be mindful of the genesis allocations) - env: $ETH_SEND_AMOUNT
|
||||
gasLimit = 21000 # gasLimit to use for the eth transfer txs - env: $ETH_SEND_GAS_LIMIT
|
||||
gasTipCap = "1000000000" # gasTipCap to use for the eth transfer txs - env: $ETH_SEND_GAS_TIP_CAP
|
||||
|
@ -68,9 +68,6 @@ type Config struct {
|
||||
|
||||
// Configuration for the eth transfer txs
|
||||
SendConfig *SendConfig
|
||||
|
||||
// Configuration for EIP1559
|
||||
EIP1559Config *EIP1559Config
|
||||
}
|
||||
|
||||
// DeploymentConfig holds the parameters for the contract deployment contracts
|
||||
@ -108,13 +105,10 @@ type SendConfig struct {
|
||||
GasTipCap *big.Int
|
||||
Amount *big.Int
|
||||
|
||||
DestinationAddresses []common.Address
|
||||
Frequency time.Duration
|
||||
TotalNumber int
|
||||
}
|
||||
|
||||
// todo: EIP1559Config
|
||||
type EIP1559Config struct{}
|
||||
|
||||
func NewConfig() (*Config, error) {
|
||||
// Initialize rpc client
|
||||
httpPathStr := viper.GetString(ethHttpPath)
|
||||
@ -232,6 +226,15 @@ func NewCallConfig(chainID *big.Int) (*CallConfig, error) {
|
||||
if !exist {
|
||||
return nil, fmt.Errorf("method '%s' not found in provided abi", methodName)
|
||||
}
|
||||
|
||||
var frequency time.Duration
|
||||
tmpFreq := viper.GetInt(ethCallFrequency)
|
||||
if tmpFreq <= 0 {
|
||||
frequency = time.Microsecond
|
||||
} else {
|
||||
frequency = viper.GetDuration(ethCallFrequency) * time.Millisecond
|
||||
}
|
||||
|
||||
return &CallConfig{
|
||||
ChainID: chainID,
|
||||
GasLimit: viper.GetUint64(ethCallGasLimit),
|
||||
@ -239,7 +242,7 @@ func NewCallConfig(chainID *big.Int) (*CallConfig, error) {
|
||||
GasTipCap: big.NewInt(viper.GetInt64(ethCallGasTipCap)),
|
||||
MethodName: methodName,
|
||||
ABI: parsedABI,
|
||||
Frequency: viper.GetDuration(ethCallFrequency) * time.Millisecond,
|
||||
Frequency: frequency,
|
||||
TotalNumber: viper.GetInt(ethCallTotalNumber),
|
||||
}, nil
|
||||
}
|
||||
@ -251,18 +254,22 @@ func NewSendConfig(chainID *big.Int) (*SendConfig, error) {
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unable to convert amount string (%s) into big.Int", amountStr)
|
||||
}
|
||||
number := viper.GetUint64(ethSendTotalNumber)
|
||||
addrs := make([]common.Address, number)
|
||||
for i := uint64(0); i < number; i++ {
|
||||
addrs[i] = crypto.CreateAddress(receiverAddressSeed, i)
|
||||
|
||||
var frequency time.Duration
|
||||
tmpFreq := viper.GetInt(ethCallFrequency)
|
||||
if tmpFreq <= 0 {
|
||||
frequency = time.Microsecond
|
||||
} else {
|
||||
frequency = viper.GetDuration(ethCallFrequency) * time.Millisecond
|
||||
}
|
||||
|
||||
return &SendConfig{
|
||||
ChainID: chainID,
|
||||
DestinationAddresses: addrs,
|
||||
Frequency: viper.GetDuration(ethSendFrequency) * time.Millisecond,
|
||||
Frequency: frequency,
|
||||
Amount: amount,
|
||||
GasLimit: viper.GetUint64(ethSendGasLimit),
|
||||
GasFeeCap: big.NewInt(viper.GetInt64(ethSendGasFeeCap)),
|
||||
GasTipCap: big.NewInt(viper.GetInt64(ethSendGasTipCap)),
|
||||
TotalNumber: viper.GetInt(ethSendTotalNumber),
|
||||
}, nil
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ func NewEthSender(config *Config) *EthSender {
|
||||
}
|
||||
|
||||
// Send awaits txs off the provided work queue and sends them
|
||||
func (s *EthSender) Send(quitChan <-chan bool, txChan <-chan *types.Transaction) (<-chan bool, <-chan error) {
|
||||
func (s *EthSender) Send(quitChan <-chan bool, txChan <-chan *types.Transaction, sentCh chan *types.Transaction) (<-chan bool, <-chan error) {
|
||||
// err channel returned to calling context
|
||||
errChan := make(chan error)
|
||||
doneChan := make(chan bool)
|
||||
@ -49,6 +49,8 @@ func (s *EthSender) Send(quitChan <-chan bool, txChan <-chan *types.Transaction)
|
||||
counter += 1
|
||||
if err := shared.SendTransaction(s.client, tx); err != nil {
|
||||
errChan <- err
|
||||
} else {
|
||||
sentCh <- tx
|
||||
}
|
||||
case <-quitChan:
|
||||
logrus.Infof("quitting Send loop (sent %d)", counter)
|
||||
|
@ -50,10 +50,12 @@ func (s *Spammer) Loop(quitChan <-chan bool) (<-chan bool, error) {
|
||||
genQuit := make(chan bool)
|
||||
senderQuit := make(chan bool)
|
||||
doneChan := make(chan bool)
|
||||
watcher := NewTxWatcher(s.config.EthClient)
|
||||
watcher.Start()
|
||||
|
||||
s.config.CallConfig.ContractAddrs = contractAddrs
|
||||
genDoneChan, txChan, genErrChan := s.TxGenerator.GenerateTxs(genQuit)
|
||||
sendDoneChan, sendErrChan := s.Sender.Send(senderQuit, txChan)
|
||||
sendDoneChan, sendErrChan := s.Sender.Send(senderQuit, txChan, watcher.PendingTxCh)
|
||||
|
||||
go func() {
|
||||
defer close(doneChan)
|
||||
@ -64,17 +66,24 @@ func (s *Spammer) Loop(quitChan <-chan bool) (<-chan bool, error) {
|
||||
recoverClose(genQuit)
|
||||
<-genDoneChan
|
||||
recoverClose(senderQuit)
|
||||
<-sendDoneChan
|
||||
recoverClose(watcher.quitCh)
|
||||
case err := <-sendErrChan:
|
||||
logrus.Errorf("tx sending error: %v", err)
|
||||
recoverClose(genQuit)
|
||||
<-genDoneChan
|
||||
recoverClose(senderQuit)
|
||||
<-sendDoneChan
|
||||
recoverClose(watcher.quitCh)
|
||||
case <-quitChan:
|
||||
logrus.Info("shutting down tx spammer")
|
||||
recoverClose(genQuit)
|
||||
<-genDoneChan
|
||||
recoverClose(senderQuit)
|
||||
<-sendDoneChan
|
||||
recoverClose(watcher.quitCh)
|
||||
case <-sendDoneChan:
|
||||
recoverClose(watcher.quitCh)
|
||||
return
|
||||
case <-genDoneChan:
|
||||
recoverClose(senderQuit)
|
||||
@ -84,15 +93,6 @@ func (s *Spammer) Loop(quitChan <-chan bool) (<-chan bool, error) {
|
||||
return doneChan, nil
|
||||
}
|
||||
|
||||
func recoverSend(ch chan bool, value bool) {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
}
|
||||
}()
|
||||
|
||||
ch <- value
|
||||
}
|
||||
|
||||
func recoverClose(ch chan bool) (justClosed bool) {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
|
@ -19,6 +19,7 @@ package auto
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
@ -79,7 +80,7 @@ func (gen *TxGenerator) GenerateTxs(quitChan <-chan bool) (<-chan bool, <-chan *
|
||||
errChan := make(chan error)
|
||||
wg := new(sync.WaitGroup)
|
||||
for i, sender := range gen.config.SenderKeys {
|
||||
if len(gen.config.SendConfig.DestinationAddresses) > 0 {
|
||||
if gen.config.SendConfig.TotalNumber > 0 {
|
||||
wg.Add(1)
|
||||
go gen.genSends(wg, txChan, errChan, quitChan, sender, gen.config.SenderAddrs[i], gen.config.SendConfig)
|
||||
}
|
||||
@ -99,9 +100,10 @@ func (gen *TxGenerator) GenerateTxs(quitChan <-chan bool) (<-chan bool, <-chan *
|
||||
func (gen *TxGenerator) genSends(wg *sync.WaitGroup, txChan chan<- *types.Transaction, errChan chan<- error, quitChan <-chan bool, senderKey *ecdsa.PrivateKey, senderAddr common.Address, sendConfig *SendConfig) {
|
||||
defer wg.Done()
|
||||
ticker := time.NewTicker(sendConfig.Frequency)
|
||||
for _, dst := range sendConfig.DestinationAddresses {
|
||||
for i := 0; i < sendConfig.TotalNumber; i++ {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
dst := crypto.CreateAddress(receiverAddressSeed, uint64(i))
|
||||
log.Debugf("Generating send from %s to %s.", senderAddr.Hex(), dst.Hex())
|
||||
rawTx, _, err := gen.GenerateTx(&GenParams{
|
||||
ChainID: sendConfig.ChainID,
|
||||
|
60
pkg/auto/tx_watcher.go
Normal file
60
pkg/auto/tx_watcher.go
Normal file
@ -0,0 +1,60 @@
|
||||
package auto
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/sirupsen/logrus"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TxWatcher struct {
|
||||
PendingTxCh chan *types.Transaction
|
||||
ethClient *ethclient.Client
|
||||
quitCh chan bool
|
||||
startedAt time.Time
|
||||
counter uint
|
||||
}
|
||||
|
||||
func NewTxWatcher(ethClient *ethclient.Client) *TxWatcher {
|
||||
return &TxWatcher{
|
||||
PendingTxCh: make(chan *types.Transaction, 1000),
|
||||
ethClient: ethClient,
|
||||
quitCh: make(chan bool),
|
||||
}
|
||||
}
|
||||
|
||||
func (tw *TxWatcher) Start() {
|
||||
tw.startedAt = time.Now()
|
||||
go func() {
|
||||
defer close(tw.PendingTxCh)
|
||||
for {
|
||||
select {
|
||||
case tx := <-tw.PendingTxCh:
|
||||
tw.counter += 1
|
||||
if 0 == tw.counter%10 {
|
||||
logrus.Debugf("TxW: checking on TX %s (%d in channel)", tx.Hash().Hex(), len(tw.PendingTxCh))
|
||||
var receipt *types.Receipt = nil
|
||||
sleep := time.Millisecond
|
||||
start := time.Now()
|
||||
for receipt == nil {
|
||||
receipt, _ = tw.ethClient.TransactionReceipt(context.Background(), tx.Hash())
|
||||
if nil == receipt {
|
||||
time.Sleep(sleep)
|
||||
sleep *= 2
|
||||
} else {
|
||||
elapsed := time.Now().Sub(tw.startedAt)
|
||||
logrus.Debugf("TxW: TX %s found in block %s after %dms.", tx.Hash().Hex(),
|
||||
receipt.BlockNumber.String(), time.Now().Sub(start).Milliseconds())
|
||||
logrus.Infof("TxW: %d in %.0f seconds (%.2f/sec, %d pending)",
|
||||
tw.counter, elapsed.Seconds(), float64(tw.counter)/elapsed.Seconds(), len(tw.PendingTxCh))
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-tw.quitCh:
|
||||
logrus.Infof("TxW: quitting with %d in channel", len(tw.PendingTxCh))
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
@ -39,13 +39,13 @@ func TxSigner(chainID *big.Int) types.Signer {
|
||||
func SendTransaction(rpcClient *rpc.Client, tx *types.Transaction) error {
|
||||
msg, _ := tx.AsMessage(TxSigner(tx.ChainId()), big.NewInt(1))
|
||||
if nil == tx.To() {
|
||||
logrus.Infof("TX %s to create contract %s (sender %s)",
|
||||
logrus.Debugf("TX %s to create contract %s (sender %s)",
|
||||
tx.Hash().Hex(), crypto.CreateAddress(msg.From(), tx.Nonce()), msg.From().Hex())
|
||||
} else if nil == tx.Data() || len(tx.Data()) == 0 {
|
||||
logrus.Infof("TX %s sending %s Wei to %s (sender %s)",
|
||||
logrus.Debugf("TX %s sending %s Wei to %s (sender %s)",
|
||||
tx.Hash().Hex(), tx.Value().String(), msg.To().Hex(), msg.From().Hex())
|
||||
} else {
|
||||
logrus.Infof("TX %s calling contract %s (sender %s)",
|
||||
logrus.Debugf("TX %s calling contract %s (sender %s)",
|
||||
tx.Hash().Hex(), msg.To().Hex(), msg.From().Hex())
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user