diff --git a/cmd/autoSend.go b/cmd/autoSend.go
new file mode 100644
index 0000000..e7c8dad
--- /dev/null
+++ b/cmd/autoSend.go
@@ -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 .
+
+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)
+}
\ No newline at end of file
diff --git a/cmd/sendTxs.go b/cmd/sendTxs.go
index c180e41..dbd6f8f 100644
--- a/cmd/sendTxs.go
+++ b/cmd/sendTxs.go
@@ -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() {
diff --git a/pkg/auto/config.go b/pkg/auto/config.go
index d7b5083..5f9a037 100644
--- a/pkg/auto/config.go
+++ b/pkg/auto/config.go
@@ -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
}
diff --git a/pkg/auto/deployer.go b/pkg/auto/deployer.go
new file mode 100644
index 0000000..d281de6
--- /dev/null
+++ b/pkg/auto/deployer.go
@@ -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 .
+
+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
+}
diff --git a/pkg/auto/env.go b/pkg/auto/env.go
index 339b273..d783706 100644
--- a/pkg/auto/env.go
+++ b/pkg/auto/env.go
@@ -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)
-}
\ No newline at end of file
+}
diff --git a/pkg/auto/sender.go b/pkg/auto/sender.go
index b051f9b..36e85de 100644
--- a/pkg/auto/sender.go
+++ b/pkg/auto/sender.go
@@ -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
}
diff --git a/pkg/auto/service.go b/pkg/auto/service.go
new file mode 100644
index 0000000..f99ee21
--- /dev/null
+++ b/pkg/auto/service.go
@@ -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 .
+
+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
+}
diff --git a/pkg/auto/tx_generator.go b/pkg/auto/tx_generator.go
new file mode 100644
index 0000000..7f626b7
--- /dev/null
+++ b/pkg/auto/tx_generator.go
@@ -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 .
+
+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")
+}
diff --git a/pkg/manual/config.go b/pkg/manual/config.go
index 1ac0397..dc8d1cf 100644
--- a/pkg/manual/config.go
+++ b/pkg/manual/config.go
@@ -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"
diff --git a/pkg/manual/env.go b/pkg/manual/env.go
index c0ba50a..4b607d6 100644
--- a/pkg/manual/env.go
+++ b/pkg/manual/env.go
@@ -54,4 +54,4 @@ const (
func bindEnv() {
viper.BindEnv("eth.txs", ETH_TX_LIST)
viper.BindEnv("eth.addrLogPath", ETH_ADDR_LOG)
-}
\ No newline at end of file
+}
diff --git a/pkg/manual/sender.go b/pkg/manual/sender.go
index 926332a..629076d 100644
--- a/pkg/manual/sender.go
+++ b/pkg/manual/sender.go
@@ -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)
-}
\ No newline at end of file
+}
diff --git a/pkg/shared/env.go b/pkg/shared/env.go
index b09f951..79fd305 100644
--- a/pkg/shared/env.go
+++ b/pkg/shared/env.go
@@ -18,4 +18,4 @@ package shared
const (
DefaultDeploymentAddrLogPathPrefix = "./accounts/addresses/"
-)
\ No newline at end of file
+)
diff --git a/pkg/shared/interface.go b/pkg/shared/interface.go
index 5a570a4..c0cef64 100644
--- a/pkg/shared/interface.go
+++ b/pkg/shared/interface.go
@@ -19,4 +19,4 @@ package shared
// Service looping interface
type Service interface {
Loop(quitChan <-chan bool) (doneChan <-chan bool)
-}
\ No newline at end of file
+}
diff --git a/pkg/shared/util.go b/pkg/shared/util.go
index 0c9975e..832039a 100644
--- a/pkg/shared/util.go
+++ b/pkg/shared/util.go
@@ -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()
-}
\ No newline at end of file
+}