Semi-deterministic, complex/large chain spammer #6

Merged
telackey merged 8 commits from auto_tx_gen_and_send into main 2020-10-30 03:09:39 +00:00
9 changed files with 152 additions and 82 deletions
Showing only changes of commit a1a54c7ac8 - Show all commits

View File

@ -83,7 +83,7 @@ func init() {
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv() viper.AutomaticEnv()
// flags // shared flags
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file location") rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file location")
rootCmd.PersistentFlags().String("log-level", log.InfoLevel.String(), "Log level (trace, debug, info, warn, error, fatal, panic") rootCmd.PersistentFlags().String("log-level", log.InfoLevel.String(), "Log level (trace, debug, info, warn, error, fatal, panic")

View File

@ -33,36 +33,6 @@ import (
"github.com/spf13/viper" "github.com/spf13/viper"
) )
const (
ETH_TX_LIST = "ETH_TX_LIST"
ETH_ADDR_LOG = "ETH_ADDR_LOG"
defaultGenKeyWritePathPrefix = "./accounts/keys/"
defaultAddrLogPath = "./accounts/addresses/accounts"
typeSuffix = ".type"
httpPathSuffix = ".http"
toSuffix = ".to"
amountSuffix = ".amount"
gasLimitSuffix = ".gasLimit"
gasPriceSuffix = ".gasPrice"
gasPremiumSuffix = ".gasPremium"
feeCapSuffix = ".feeCap"
dataSuffix = ".data"
senderKeyPathSuffix = ".senderKeyPath"
writeSenderPathSuffix = ".writeSenderPath"
l1SenderSuffix = ".l1Sender"
l1RollupTxIdSuffix = ".l1RollupTxId"
sigHashTypeSuffix = ".sigHashType"
frequencySuffix = ".frequency"
totalNumberSuffix = ".totalNumber"
delaySuffix = ".delay"
startingNonceSuffix = ".startingNonce"
queueOriginSuffix = ".queueOrigin"
chainIDSuffix = ".chainID"
contractWriteSuffix = ".writeDeploymentAddrPath"
)
// TxParams holds the parameters for a given transaction // TxParams holds the parameters for a given transaction
type TxParams struct { type TxParams struct {
// Name of this tx in the .toml file // Name of this tx in the .toml file
@ -111,9 +81,7 @@ type TxParams struct {
// NewConfig returns a new tx spammer config // NewConfig returns a new tx spammer config
func NewTxParams() ([]TxParams, error) { func NewTxParams() ([]TxParams, error) {
viper.BindEnv("eth.txs", ETH_TX_LIST) bindEnv()
viper.BindEnv("eth.addrLogPath", ETH_ADDR_LOG)
addrLogPath := viper.GetString("eth.addrLogPath") addrLogPath := viper.GetString("eth.addrLogPath")
txs := viper.GetStringSlice("eth.txs") txs := viper.GetStringSlice("eth.txs")
txParams := make([]TxParams, len(txs)) txParams := make([]TxParams, len(txs))

57
pkg/manual/env.go Normal file
View File

@ -0,0 +1,57 @@
// 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 manual
import "github.com/spf13/viper"
const (
// env variables
ETH_TX_LIST = "ETH_TX_LIST"
ETH_ADDR_LOG = "ETH_ADDR_LOG"
// write paths
defaultGenKeyWritePathPrefix = "./accounts/keys/out/"
defaultAddrLogPath = "./accounts/addresses/accounts"
// .toml binding suffixes
typeSuffix = ".type"
httpPathSuffix = ".http"
toSuffix = ".to"
amountSuffix = ".amount"
gasLimitSuffix = ".gasLimit"
gasPriceSuffix = ".gasPrice"
gasPremiumSuffix = ".gasPremium"
feeCapSuffix = ".feeCap"
dataSuffix = ".data"
senderKeyPathSuffix = ".senderKeyPath"
writeSenderPathSuffix = ".writeSenderPath"
l1SenderSuffix = ".l1Sender"
l1RollupTxIdSuffix = ".l1RollupTxId"
sigHashTypeSuffix = ".sigHashType"
frequencySuffix = ".frequency"
totalNumberSuffix = ".totalNumber"
delaySuffix = ".delay"
startingNonceSuffix = ".startingNonce"
queueOriginSuffix = ".queueOrigin"
chainIDSuffix = ".chainID"
contractWriteSuffix = ".writeDeploymentAddrPath"
)
func bindEnv() {
viper.BindEnv("eth.txs", ETH_TX_LIST)
viper.BindEnv("eth.addrLogPath", ETH_ADDR_LOG)
}

View File

@ -17,14 +17,12 @@
package manual package manual
import ( import (
"context"
"fmt" "fmt"
"github.com/sirupsen/logrus"
"sync" "sync"
"time" "time"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/vulcanize/tx_spammer/pkg/shared"
"github.com/ethereum/go-ethereum/rpc"
"github.com/sirupsen/logrus"
) )
// TxSender type for // TxSender type for
@ -86,10 +84,6 @@ func (s *TxSender) genAndSend(p TxParams) error {
if err != nil { if err != nil {
return err return err
} }
return sendRawTransaction(p.Client, tx, p.Name) logrus.Infof("sending tx %s", p.Name)
} return shared.SendRawTransaction(p.Client, tx)
}
func sendRawTransaction(rpcClient *rpc.Client, txRlp []byte, name string) error {
logrus.Infof("sending tx %s", name)
return rpcClient.CallContext(context.Background(), nil, "eth_sendRawTransaction", hexutil.Encode(txRlp))
}

View File

@ -17,31 +17,24 @@
package manual package manual
import ( import (
"sync"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/vulcanize/tx_spammer/pkg/shared"
) )
type Service interface {
Loop(wg *sync.WaitGroup, quitChan <-chan bool)
}
type Spammer struct { type Spammer struct {
Sender *TxSender Sender *TxSender
} }
func NewTxSpammer(params []TxParams) Service { func NewTxSpammer(params []TxParams) shared.Service {
return &Spammer{ return &Spammer{
Sender: NewTxSender(params), Sender: NewTxSender(params),
} }
} }
func (s *Spammer) Loop(wg *sync.WaitGroup, quitChan <-chan bool) { func (s *Spammer) Loop(quitChan <-chan bool) <-chan bool {
forwardQuit := make(chan bool) forwardQuit := make(chan bool)
doneChan, errChan := s.Sender.Send(forwardQuit) doneChan, errChan := s.Sender.Send(forwardQuit)
wg.Add(1)
go func() { go func() {
defer wg.Done()
for { for {
select { select {
case err := <-errChan: case err := <-errChan:
@ -53,4 +46,5 @@ func (s *Spammer) Loop(wg *sync.WaitGroup, quitChan <-chan bool) {
} }
} }
}() }()
return doneChan
} }

View File

@ -17,19 +17,14 @@
package manual package manual
import ( import (
"errors"
"fmt" "fmt"
"github.com/vulcanize/tx_spammer/pkg/shared"
"os"
"sync/atomic" "sync/atomic"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) "github.com/vulcanize/tx_spammer/pkg/shared"
const (
defaultDeploymentAddrLogPathPrefix = "./accounts/addresses/"
) )
// TxGenerator generates and signs txs // TxGenerator generates and signs txs
@ -54,7 +49,9 @@ func NewTxGenerator(params []TxParams) *TxGenerator {
func (tg TxGenerator) GenerateTx(params TxParams) ([]byte, error) { func (tg TxGenerator) GenerateTx(params TxParams) ([]byte, error) {
tx := make([]byte, 0) tx := make([]byte, 0)
switch params.Type { switch params.Type {
case shared.Standard, shared.OptimismL1ToL2, shared.OptimismL2: case shared.OptimismL2:
return tg.genL2(params)
case shared.Standard:
return tg.gen(params) return tg.gen(params)
case shared.EIP1559: case shared.EIP1559:
return tg.gen1559(params) return tg.gen1559(params)
@ -64,19 +61,19 @@ func (tg TxGenerator) GenerateTx(params TxParams) ([]byte, error) {
return tx, nil return tx, nil
} }
func (gen TxGenerator) gen(params TxParams) ([]byte, error) { func (gen TxGenerator) genL2(params TxParams) ([]byte, error) {
nonce := atomic.AddUint64(gen.nonces[params.Sender], 1) nonce := atomic.AddUint64(gen.nonces[params.Sender], 1)
tx := new(types.Transaction) tx := new(types.Transaction)
if params.To == nil { if params.To == nil {
tx = types.NewContractCreation(nonce, params.Amount, params.GasLimit, params.GasPrice, params.Data, params.L1SenderAddr, params.L1RollupTxId, params.QueueOrigin) tx = types.NewContractCreation(nonce, params.Amount, params.GasLimit, params.GasPrice, params.Data, params.L1SenderAddr, params.L1RollupTxId, params.QueueOrigin)
if err := writeContractAddr(params.ContractAddrWritePath, params.Sender, nonce); err != nil { if err := shared.WriteContractAddr(params.ContractAddrWritePath, params.Sender, nonce); err != nil {
return nil, err return nil, err
} }
} else { } else {
tx = types.NewTransaction(nonce, *params.To, params.Amount, params.GasLimit, params.GasPrice, params.Data, params.L1SenderAddr, params.L1RollupTxId, params.QueueOrigin, params.SigHashType) tx = types.NewTransaction(nonce, *params.To, params.Amount, params.GasLimit, params.GasPrice, params.Data, params.L1SenderAddr, params.L1RollupTxId, params.QueueOrigin, params.SigHashType)
} }
signer, err := shared.TxSigner(params.Type, params.ChainID) signer, err := shared.TxSigner(shared.OptimismL2, params.ChainID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -91,22 +88,12 @@ func (gen TxGenerator) gen(params TxParams) ([]byte, error) {
return txRlp, nil return txRlp, nil
} }
func (gen TxGenerator) gen1559(params TxParams) ([]byte, error) { func (gen TxGenerator) gen(params TxParams) ([]byte, error) {
// TODO: support EIP1559; new to make a new major version, vendor it, or release with different pkg name so that we can import both optimism and eip1559 geth // TODO: support standard geth
return nil, fmt.Errorf("1559 support not yet available") return nil, errors.New("L1 support not yet available")
} }
func writeContractAddr(filePath string, senderAddr common.Address, nonce uint64) error { func (gen TxGenerator) gen1559(params TxParams) ([]byte, error) {
if filePath == "" { // TODO: support EIP1559
filePath = defaultDeploymentAddrLogPathPrefix + senderAddr.Hex() return nil, errors.New("1559 support not yet available")
}
contractAddr := crypto.CreateAddress(senderAddr, nonce)
f, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
if _, err := f.WriteString(contractAddr.Hex() + "\n"); err != nil {
return err
}
return f.Close()
} }

21
pkg/shared/env.go Normal file
View File

@ -0,0 +1,21 @@
// 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 shared
const (
DefaultDeploymentAddrLogPathPrefix = "./accounts/addresses/"
)

22
pkg/shared/interface.go Normal file
View File

@ -0,0 +1,22 @@
// 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 shared
// Service looping interface
type Service interface {
Loop(quitChan <-chan bool) (doneChan <-chan bool)
}

View File

@ -17,10 +17,16 @@
package shared package shared
import ( import (
"context"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"math/big" "math/big"
"os"
"github.com/ethereum/go-ethereum/core/types" "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 // ChainConfig returns the appropriate ethereum chain config for the provided chain id
@ -34,3 +40,24 @@ func TxSigner(kind TxType, chainID uint64) (types.Signer, error) {
return nil, fmt.Errorf("chain config for chainid %d not available", chainID) return nil, fmt.Errorf("chain config for chainid %d not available", chainID)
} }
} }
// SendRawTransaction sends a raw, signed tx using the provided client
func SendRawTransaction(rpcClient *rpc.Client, txRlp []byte) error {
return rpcClient.CallContext(context.Background(), nil, "eth_sendRawTransaction", hexutil.Encode(txRlp))
}
// WriteContractAddr appends a contract addr to an out file
func WriteContractAddr(filePath string, senderAddr common.Address, nonce uint64) error {
if filePath == "" {
filePath = DefaultDeploymentAddrLogPathPrefix + senderAddr.Hex()
}
contractAddr := crypto.CreateAddress(senderAddr, nonce)
f, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
if _, err := f.WriteString(contractAddr.Hex() + "\n"); err != nil {
return err
}
return f.Close()
}