Semi-deterministic, complex/large chain spammer #6
39
environments/gen.toml
Normal file
39
environments/gen.toml
Normal file
@ -0,0 +1,39 @@
|
||||
[eth]
|
||||
keyDirPath = "" # path to the directory with all of the key pairs to use - env: $ETH_KEY_DIR_PATH
|
||||
addrFilePath = "" # path to a file with a newline seperated list of addresses we want to send value transfers to - env: $ETH_ADDR_DIR_PATH
|
||||
httpPath = "" # http url for the node we wish to send all our transactions to - env: $ETH_HTTP_PATH
|
||||
chainID = 421 # chain id - env: $ETH_CHAIN_ID
|
||||
type = "L2" # tx type (EIP1559, Standard, or L2) - env: $ETH_TX_TYPE
|
||||
|
||||
[deployment]
|
||||
number = 1 # number of contracts we will deploy for each key at keyPath - env: $ETH_DEPLOYMENT_NUMBER
|
||||
hexData = "" # hex data for the contracts we will deploy - env: $ETH_DEPLOYMENT_HEX_DATA
|
||||
gasLimit = 0 # gasLimit to use for the deployment txs - env: $ETH_DEPLOYMENT_GAS_LIMIT
|
||||
gasPrice = "0" # gasPrice to use for the deployment txs - env: $ETH_DEPLOYMENT_GAS_PRICE
|
||||
|
||||
[optimism]
|
||||
l1Sender = "" # l1 sender address hex to use for all txs - env: $ETH_OPTIMISM_L1_SENDER
|
||||
l1RollupTxId = 0 # rollup tx id to use for all txs - env: $ETH_OPTIMISM_ROLLUP_TX_ID
|
||||
sigHashType = 0 # sig hash type to use for all txs - env: $ETH_OPTIMISM_SIG_HASH_TYPE
|
||||
queueOrigin = 0 # queue origin id to use for all txs - env: $ETH_OPTIMISM_QUEUE_ORIGIN
|
||||
|
||||
[contractSpammer]
|
||||
frequency = 30 # how often to send a transaction (in seconds) - env: $ETH_CALL_FREQ
|
||||
totalNumber = 10000 # total number of transactions to send (across all senders) - env: $ETH_CALL_TOTAL_NUMBER
|
||||
abiPath = "" # 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(uint256 pos, 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
|
||||
# the second argument is an integer value that we store at these positions
|
||||
methodName = "Put" # the method name we are calling - env: $ETH_CALL_METHOD_NAME
|
||||
positionStart = 0 # the starting value for the first argument - env: $ETH_CALL_POSITION_START
|
||||
positionEnd = 1000 # the maximum value for the first argument - env: $ETH_CALL_POSITION_END
|
||||
storageValue = 1337 # the value we store at each position - env: $ETH_CALL_STORAGE_VALUE
|
||||
gasLimit = 0 # gasLimit to use for the eth call txs - env: $ETH_CALL_GAS_LIMIT
|
||||
gasPrice = "0" # gasPrice to use for the eth call txs - env: $ETH_CALL_GAS_PRICE
|
||||
|
||||
[sendSpammer]
|
||||
frequency = 30 # how often to send a transaction (in seconds) - env: $ETH_SEND_FREQ
|
||||
totalNumber = 10000 # total number of transactions to send (across all senders) - env: $ETH_SEND_TOTAL_NUMBER
|
||||
amount = "1" # amount of wei (1x10^-18 ETH) to send in each tx (be mindful of the genesis allocations) - env: $ETH_SEND_AMOUNT
|
||||
gasLimit = 0 # gasLimit to use for the eth transfer txs - env: $ETH_SEND_GAS_LIMIT
|
||||
gasPrice = "0" # gasPrice to use for the eth transfer txs - env: $ETH_SEND_GAS_PRICE
|
394
pkg/auto/config.go
Normal file
394
pkg/auto/config.go
Normal file
@ -0,0 +1,394 @@
|
||||
// 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 (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/vulcanize/tx_spammer/pkg/shared"
|
||||
)
|
||||
|
||||
const (
|
||||
// toml bindings
|
||||
ethKeyDirPath = "eth.keyDirPath"
|
||||
ethAddrFilePath = "eth.addrFilePath"
|
||||
ethHttpPath = "eth.httpPath"
|
||||
ethChainID = "eth.chainID"
|
||||
ethType = "eth.type"
|
||||
|
||||
ethDeploymentNumber = "deployment.number"
|
||||
ethDeploymentData = "deployment.hexData"
|
||||
ethDeploymentGasPrice = "deployment.gasPrice"
|
||||
ethDeploymentGasLimit = "deployment.gasLimit"
|
||||
|
||||
ethOptimismL1Sender = "optimism.l1Sender"
|
||||
ethOptimismRollupTxID = "optimism.l1RollupTxId"
|
||||
ethOptimismSigHashType = "optimism.sigHashType"
|
||||
ethOptimismQueueOrigin = "optimism.queueOrigin"
|
||||
|
||||
ethCallFrequency = "contractSpammer.frequency"
|
||||
ethCallTotalNumber = "contractSpammer.totalNumber"
|
||||
ethCallABIPath = "contractSpammer.abiPath"
|
||||
ethCallMethodName = "contractSpammer.methodName"
|
||||
ethCallPositionStart = "contractSpammer.positionStart"
|
||||
ethCallPositionEnd = "contractSpammer.positionEnd"
|
||||
ethCallStorageValue = "contractSpammer.storageValue"
|
||||
ethCallGasLimit = "contractSpammer.gasLimit"
|
||||
ethCallGasPrice = "contractSpammer.gasPrice"
|
||||
|
||||
ethSendFrequency = "sendSpammer.frequency"
|
||||
ethSendTotalNumber = "sendSpammer.totalNumber"
|
||||
ethSendAmount = "sendSpammer.amount"
|
||||
ethSendGasLimit = "sendSpammer.gasLimit"
|
||||
ethSendGasPrice = "sendSpammer.gasPrice"
|
||||
|
||||
// env variables
|
||||
ETH_KEY_DIR_PATH = "ETH_KEY_DIR_PATH"
|
||||
ETH_ADDR_DIR_PATH = "ETH_ADDR_DIR_PATH"
|
||||
ETH_HTTP_PATH = "ETH_HTTP_PATH"
|
||||
ETH_CHAIN_ID = "ETH_CHAIN_ID"
|
||||
ETH_TX_TYPE = "ETH_TX_TYPE"
|
||||
|
||||
ETH_DEPLOYMENT_NUMBER = "ETH_DEPLOYMENT_NUMBER"
|
||||
ETH_DEPLOYMENT_HEX_DATA = "ETH_DEPLOYMENT_HEX_DATA"
|
||||
ETH_DEPLOYMENT_GAS_LIMIT = "ETH_DEPLOYMENT_GAS_LIMIT"
|
||||
ETH_DEPLOYMENT_GAS_PRICE = "ETH_DEPLOYMENT_GAS_PRICE"
|
||||
|
||||
ETH_OPTIMISM_L1_SENDER = "ETH_OPTIMISM_L1_SENDER"
|
||||
ETH_OPTIMISM_ROLLUP_TX_ID = "ETH_OPTIMISM_ROLLUP_TX_ID"
|
||||
ETH_OPTIMISM_SIG_HASH_TYPE = "ETH_OPTIMISM_SIG_HASH_TYPE"
|
||||
ETH_OPTIMISM_QUEUE_ORIGIN = "ETH_OPTIMISM_QUEUE_ORIGIN"
|
||||
|
||||
ETH_CALL_FREQ = "ETH_CALL_FREQ"
|
||||
ETH_CALL_TOTAL_NUMBER = "ETH_CALL_TOTAL_NUMBER"
|
||||
ETH_CALL_ABI_PATH = "ETH_CALL_ABI_PATH"
|
||||
ETH_CALL_METHOD_NAME = "ETH_CALL_METHOD_NAME"
|
||||
ETH_CALL_POSITION_START = "ETH_CALL_POSITION_START"
|
||||
ETH_CALL_POSITION_END = "ETH_CALL_POSITION_END"
|
||||
ETH_CALL_STORAGE_VALUE = "ETH_CALL_STORAGE_VALUE"
|
||||
ETH_CALL_GAS_LIMIT = "ETH_CALL_GAS_LIMIT"
|
||||
ETH_CALL_GAS_PRICE = "ETH_CALL_GAS_PRICE"
|
||||
|
||||
ETH_SEND_FREQ = "ETH_SEND_FREQ"
|
||||
ETH_SEND_TOTAL_NUMBER = "ETH_SEND_TOTAL_NUMBER"
|
||||
ETH_SEND_AMOUNT = "ETH_SEND_AMOUNT"
|
||||
ETH_SEND_GAS_LIMIT = "ETH_SEND_GAS_LIMIT"
|
||||
ETH_SEND_GAS_PRICE = "ETH_SEND_GAS_PRICE"
|
||||
)
|
||||
|
||||
// Config holds all the parameters for the auto tx spammer
|
||||
type Config struct {
|
||||
// HTTP client for sending transactions
|
||||
Client *rpc.Client
|
||||
|
||||
// Key pairs for the accounts we will use to deploy contracts and send txs
|
||||
SenderKeys []*ecdsa.PrivateKey
|
||||
|
||||
// Addresses to send eth transfer txs to
|
||||
DestinationAddrs []common.Address
|
||||
|
||||
// Type of the txs we are working with
|
||||
Type shared.TxType
|
||||
|
||||
// Chain ID for the chain we are working with
|
||||
ChainID uint64
|
||||
|
||||
// Optimism-specific metadata fields (optional)
|
||||
L1SenderAddr *common.Address
|
||||
L1RollupTxId *hexutil.Uint64
|
||||
SigHashType types.SignatureHashType
|
||||
QueueOrigin types.QueueOrigin
|
||||
|
||||
// Configuration for the initial contract deployment
|
||||
DeploymentConfig *DeploymentConfig
|
||||
|
||||
// Configuration for the contract calling txs
|
||||
CallConfig *CallConfig
|
||||
|
||||
// Configuration for the eth transfer txs
|
||||
SendConfig *SendConfig
|
||||
}
|
||||
|
||||
// DeploymentConfig holds the parameters for the contract deployment contracts
|
||||
type DeploymentConfig struct {
|
||||
GasLimit uint64
|
||||
GasPrice *big.Int
|
||||
Data []byte
|
||||
|
||||
Number uint64
|
||||
}
|
||||
|
||||
// CallConfig holds the parameters for the contract calling txs
|
||||
type CallConfig struct {
|
||||
GasLimit uint64
|
||||
GasPrice *big.Int
|
||||
MethodName string
|
||||
ABI abi.ABI
|
||||
PositionStart uint64
|
||||
PositionEnd uint64
|
||||
StorageValue uint64
|
||||
|
||||
Frequency time.Duration
|
||||
Number uint64
|
||||
}
|
||||
|
||||
// SendConfig holds the parameters for the eth transfer txs
|
||||
type SendConfig struct {
|
||||
GasLimit uint64
|
||||
GasPrice *big.Int
|
||||
Amount *big.Int
|
||||
|
||||
Frequency time.Duration
|
||||
Number uint64
|
||||
}
|
||||
|
||||
func NewConfig() (*Config, error) {
|
||||
viper.BindEnv(ethKeyDirPath, ETH_KEY_DIR_PATH)
|
||||
viper.BindEnv(ethAddrFilePath, ETH_ADDR_DIR_PATH)
|
||||
viper.BindEnv(ethHttpPath, ETH_HTTP_PATH)
|
||||
viper.BindEnv(ethType, ETH_TX_TYPE)
|
||||
viper.BindEnv(ethChainID, ETH_CHAIN_ID)
|
||||
|
||||
viper.BindEnv(ethOptimismL1Sender, ETH_OPTIMISM_L1_SENDER)
|
||||
viper.BindEnv(ethOptimismQueueOrigin, ETH_OPTIMISM_QUEUE_ORIGIN)
|
||||
viper.BindEnv(ethOptimismRollupTxID, ETH_OPTIMISM_ROLLUP_TX_ID)
|
||||
viper.BindEnv(ethOptimismSigHashType, ETH_OPTIMISM_SIG_HASH_TYPE)
|
||||
|
||||
// Initialize rpc client
|
||||
httpPathStr := viper.GetString(ethHttpPath)
|
||||
if httpPathStr == "" {
|
||||
return nil, fmt.Errorf("missing %s", ethHttpPath)
|
||||
}
|
||||
if !strings.HasPrefix(httpPathStr, "http://") {
|
||||
httpPathStr = "http://" + httpPathStr
|
||||
}
|
||||
rpcClient, err := rpc.Dial(httpPathStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Load keys
|
||||
keyDirPath := viper.GetString(ethKeyDirPath)
|
||||
if keyDirPath == "" {
|
||||
return nil, fmt.Errorf("missing %s", ethKeyDirPath)
|
||||
}
|
||||
keyFiles, err := ioutil.ReadDir(keyDirPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keys := make([]*ecdsa.PrivateKey, 0)
|
||||
for _, keyFile := range keyFiles {
|
||||
if keyFile.IsDir() {
|
||||
continue
|
||||
}
|
||||
filePath := filepath.Join(keyDirPath, keyFile.Name())
|
||||
key, err := crypto.LoadECDSA(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load ecdsa key file at %s", filePath)
|
||||
}
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
// Load eth transfer destination addresses
|
||||
addrs := make([]common.Address, 0)
|
||||
addrFilePath := viper.GetString(ethAddrFilePath)
|
||||
if addrFilePath == "" {
|
||||
return nil, fmt.Errorf("missing %s", ethAddrFilePath)
|
||||
}
|
||||
addrFile, err := os.Open(addrFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer addrFile.Close()
|
||||
scanner := bufio.NewScanner(addrFile)
|
||||
for scanner.Scan() {
|
||||
addrBytes := scanner.Bytes()
|
||||
addr := common.BytesToAddress(addrBytes)
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Load tx type
|
||||
txType, err := shared.TxTypeFromString(viper.GetString(ethType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Load optimism params
|
||||
l1SenderStr := viper.GetString(ethOptimismL1Sender)
|
||||
var l1Sender *common.Address
|
||||
if l1SenderStr != "" {
|
||||
sender := common.HexToAddress(l1SenderStr)
|
||||
l1Sender = &sender
|
||||
}
|
||||
l1RollupTxId := viper.GetUint64(ethOptimismRollupTxID)
|
||||
l1rtid := (hexutil.Uint64)(l1RollupTxId)
|
||||
sigHashType := viper.GetUint(ethOptimismSigHashType)
|
||||
queueOrigin := viper.GetInt64(ethOptimismQueueOrigin)
|
||||
|
||||
// Load deployment config
|
||||
deploymentConfig, err := NewDeploymentConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Load call config
|
||||
callConfig, err := NewCallConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Load send config
|
||||
sendConfig, err := NewSendConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Assemble and return
|
||||
return &Config{
|
||||
Client: rpcClient,
|
||||
SenderKeys: keys,
|
||||
DestinationAddrs: addrs,
|
||||
Type: txType,
|
||||
ChainID: viper.GetUint64(ethChainID),
|
||||
|
||||
L1SenderAddr: l1Sender,
|
||||
L1RollupTxId: &l1rtid,
|
||||
SigHashType: (types.SignatureHashType)(uint8(sigHashType)),
|
||||
QueueOrigin: (types.QueueOrigin)(queueOrigin),
|
||||
|
||||
DeploymentConfig: deploymentConfig,
|
||||
CallConfig: callConfig,
|
||||
SendConfig: sendConfig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewDeploymentConfig constructs and returns a new DeploymentConfig
|
||||
func NewDeploymentConfig() (*DeploymentConfig, error) {
|
||||
viper.BindEnv(ethDeploymentNumber, ETH_DEPLOYMENT_NUMBER)
|
||||
viper.BindEnv(ethDeploymentData, ETH_DEPLOYMENT_HEX_DATA)
|
||||
viper.BindEnv(ethDeploymentGasLimit, ETH_DEPLOYMENT_GAS_LIMIT)
|
||||
viper.BindEnv(ethDeploymentGasPrice, ETH_DEPLOYMENT_GAS_PRICE)
|
||||
|
||||
hexData := viper.GetString(ethDeploymentData)
|
||||
data := common.Hex2Bytes(hexData)
|
||||
gasPriceStr := viper.GetString(ethDeploymentGasPrice)
|
||||
gasPrice, ok := new(big.Int).SetString(gasPriceStr, 10)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unable to convert gasPrice string (%s) into big.Int", gasPriceStr)
|
||||
}
|
||||
|
||||
return &DeploymentConfig{
|
||||
Number: viper.GetUint64(ethDeploymentNumber),
|
||||
Data: data,
|
||||
GasPrice: gasPrice,
|
||||
GasLimit: viper.GetUint64(ethDeploymentGasLimit),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewCallConfig constructs and returns a new CallConfig
|
||||
func NewCallConfig() (*CallConfig, error) {
|
||||
viper.BindEnv(ethCallABIPath, ETH_CALL_ABI_PATH)
|
||||
viper.BindEnv(ethCallFrequency, ETH_CALL_FREQ)
|
||||
viper.BindEnv(ethCallGasLimit, ETH_CALL_GAS_LIMIT)
|
||||
viper.BindEnv(ethCallGasPrice, ETH_CALL_GAS_PRICE)
|
||||
viper.BindEnv(ethCallMethodName, ETH_CALL_METHOD_NAME)
|
||||
viper.BindEnv(ethCallPositionEnd, ETH_CALL_POSITION_END)
|
||||
viper.BindEnv(ethCallPositionStart, ETH_CALL_POSITION_START)
|
||||
viper.BindEnv(ethCallStorageValue, ETH_CALL_STORAGE_VALUE)
|
||||
viper.BindEnv(ethCallTotalNumber, ETH_CALL_TOTAL_NUMBER)
|
||||
|
||||
gasPriceStr := viper.GetString(ethCallGasPrice)
|
||||
gasPrice, ok := new(big.Int).SetString(gasPriceStr, 10)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unable to convert gasPrice string (%s) into big.Int", gasPriceStr)
|
||||
}
|
||||
abiPath := viper.GetString(ethCallABIPath)
|
||||
if abiPath == "" {
|
||||
return nil, fmt.Errorf("missing contractSpammer.abiPath")
|
||||
}
|
||||
abiBytes, err := ioutil.ReadFile(abiPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parsedABI, err := abi.JSON(bytes.NewReader(abiBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
methodName := viper.GetString(ethCallMethodName)
|
||||
_, exist := parsedABI.Methods[methodName]
|
||||
if !exist {
|
||||
return nil, fmt.Errorf("method '%s' not found in provided abi", methodName)
|
||||
}
|
||||
|
||||
return &CallConfig{
|
||||
Number: viper.GetUint64(ethCallTotalNumber),
|
||||
GasPrice: gasPrice,
|
||||
GasLimit: viper.GetUint64(ethCallGasLimit),
|
||||
MethodName: methodName,
|
||||
ABI: parsedABI,
|
||||
PositionEnd: viper.GetUint64(ethCallPositionEnd),
|
||||
PositionStart: viper.GetUint64(ethCallPositionStart),
|
||||
StorageValue: viper.GetUint64(ethCallStorageValue),
|
||||
Frequency: viper.GetDuration(ethCallFrequency),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewSendConfig constructs and returns a new SendConfig
|
||||
func NewSendConfig() (*SendConfig, error) {
|
||||
viper.BindEnv(ethSendFrequency, ETH_SEND_FREQ)
|
||||
viper.BindEnv(ethSendTotalNumber, ETH_SEND_TOTAL_NUMBER)
|
||||
viper.BindEnv(ethSendAmount, ETH_SEND_AMOUNT)
|
||||
viper.BindEnv(ethSendGasLimit, ETH_SEND_GAS_LIMIT)
|
||||
viper.BindEnv(ethSendGasPrice, ETH_SEND_GAS_PRICE)
|
||||
|
||||
amountStr := viper.GetString(ethSendAmount)
|
||||
amount, ok := new(big.Int).SetString(amountStr, 10)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unable to convert amount string (%s) into big.Int", amountStr)
|
||||
}
|
||||
gasPriceStr := viper.GetString(ethSendGasPrice)
|
||||
gasPrice, ok := new(big.Int).SetString(gasPriceStr, 10)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unable to convert gasPrice string (%s) into big.Int", gasPriceStr)
|
||||
}
|
||||
return &SendConfig{
|
||||
Frequency: viper.GetDuration(ethSendFrequency),
|
||||
Number: viper.GetUint64(ethSendTotalNumber),
|
||||
Amount: amount,
|
||||
GasPrice: gasPrice,
|
||||
GasLimit: viper.GetUint64(ethSendGasLimit),
|
||||
}, nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user