complex chain generator

This commit is contained in:
Ian Norden 2020-10-23 10:30:33 -05:00
parent 6d3943cf6f
commit 3cff19fc83
14 changed files with 301 additions and 28 deletions

61
cmd/autoSend.go Normal file
View File

@ -0,0 +1,61 @@
// Copyright © 2020 Vulcanize, Inc
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package cmd
import (
"os"
"os/signal"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/vulcanize/tx_spammer/pkg/auto"
)
// autoSendCmd represents the autoSend command
var autoSendCmd = &cobra.Command{
Use: "autoSend",
Short: "Send large volumes of different tx types to different nodes for testing purposes",
Long: `Loads tx configuration from .toml config file
Generates txs from configuration and provided private keys and sends them to designated node according to set frequency and number
Support standard, optimism L2, optimism L1 to L2, and EIP1559 transactions`,
Run: func(cmd *cobra.Command, args []string) {
subCommand = cmd.CalledAs()
logWithCommand = *logrus.WithField("SubCommand", subCommand)
autoSend()
},
}
func autoSend() {
config, err := auto.NewConfig()
if err != nil {
logWithCommand.Fatal(err)
}
txSpammer := auto.NewTxSpammer(config)
quitChan := make(chan bool)
doneChan := txSpammer.Loop(quitChan)
go func() {
shutdown := make(chan os.Signal)
signal.Notify(shutdown, os.Interrupt)
<-shutdown
close(quitChan)
}()
<-doneChan
}
func init() {
rootCmd.AddCommand(autoSendCmd)
}

View File

