Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/livefuzzer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var airdropCommand = &cli.Command{
Flags: []cli.Flag{
flags.SkFlag,
flags.RpcFlag,
flags.RpcsFlag,
},
}

Expand Down Expand Up @@ -50,6 +51,7 @@ var createCommand = &cli.Command{
Flags: []cli.Flag{
flags.CountFlag,
flags.RpcFlag,
flags.RpcsFlag,
},
}

Expand Down
6 changes: 6 additions & 0 deletions flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ var (
Value: "http://127.0.0.1:8545",
}

RpcsFlag = &cli.StringFlag{
Name: "rpcs",
Usage: "Comma separated list of RPC providers to use for sending transactions",
}

TxCountFlag = &cli.IntFlag{
Name: "txcount",
Usage: "Number of transactions send per account per block, 0 = best estimate",
Expand All @@ -62,6 +67,7 @@ var (
NoALFlag,
CorpusFlag,
RpcFlag,
RpcsFlag,
TxCountFlag,
CountFlag,
GasLimitFlag,
Expand Down
16 changes: 9 additions & 7 deletions spammer/addresslist.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"math/big"
"math/rand"
"time"

"github.com/ethereum/go-ethereum"
Expand Down Expand Up @@ -144,24 +145,25 @@ func CreateAddresses(N int) ([]string, []string) {
}

func Airdrop(config *Config, value *big.Int) error {
backend := ethclient.NewClient(config.backend)
backend := config.backends[rand.Intn(len(config.backends))]
client := ethclient.NewClient(backend)
sender := crypto.PubkeyToAddress(config.faucet.PublicKey)
fmt.Printf("Airdrop faucet is at %x\n", sender)
var tx *types.Transaction
chainid, err := backend.ChainID(context.Background())
chainid, err := client.ChainID(context.Background())
if err != nil {
fmt.Printf("error getting chain ID; could not airdrop: %v\n", err)
return err
}
for _, addr := range config.keys {
nonce, err := backend.PendingNonceAt(context.Background(), sender)
nonce, err := client.PendingNonceAt(context.Background(), sender)
if err != nil {
fmt.Printf("error getting pending nonce; could not airdrop: %v\n", err)
return err
}
to := crypto.PubkeyToAddress(addr.PublicKey)
gp, _ := backend.SuggestGasPrice(context.Background())
gas, err := backend.EstimateGas(context.Background(), ethereum.CallMsg{
gp, _ := client.SuggestGasPrice(context.Background())
gas, err := client.EstimateGas(context.Background(), ethereum.CallMsg{
From: crypto.PubkeyToAddress(config.faucet.PublicKey),
To: &to,
Gas: 30_000_000,
Expand All @@ -175,15 +177,15 @@ func Airdrop(config *Config, value *big.Int) error {
}
tx2 := types.NewTransaction(nonce, to, value, gas, gp, nil)
signedTx, _ := types.SignTx(tx2, types.LatestSignerForChainID(chainid), config.faucet)
if err := backend.SendTransaction(context.Background(), signedTx); err != nil {
if err := client.SendTransaction(context.Background(), signedTx); err != nil {
fmt.Printf("error sending transaction; could not airdrop: %v\n", err)
return err
}
tx = signedTx
time.Sleep(10 * time.Millisecond)
}
// Wait for the last transaction to be mined
if _, err := bind.WaitMined(context.Background(), backend, tx); err != nil {
if _, err := bind.WaitMined(context.Background(), client, tx); err != nil {
return err
}
return nil
Expand Down
14 changes: 8 additions & 6 deletions spammer/basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/ecdsa"
"fmt"
"math/big"
"math/rand"
"time"

"github.com/MariusVanDerWijden/FuzzyVM/filler"
Expand All @@ -19,21 +20,22 @@ import (
const TX_TIMEOUT = 5 * time.Minute

func SendBasicTransactions(config *Config, key *ecdsa.PrivateKey, f *filler.Filler) error {
backend := ethclient.NewClient(config.backend)
backend := config.backends[rand.Intn(len(config.backends))]
client := ethclient.NewClient(backend)
sender := crypto.PubkeyToAddress(key.PublicKey)
chainID, err := backend.ChainID(context.Background())
chainID, err := client.ChainID(context.Background())
if err != nil {
log.Warn("Could not get chainID, using default")
chainID = big.NewInt(0x01000666)
}

var lastTx *types.Transaction
for i := uint64(0); i < config.N; i++ {
nonce, err := backend.NonceAt(context.Background(), sender, big.NewInt(-1))
nonce, err := client.NonceAt(context.Background(), sender, big.NewInt(-1))
if err != nil {
return err
}
tx, err := txfuzz.RandomValidTx(config.backend, f, sender, nonce, nil, nil, config.accessList)
tx, err := txfuzz.RandomValidTx(backend, f, sender, nonce, nil, nil, config.accessList)
if err != nil {
log.Warn("Could not create valid tx: %v", nonce)
return err
Expand All @@ -42,7 +44,7 @@ func SendBasicTransactions(config *Config, key *ecdsa.PrivateKey, f *filler.Fill
if err != nil {
return err
}
if err := backend.SendTransaction(context.Background(), signedTx); err != nil {
if err := client.SendTransaction(context.Background(), signedTx); err != nil {
log.Warn("Could not submit transaction: %v", err)
return err
}
Expand All @@ -52,7 +54,7 @@ func SendBasicTransactions(config *Config, key *ecdsa.PrivateKey, f *filler.Fill
if lastTx != nil {
ctx, cancel := context.WithTimeout(context.Background(), TX_TIMEOUT)
defer cancel()
if _, err := bind.WaitMined(ctx, backend, lastTx); err != nil {
if _, err := bind.WaitMined(ctx, client, lastTx); err != nil {
fmt.Printf("Waiting for transactions to be mined failed: %v\n", err.Error())
}
}
Expand Down
14 changes: 8 additions & 6 deletions spammer/blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/ecdsa"
"fmt"
"math/big"
"math/rand"
"time"

"github.com/MariusVanDerWijden/FuzzyVM/filler"
Expand All @@ -17,21 +18,22 @@ import (
)

func SendBlobTransactions(config *Config, key *ecdsa.PrivateKey, f *filler.Filler) error {
backend := ethclient.NewClient(config.backend)
backend := config.backends[rand.Intn(len(config.backends))]
client := ethclient.NewClient(backend)
sender := crypto.PubkeyToAddress(key.PublicKey)
chainID, err := backend.ChainID(context.Background())
chainID, err := client.ChainID(context.Background())
if err != nil {
log.Warn("Could not get chainID, using default")
chainID = big.NewInt(0x01000666)
}

var lastTx *types.Transaction
for i := uint64(0); i < config.N; i++ {
nonce, err := backend.NonceAt(context.Background(), sender, big.NewInt(-1))
nonce, err := client.NonceAt(context.Background(), sender, big.NewInt(-1))
if err != nil {
return err
}
tx, err := txfuzz.RandomBlobTx(config.backend, f, sender, nonce, nil, nil, config.accessList)
tx, err := txfuzz.RandomBlobTx(backend, f, sender, nonce, nil, nil, config.accessList)
if err != nil {
log.Warn("Could not create valid tx: %v", nonce)
return err
Expand All @@ -40,7 +42,7 @@ func SendBlobTransactions(config *Config, key *ecdsa.PrivateKey, f *filler.Fille
if err != nil {
return err
}
if err := backend.SendTransaction(context.Background(), signedTx); err != nil {
if err := client.SendTransaction(context.Background(), signedTx); err != nil {
log.Warn("Could not submit transaction: %v", err)
return err
}
Expand All @@ -51,7 +53,7 @@ func SendBlobTransactions(config *Config, key *ecdsa.PrivateKey, f *filler.Fille
if lastTx != nil {
ctx, cancel := context.WithTimeout(context.Background(), TX_TIMEOUT)
defer cancel()
if _, err := bind.WaitMined(ctx, backend, lastTx); err != nil {
if _, err := bind.WaitMined(ctx, client, lastTx); err != nil {
fmt.Printf("Waiting for transactions to be mined failed: %v\n", err.Error())
}
}
Expand Down
48 changes: 36 additions & 12 deletions spammer/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import (
"crypto/ecdsa"
crand "crypto/rand"
"encoding/binary"
"errors"
"fmt"
"math/rand"
"os"
"strings"

txfuzz "github.com/MariusVanDerWijden/tx-fuzz"
"github.com/MariusVanDerWijden/tx-fuzz/flags"
Expand All @@ -20,7 +22,7 @@ import (
)

type Config struct {
backend *rpc.Client // connection to the rpc provider
backends []*rpc.Client // connection to the rpc provider

N uint64 // number of transactions send per account
faucet *ecdsa.PrivateKey // private key of the faucet account
Expand All @@ -34,11 +36,19 @@ type Config struct {
mut *mutator.Mutator // Mutator based on the seed
}

func NewDefaultConfig(rpcAddr string, N uint64, accessList bool, rng *rand.Rand) (*Config, error) {
func NewDefaultConfig(rpcAddrs string, N uint64, accessList bool, rng *rand.Rand) (*Config, error) {
// Setup RPC
backend, err := rpc.Dial(rpcAddr)
if err != nil {
return nil, err
backends := make([]*rpc.Client, 0)

for _, rpcAddr := range strings.Split(rpcAddrs, ",") {
backend, err := rpc.Dial(rpcAddr)
if err == nil {
backends = append(backends, backend)
}
}

if len(backends) == 0 {
return nil, errors.New("no valid rpc addresses found")
}

// Setup Keys
Expand All @@ -48,7 +58,7 @@ func NewDefaultConfig(rpcAddr string, N uint64, accessList bool, rng *rand.Rand)
}

return &Config{
backend: backend,
backends: backends,
N: N,
faucet: crypto.ToECDSAUnsafe(common.FromHex(txfuzz.SK)),
keys: keys,
Expand All @@ -62,14 +72,28 @@ func NewDefaultConfig(rpcAddr string, N uint64, accessList bool, rng *rand.Rand)

func NewConfigFromContext(c *cli.Context) (*Config, error) {
// Setup RPC
rpcAddr := c.String(flags.RpcFlag.Name)
backend, err := rpc.Dial(rpcAddr)
if err != nil {
return nil, err
var rpcAddrs []string
if rpcs := c.String(flags.RpcsFlag.Name); rpcs != "" {
rpcAddrs = strings.Split(rpcs, ",")
} else {
rpcAddrs = []string{c.String(flags.RpcFlag.Name)}
}

backends := make([]*rpc.Client, 0)
for _, rpcAddr := range rpcAddrs {
backend, err := rpc.Dial(rpcAddr)
if err == nil {
backends = append(backends, backend)
}
}

if len(backends) == 0 {
return nil, errors.New("no valid rpc addresses found")
}

// Setup faucet
faucet := crypto.ToECDSAUnsafe(common.FromHex(txfuzz.SK))
var err error
if sk := c.String(flags.SkFlag.Name); sk != "" {
faucet, err = crypto.ToECDSA(common.FromHex(sk))
if err != nil {
Expand All @@ -94,7 +118,7 @@ func NewConfigFromContext(c *cli.Context) (*Config, error) {
// Setup N
N := c.Int(flags.TxCountFlag.Name)
if N == 0 {
N, err = setupN(backend, len(keys), gasLimit)
N, err = setupN(backends[0], len(keys), gasLimit)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -124,7 +148,7 @@ func NewConfigFromContext(c *cli.Context) (*Config, error) {
}

return &Config{
backend: backend,
backends: backends,
N: uint64(N),
faucet: faucet,
accessList: !c.Bool(flags.NoALFlag.Name),
Expand Down
15 changes: 8 additions & 7 deletions spammer/eip7702.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,24 @@ import (
)

func Send7702Transactions(config *Config, key *ecdsa.PrivateKey, f *filler.Filler) error {
backend := ethclient.NewClient(config.backend)
backend := config.backends[rand.Intn(len(config.backends))]
client := ethclient.NewClient(backend)
sender := crypto.PubkeyToAddress(key.PublicKey)
chainID, err := backend.ChainID(context.Background())
chainID, err := client.ChainID(context.Background())
if err != nil {
log.Warn("Could not get chainID, using default")
chainID = big.NewInt(0x01000666)
}

var lastTx *types.Transaction
for i := uint64(0); i < config.N; i++ {
nonce, err := backend.NonceAt(context.Background(), sender, big.NewInt(-1))
nonce, err := client.NonceAt(context.Background(), sender, big.NewInt(-1))
if err != nil {
return err
}

authorizer := config.keys[rand.Intn(len(config.keys))]
nonceAuth, err := backend.NonceAt(context.Background(), crypto.PubkeyToAddress(authorizer.PublicKey), big.NewInt(-1))
nonceAuth, err := client.NonceAt(context.Background(), crypto.PubkeyToAddress(authorizer.PublicKey), big.NewInt(-1))
if err != nil {
return err
}
Expand All @@ -50,7 +51,7 @@ func Send7702Transactions(config *Config, key *ecdsa.PrivateKey, f *filler.Fille
return err
}

tx, err := txfuzz.RandomAuthTx(config.backend, f, sender, nonce, nil, nil, config.accessList, types.AuthorizationList{auth})
tx, err := txfuzz.RandomAuthTx(backend, f, sender, nonce, nil, nil, config.accessList, types.AuthorizationList{auth})
if err != nil {
fmt.Printf("Could not create valid tx: %v", nonce)
return err
Expand All @@ -59,7 +60,7 @@ func Send7702Transactions(config *Config, key *ecdsa.PrivateKey, f *filler.Fille
if err != nil {
return err
}
if err := backend.SendTransaction(context.Background(), signedTx); err != nil {
if err := client.SendTransaction(context.Background(), signedTx); err != nil {
fmt.Printf("Could not submit transaction: %v", err)
return err
}
Expand All @@ -69,7 +70,7 @@ func Send7702Transactions(config *Config, key *ecdsa.PrivateKey, f *filler.Fille
if lastTx != nil {
ctx, cancel := context.WithTimeout(context.Background(), TX_TIMEOUT)
defer cancel()
if _, err := bind.WaitMined(ctx, backend, lastTx); err != nil {
if _, err := bind.WaitMined(ctx, client, lastTx); err != nil {
fmt.Printf("Waiting for transactions to be mined failed: %v\n", err.Error())
}
}
Expand Down
9 changes: 6 additions & 3 deletions spammer/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"math/big"
"math/rand"
"time"

"github.com/ethereum/go-ethereum"
Expand Down Expand Up @@ -75,8 +76,9 @@ func Unstuck(config *Config) error {

func tryUnstuck(config *Config, sk *ecdsa.PrivateKey) error {
var (
client = ethclient.NewClient(config.backend)
addr = crypto.PubkeyToAddress(sk.PublicKey)
backend = config.backends[rand.Intn(len(config.backends))]
client = ethclient.NewClient(backend)
addr = crypto.PubkeyToAddress(sk.PublicKey)
)
for i := 0; i < 100; i++ {
noTx, err := isStuck(config, addr)
Expand Down Expand Up @@ -107,7 +109,8 @@ func tryUnstuck(config *Config, sk *ecdsa.PrivateKey) error {
}

func isStuck(config *Config, account common.Address) (uint64, error) {
client := ethclient.NewClient(config.backend)
backend := config.backends[rand.Intn(len(config.backends))]
client := ethclient.NewClient(backend)
nonce, err := client.NonceAt(context.Background(), account, nil)
if err != nil {
return 0, err
Expand Down