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
|
gasFeeCap = "1000000007" # gasFeeCap to use for the deployment txs - env: $ETH_DEPLOYMENT_GAS_FEE_CAP
|
||||||
|
|
||||||
[contractSpammer]
|
[contractSpammer]
|
||||||
frequency = 10 # how often to send a transaction (in milliseconds) - env: $ETH_CALL_FREQ
|
frequency = 0 # 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
|
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
|
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
|
# 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
|
# 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
|
gasFeeCap = "1000000007" # gasFeeCap to use for the eth call txs - env: $ETH_CALL_GAS_FEE_CAP
|
||||||
|
|
||||||
[sendSpammer]
|
[sendSpammer]
|
||||||
frequency = 50 # how often to send a transaction (in milliseconds) - env: $ETH_SEND_FREQ
|
frequency = 0 # 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
|
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
|
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
|
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
|
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
|
// Configuration for the eth transfer txs
|
||||||
SendConfig *SendConfig
|
SendConfig *SendConfig
|
||||||
|
|
||||||
// Configuration for EIP1559
|
|
||||||
EIP1559Config *EIP1559Config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeploymentConfig holds the parameters for the contract deployment contracts
|
// DeploymentConfig holds the parameters for the contract deployment contracts
|
||||||
@ -108,13 +105,10 @@ type SendConfig struct {
|
|||||||
GasTipCap *big.Int
|
GasTipCap *big.Int
|
||||||
Amount *big.Int
|
Amount *big.Int
|
||||||
|
|
||||||
DestinationAddresses []common.Address
|
|
||||||
Frequency time.Duration
|
Frequency time.Duration
|
||||||
|
TotalNumber int
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: EIP1559Config
|
|
||||||
type EIP1559Config struct{}
|
|
||||||
|
|
||||||
func NewConfig() (*Config, error) {
|
func NewConfig() (*Config, error) {
|
||||||
// Initialize rpc client
|
// Initialize rpc client
|
||||||
httpPathStr := viper.GetString(ethHttpPath)
|
httpPathStr := viper.GetString(ethHttpPath)
|
||||||
@ -232,6 +226,15 @@ func NewCallConfig(chainID *big.Int) (*CallConfig, error) {
|
|||||||
if !exist {
|
if !exist {
|
||||||
return nil, fmt.Errorf("method '%s' not found in provided abi", methodName)
|
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{
|
return &CallConfig{
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
GasLimit: viper.GetUint64(ethCallGasLimit),
|
GasLimit: viper.GetUint64(ethCallGasLimit),
|
||||||
@ -239,7 +242,7 @@ func NewCallConfig(chainID *big.Int) (*CallConfig, error) {
|
|||||||
GasTipCap: big.NewInt(viper.GetInt64(ethCallGasTipCap)),
|
GasTipCap: big.NewInt(viper.GetInt64(ethCallGasTipCap)),
|
||||||
MethodName: methodName,
|
MethodName: methodName,
|
||||||
ABI: parsedABI,
|
ABI: parsedABI,
|
||||||
Frequency: viper.GetDuration(ethCallFrequency) * time.Millisecond,
|
Frequency: frequency,
|
||||||
TotalNumber: viper.GetInt(ethCallTotalNumber),
|
TotalNumber: viper.GetInt(ethCallTotalNumber),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -251,18 +254,22 @@ func NewSendConfig(chainID *big.Int) (*SendConfig, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("unable to convert amount string (%s) into big.Int", amountStr)
|
return nil, fmt.Errorf("unable to convert amount string (%s) into big.Int", amountStr)
|
||||||
}
|
}
|
||||||
number := viper.GetUint64(ethSendTotalNumber)
|
|
||||||
addrs := make([]common.Address, number)
|
var frequency time.Duration
|
||||||
for i := uint64(0); i < number; i++ {
|
tmpFreq := viper.GetInt(ethCallFrequency)
|
||||||
addrs[i] = crypto.CreateAddress(receiverAddressSeed, i)
|
if tmpFreq <= 0 {
|
||||||
|
frequency = time.Microsecond
|
||||||
|
} else {
|
||||||
|
frequency = viper.GetDuration(ethCallFrequency) * time.Millisecond
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SendConfig{
|
return &SendConfig{
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
DestinationAddresses: addrs,
|
Frequency: frequency,
|
||||||
Frequency: viper.GetDuration(ethSendFrequency) * time.Millisecond,
|
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
GasLimit: viper.GetUint64(ethSendGasLimit),
|
GasLimit: viper.GetUint64(ethSendGasLimit),
|
||||||
GasFeeCap: big.NewInt(viper.GetInt64(ethSendGasFeeCap)),
|
GasFeeCap: big.NewInt(viper.GetInt64(ethSendGasFeeCap)),
|
||||||
GasTipCap: big.NewInt(viper.GetInt64(ethSendGasTipCap)),
|
GasTipCap: big.NewInt(viper.GetInt64(ethSendGasTipCap)),
|
||||||
|
TotalNumber: viper.GetInt(ethSendTotalNumber),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ func NewEthSender(config *Config) *EthSender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send awaits txs off the provided work queue and sends them
|
// 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
|
// err channel returned to calling context
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
doneChan := make(chan bool)
|
doneChan := make(chan bool)
|
||||||
@ -49,6 +49,8 @@ func (s *EthSender) Send(quitChan <-chan bool, txChan <-chan *types.Transaction)
|
|||||||
counter += 1
|
counter += 1
|
||||||
if err := shared.SendTransaction(s.client, tx); err != nil {
|
if err := shared.SendTransaction(s.client, tx); err != nil {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
|
} else {
|
||||||
|
sentCh <- tx
|
||||||
}
|
}
|
||||||
case <-quitChan:
|
case <-quitChan:
|
||||||
logrus.Infof("quitting Send loop (sent %d)", counter)
|
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)
|
genQuit := make(chan bool)
|
||||||
senderQuit := make(chan bool)
|
senderQuit := make(chan bool)
|
||||||
doneChan := make(chan bool)
|
doneChan := make(chan bool)
|
||||||
|
watcher := NewTxWatcher(s.config.EthClient)
|
||||||
|
watcher.Start()
|
||||||
|
|
||||||
s.config.CallConfig.ContractAddrs = contractAddrs
|
s.config.CallConfig.ContractAddrs = contractAddrs
|
||||||
genDoneChan, txChan, genErrChan := s.TxGenerator.GenerateTxs(genQuit)
|
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() {
|
go func() {
|
||||||
defer close(doneChan)
|
defer close(doneChan)
|
||||||
@ -64,17 +66,24 @@ func (s *Spammer) Loop(quitChan <-chan bool) (<-chan bool, error) {
|
|||||||
recoverClose(genQuit)
|
recoverClose(genQuit)
|
||||||
<-genDoneChan
|
<-genDoneChan
|
||||||
recoverClose(senderQuit)
|
recoverClose(senderQuit)
|
||||||
|
<-sendDoneChan
|
||||||
|
recoverClose(watcher.quitCh)
|
||||||
case err := <-sendErrChan:
|
case err := <-sendErrChan:
|
||||||
logrus.Errorf("tx sending error: %v", err)
|
logrus.Errorf("tx sending error: %v", err)
|
||||||
recoverClose(genQuit)
|
recoverClose(genQuit)
|
||||||
<-genDoneChan
|
<-genDoneChan
|
||||||
recoverClose(senderQuit)
|
recoverClose(senderQuit)
|
||||||
|
<-sendDoneChan
|
||||||
|
recoverClose(watcher.quitCh)
|
||||||
case <-quitChan:
|
case <-quitChan:
|
||||||
logrus.Info("shutting down tx spammer")
|
logrus.Info("shutting down tx spammer")
|
||||||
recoverClose(genQuit)
|
recoverClose(genQuit)
|
||||||
<-genDoneChan
|
<-genDoneChan
|
||||||
recoverClose(senderQuit)
|
recoverClose(senderQuit)
|
||||||
|
<-sendDoneChan
|
||||||
|
recoverClose(watcher.quitCh)
|
||||||
case <-sendDoneChan:
|
case <-sendDoneChan:
|
||||||
|
recoverClose(watcher.quitCh)
|
||||||
return
|
return
|
||||||
case <-genDoneChan:
|
case <-genDoneChan:
|
||||||
recoverClose(senderQuit)
|
recoverClose(senderQuit)
|
||||||
@ -84,15 +93,6 @@ func (s *Spammer) Loop(quitChan <-chan bool) (<-chan bool, error) {
|
|||||||
return doneChan, nil
|
return doneChan, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func recoverSend(ch chan bool, value bool) {
|
|
||||||
defer func() {
|
|
||||||
if recover() != nil {
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
ch <- value
|
|
||||||
}
|
|
||||||
|
|
||||||
func recoverClose(ch chan bool) (justClosed bool) {
|
func recoverClose(ch chan bool) (justClosed bool) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if recover() != nil {
|
if recover() != nil {
|
||||||
|
@ -19,6 +19,7 @@ package auto
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -79,7 +80,7 @@ func (gen *TxGenerator) GenerateTxs(quitChan <-chan bool) (<-chan bool, <-chan *
|
|||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
wg := new(sync.WaitGroup)
|
wg := new(sync.WaitGroup)
|
||||||
for i, sender := range gen.config.SenderKeys {
|
for i, sender := range gen.config.SenderKeys {
|
||||||
if len(gen.config.SendConfig.DestinationAddresses) > 0 {
|
if gen.config.SendConfig.TotalNumber > 0 {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go gen.genSends(wg, txChan, errChan, quitChan, sender, gen.config.SenderAddrs[i], gen.config.SendConfig)
|
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) {
|
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()
|
defer wg.Done()
|
||||||
ticker := time.NewTicker(sendConfig.Frequency)
|
ticker := time.NewTicker(sendConfig.Frequency)
|
||||||
for _, dst := range sendConfig.DestinationAddresses {
|
for i := 0; i < sendConfig.TotalNumber; i++ {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
|
dst := crypto.CreateAddress(receiverAddressSeed, uint64(i))
|
||||||
log.Debugf("Generating send from %s to %s.", senderAddr.Hex(), dst.Hex())
|
log.Debugf("Generating send from %s to %s.", senderAddr.Hex(), dst.Hex())
|
||||||
rawTx, _, err := gen.GenerateTx(&GenParams{
|
rawTx, _, err := gen.GenerateTx(&GenParams{
|
||||||
ChainID: sendConfig.ChainID,
|
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 {
|
func SendTransaction(rpcClient *rpc.Client, tx *types.Transaction) error {
|
||||||
msg, _ := tx.AsMessage(TxSigner(tx.ChainId()), big.NewInt(1))
|
msg, _ := tx.AsMessage(TxSigner(tx.ChainId()), big.NewInt(1))
|
||||||
if nil == tx.To() {
|
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())
|
tx.Hash().Hex(), crypto.CreateAddress(msg.From(), tx.Nonce()), msg.From().Hex())
|
||||||
} else if nil == tx.Data() || len(tx.Data()) == 0 {
|
} 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())
|
tx.Hash().Hex(), tx.Value().String(), msg.To().Hex(), msg.From().Hex())
|
||||||
} else {
|
} 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())
|
tx.Hash().Hex(), msg.To().Hex(), msg.From().Hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user