@ -18,7 +18,6 @@ package cmd
import (
"os"
"os/signal"
"sync"
"github.com/sirupsen/logrus"
@ -46,9 +45,8 @@ func sendTxs() {
logWithCommand.Fatal(err)
}
txSpammer := manual.NewTxSpammer(params)
wg := new(sync.WaitGroup)
quitChan := make(chan bool)
txSpammer.Loop(wg, quitChan)
doneChan := txSpammer.Loop(quitChan)
go func() {
shutdown := make(chan os.Signal)
@ -56,7 +54,7 @@ func sendTxs() {
<-shutdown
close(quitChan)
}()
wg.Wait()
<-doneChan
}
func init() {

View File

@ -48,7 +48,7 @@ type Config struct {
Client *rpc.Client
// Key pairs for the accounts we will use to deploy contracts and send txs
SenderKeys []*ecdsa.PrivateKey
SenderKeys []*ecdsa.PrivateKey
SenderAddrs []common.Address
// Type of the txs we are working with
@ -92,8 +92,8 @@ type DeploymentConfig struct {
// CallConfig holds the parameters for the contract calling txs
type CallConfig struct {
GasLimit uint64
GasPrice *big.Int
GasLimit uint64
GasPrice *big.Int
MethodName string
ABI abi.ABI
@ -112,13 +112,12 @@ type SendConfig struct {
Amount *big.Int
DestinationAddresses []common.Address
Frequency time.Duration
Number uint64
Frequency time.Duration
Number uint64
}
// todo: EIP1559Config
type EIP1559Config struct {
}
func NewConfig() (*Config, error) {
@ -217,7 +216,7 @@ func NewConfig() (*Config, error) {
}
// NewOptimismConfig constructs and returns a new OptimismConfig
func NewOptimismConfig() *OptimismConfig{
func NewOptimismConfig() *OptimismConfig {
l1SenderStr := viper.GetString(ethOptimismL1Sender)
var l1Sender *common.Address
if l1SenderStr != "" {
@ -306,11 +305,11 @@ func NewSendConfig(destinationAddrs []common.Address) (*SendConfig, error) {
}
return &SendConfig{
DestinationAddresses: destinationAddrs,
Frequency: viper.GetDuration(ethSendFrequency),
Number: viper.GetUint64(ethSendTotalNumber),
Amount: amount,
GasPrice: gasPrice,
GasLimit: viper.GetUint64(ethSendGasLimit),
Frequency: viper.GetDuration(ethSendFrequency),
Number: viper.GetUint64(ethSendTotalNumber),
Amount: amount,
GasPrice: gasPrice,
GasLimit: viper.GetUint64(ethSendGasLimit),
}, nil
}

36
pkg/auto/deployer.go Normal file
View File

@ -0,0 +1,36 @@
// VulcanizeDB
// Copyright © 2020 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package auto
import "crypto/ecdsa"
type ContractDeployer struct {
SenderKeys []*ecdsa.PrivateKey
Config *DeploymentConfig
}
func NewContractDeployer(config *Config) *ContractDeployer {
return &ContractDeployer{
Config: config.DeploymentConfig,
SenderKeys: config.SenderKeys,
}
}
func (cp *ContractDeployer) Deploy() error {
return nil
}

View File

@ -118,4 +118,4 @@ func bindEnv() {
viper.BindEnv(ethSendAmount, ETH_SEND_AMOUNT)
viper.BindEnv(ethSendGasLimit, ETH_SEND_GAS_LIMIT)
viper.BindEnv(ethSendGasPrice, ETH_SEND_GAS_PRICE)
}
}

View File

@ -42,7 +42,7 @@ func (s *EthSender) Send(quitChan <-chan bool, txRlpChan <-chan []byte) (<-chan
go func() {
for {
select {
case tx := <- txRlpChan:
case tx := <-txRlpChan:
if err := shared.SendRawTransaction(s.client, tx); err != nil {
errChan <- err
}

56
pkg/auto/service.go Normal file
View File

@ -0,0 +1,56 @@
// VulcanizeDB
// Copyright © 2020 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package auto
import (
"github.com/sirupsen/logrus"
"github.com/vulcanize/tx_spammer/pkg/shared"
)
// Spammer underlying struct type for spamming service
type Spammer struct {
Deployer *ContractDeployer
Caller *ContractCaller
Sender *EthSender
}
// NewTxSpammer creates a new tx spamming service
func NewTxSpammer(config *Config) shared.Service {
return &Spammer{
Deployer: NewContractDeployer(config),
Caller: NewContractCaller(config),
Sender: NewEthSender(config),
}
}
func (s *Spammer) Loop(quitChan <-chan bool) <-chan bool {
forwardQuit := make(chan bool)
doneChan, errChan := s.Sender.Send(forwardQuit)
go func() {
for {
select {
case err := <-errChan:
logrus.Error(err)
case forwardQuit <- <-quitChan:
return
case <-doneChan:
return
}
}
}()
return doneChan
}

120
pkg/auto/tx_generator.go Normal file
View File

@ -0,0 +1,120 @@
// VulcanizeDB
// Copyright © 2020 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package auto
import (
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
"sync/atomic"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/vulcanize/tx_spammer/pkg/shared"
)
// TxGenerator generates and signs txs
type TxGenerator struct {
signer types.Signer
optimismConfig *OptimismConfig
eip1559Config *EIP1559Config
// keep track of account nonces locally so we aren't spamming to determine the nonce
// this assumes these accounts are not sending txs outside this process
nonces map[common.Address]*uint64
}
// NewTxGenerator creates a new tx generator
func NewTxGenerator(config Config) *TxGenerator {
nonces := make(map[common.Address]*uint64)
for _, addr := range config.SenderAddrs {
startingNonce := uint64(0)
nonces[addr] = &startingNonce
}
return &TxGenerator{
signer: config.Signer,
nonces: nonces,
optimismConfig: config.OptimismConfig,
eip1559Config: config.EIP1559Config,
}
}
// GenParams params for GenerateTx method calls
type GenParams struct {
Signer types.Signer
Sender common.Address
SenderKey *ecdsa.PrivateKey
To *common.Address
Amount *big.Int
GasLimit uint64
GasPrice *big.Int
Data []byte
}
func (tg TxGenerator) GenerateTxs(quitChan <-chan bool) (<-chan bool, <-chan []byte, <-chan error) {
}
// GenerateTx generates tx from the provided params
func (tg TxGenerator) GenerateTx(ty shared.TxType, params *GenParams) ([]byte, error) {
tx := make([]byte, 0)
switch ty {
case shared.OptimismL2:
return tg.genL2(params, tg.optimismConfig)
case shared.Standard:
return tg.gen(params)
case shared.EIP1559:
return tg.gen1559(params, tg.eip1559Config)
default:
return nil, fmt.Errorf("unsupported tx type: %s", ty.String())
}
return tx, nil
}
func (gen TxGenerator) genL2(params *GenParams, op *OptimismConfig) ([]byte, error) {
nonce := atomic.AddUint64(gen.nonces[params.Sender], 1)
tx := new(types.Transaction)
if params.To == nil {
tx = types.NewContractCreation(nonce, params.Amount, params.GasLimit, params.GasPrice, params.Data, op.L1SenderAddr, op.L1RollupTxId, op.QueueOrigin)
if err := shared.WriteContractAddr(shared.DefaultDeploymentAddrLogPathPrefix, params.Sender, nonce); err != nil {
return nil, err
}
} else {
tx = types.NewTransaction(nonce, *params.To, params.Amount, params.GasLimit, params.GasPrice, params.Data, op.L1SenderAddr, op.L1RollupTxId, op.QueueOrigin, op.SigHashType)
}
signedTx, err := types.SignTx(tx, params.Signer, params.SenderKey)
if err != nil {
return nil, err
}
txRlp, err := rlp.EncodeToBytes(signedTx)
if err != nil {
return nil, err
}
return txRlp, nil
}
func (gen TxGenerator) gen(params *GenParams) ([]byte, error) {
// TODO: support standard geth
return nil, errors.New("L1 support not yet available")
}
func (gen TxGenerator) gen1559(params *GenParams, eip1559Config *EIP1559Config) ([]byte, error) {
// TODO: support EIP1559
return nil, errors.New("1559 support not yet available")
}

View File

@ -19,12 +19,13 @@ package manual
import (
"crypto/ecdsa"
"fmt"
"github.com/vulcanize/tx_spammer/pkg/shared"
"math/big"
"os"
"strings"
"time"
"github.com/vulcanize/tx_spammer/pkg/shared"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"

View File

@ -54,4 +54,4 @@ const (
func bindEnv() {
viper.BindEnv("eth.txs", ETH_TX_LIST)
viper.BindEnv("eth.addrLogPath", ETH_ADDR_LOG)
}
}

View File

@ -18,10 +18,11 @@ package manual
import (
"fmt"
"github.com/sirupsen/logrus"
"sync"
"time"
"github.com/sirupsen/logrus"
"github.com/vulcanize/tx_spammer/pkg/shared"
)
@ -86,4 +87,4 @@ func (s *TxSender) genAndSend(p TxParams) error {
}
logrus.Infof("sending tx %s", p.Name)
return shared.SendRawTransaction(p.Client, tx)
}
}

View File

@ -18,4 +18,4 @@ package shared
const (
DefaultDeploymentAddrLogPathPrefix = "./accounts/addresses/"
)
)

View File

@ -19,4 +19,4 @@ package shared
// Service looping interface
type Service interface {
Loop(quitChan <-chan bool) (doneChan <-chan bool)
}
}

View File

@ -19,14 +19,15 @@ package shared
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"math/big"
"os"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/temp/common/hexutil"
)
// ChainConfig returns the appropriate ethereum chain config for the provided chain id
@ -60,4 +61,4 @@ func WriteContractAddr(filePath string, senderAddr common.Address, nonce uint64)
return err
}
return f.Close()
}
}