Semi-deterministic, complex/large chain spammer #6
@ -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")
|
||||||
|
@ -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
57
pkg/manual/env.go
Normal 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)
|
||||||
|
}
|
@ -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))
|
|
||||||
}
|
}
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
21
pkg/shared/env.go
Normal 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
22
pkg/shared/interface.go
Normal 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)
|
||||||
|
}
|
@ -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()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user