Update for testing with Merge fixturenet. #11

Merged
telackey merged 8 commits from telackey/the_merge into main 2022-11-03 02:33:19 +00:00
7 changed files with 111 additions and 40 deletions
Showing only changes of commit 10c0d50ded - Show all commits

View File

@ -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

View File

@ -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
} }

View File

@ -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)

View File

@ -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 {

View File

@ -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
View 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
}
}
}()
}

View File

@ -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())
} }