Skip to content

Commit

Permalink
txfuzz: refactor tx creation, remove unused functions (#39)
Browse files Browse the repository at this point in the history
* txfuzz: refactor tx creation, remove unused functions

* cmd/livefuzzer: add default config constructor

* txfuzz: happy lint

* cmd/livefuzzer: move spammer to spammer package

* spammer: removed unused function

* spammer: only airdrop to active addresses

* spammer: happy lint

* cmd/livefuzzer: implement unstuck command

* cmd/livefuzzer: implement unstuck command

* spammer: fix sendTx

* spammer: fix sendtx

* spammer: fix sendtx finally

* spammer: unstuck transactions before spamming
  • Loading branch information
MariusVanDerWijden authored Oct 16, 2023
1 parent 172b73f commit eb98970
Show file tree
Hide file tree
Showing 13 changed files with 473 additions and 476 deletions.
126 changes: 70 additions & 56 deletions accesslist.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/rpc"
)

// CreateAccessList creates a new access list for a transaction via the eth_createAccessList.
func CreateAccessList(client *rpc.Client, tx *types.Transaction, from common.Address) (*types.AccessList, error) {
msg := ethereum.CallMsg{
From: from,
Expand All @@ -23,10 +24,6 @@ func CreateAccessList(client *rpc.Client, tx *types.Transaction, from common.Add
Data: tx.Data(),
AccessList: nil,
}
return createAccessList(client, msg)
}

func createAccessList(client *rpc.Client, msg ethereum.CallMsg) (*types.AccessList, error) {
if client == nil {
return &types.AccessList{}, nil
}
Expand All @@ -35,64 +32,81 @@ func createAccessList(client *rpc.Client, msg ethereum.CallMsg) (*types.AccessLi
return al, err
}

type accessListMutator func(list *types.AccessList) *types.AccessList

var mutators = []accessListMutator{
noChange,
delete,
addRandom,
replaceRandom,
replaceRandomSlot,
fullyRandom,
}

// MutateAccessList mutates the given access list.
func MutateAccessList(list types.AccessList) *types.AccessList {
switch rand.Int31n(5) {
case 0:
// Leave the accesslist as is
return &list
case 1:
// delete the access list
return &types.AccessList{}
case 2:
// empty the access list
return &types.AccessList{}
case 3:
// add a random entry and random slots to the list
addr := randomAddress()
keys := []common.Hash{}
for i := 0; i < rand.Intn(10); i++ {
h := randomHash()
keys = append(keys, h)
}
tuple := types.AccessTuple{Address: addr, StorageKeys: keys}
newList := types.AccessList(append([]types.AccessTuple{tuple}, list...))
return &newList
case 4:
// replace a random entry and random slots of it in the list
slot := list[rand.Int31n(int32(len(list)))]
index := rand.Intn(len(mutators))
return mutators[index](&list)
}

// Leave the accesslist as is
func noChange(list *types.AccessList) *types.AccessList { return list }

// empty the access list
func delete(list *types.AccessList) *types.AccessList { return &types.AccessList{} }

// add a random entry and random slots to the list
func addRandom(list *types.AccessList) *types.AccessList {
addr := randomAddress()
keys := []common.Hash{}
for i := 0; i < rand.Intn(10); i++ {
h := randomHash()
keys = append(keys, h)
}
tuple := types.AccessTuple{Address: addr, StorageKeys: keys}
newList := types.AccessList(append([]types.AccessTuple{tuple}, *list...))
return &newList
}

// replace a random entry and random slots of it in the list
func replaceRandom(list *types.AccessList) *types.AccessList {
slot := (*list)[rand.Int31n(int32(len(*list)))]
addr := randomAddress()
keys := []common.Hash{}
if len(slot.StorageKeys) == 0 {
return list
}
for i := 0; i < rand.Intn(len(slot.StorageKeys)); i++ {
h := randomHash()
keys = append(keys, h)
}
tuple := types.AccessTuple{Address: addr, StorageKeys: keys}
newList := types.AccessList(append([]types.AccessTuple{tuple}, *list...))
return &newList
}

// replace a random slot in an existing entry
func replaceRandomSlot(list *types.AccessList) *types.AccessList {
keyIdx := rand.Int31n(int32(len(*list)))
slotIdx := rand.Int31n(int32(len((*list)[keyIdx].StorageKeys)))
h := randomHash()
(*list)[keyIdx].StorageKeys[slotIdx] = h
return list
}

func fullyRandom(list *types.AccessList) *types.AccessList {
var accesslist []types.AccessTuple
for i := 0; i < rand.Int(); i++ {
addr := randomAddress()
keys := []common.Hash{}
if len(slot.StorageKeys) == 0 {
break
}
for i := 0; i < rand.Intn(len(slot.StorageKeys)); i++ {
// create a fully random access list
for q := 0; q < rand.Int(); q++ {
h := randomHash()
keys = append(keys, h)
}
tuple := types.AccessTuple{Address: addr, StorageKeys: keys}
newList := types.AccessList(append([]types.AccessTuple{tuple}, list...))
return &newList
case 5:
// replace a random slot in an existing entry
keyIdx := rand.Int31n(int32(len(list)))
slotIdx := rand.Int31n(int32(len(list[keyIdx].StorageKeys)))
h := randomHash()
list[keyIdx].StorageKeys[slotIdx] = h
case 6:
var accesslist []types.AccessTuple
for i := 0; i < rand.Int(); i++ {
addr := randomAddress()
keys := []common.Hash{}
// create a fully random access list
for q := 0; q < rand.Int(); q++ {
h := randomHash()
keys = append(keys, h)
}
tuple := types.AccessTuple{Address: addr, StorageKeys: keys}
accesslist = append(accesslist, tuple)
}
newList := types.AccessList(accesslist)
return &newList
accesslist = append(accesslist, tuple)
}
return &list
newList := types.AccessList(accesslist)
return &newList
}
54 changes: 0 additions & 54 deletions cmd/livefuzzer/helper.go

This file was deleted.

93 changes: 37 additions & 56 deletions cmd/livefuzzer/main.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package main

import (
"crypto/ecdsa"
"fmt"
"math/big"
"os"
"sync"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/MariusVanDerWijden/tx-fuzz/flags"
"github.com/MariusVanDerWijden/tx-fuzz/spammer"
"github.com/ethereum/go-ethereum/params"
"github.com/urfave/cli/v2"
)
Expand All @@ -20,45 +17,42 @@ var airdropCommand = &cli.Command{
Usage: "Airdrops to a list of accounts",
Action: runAirdrop,
Flags: []cli.Flag{
skFlag,
rpcFlag,
flags.SkFlag,
flags.RpcFlag,
},
}

var spamCommand = &cli.Command{
Name: "spam",
Usage: "Send spam transactions",
Action: runBasicSpam,
Flags: spamFlags,
Flags: flags.SpamFlags,
}

var blobSpamCommand = &cli.Command{
Name: "blobs",
Usage: "Send blob spam transactions",
Action: runBlobSpam,
Flags: spamFlags,
}

var unstuckCommand = &cli.Command{
Name: "unstuck",
Usage: "Tries to unstuck an account",
Action: runUnstuck,
Flags: []cli.Flag{
skFlag,
rpcFlag,
},
Flags: flags.SpamFlags,
}

var createCommand = &cli.Command{
Name: "create",
Usage: "Create ephemeral accounts",
Action: runCreate,
Flags: []cli.Flag{
countFlag,
rpcFlag,
flags.CountFlag,
flags.RpcFlag,
},
}

var unstuckCommand = &cli.Command{
Name: "unstuck",
Usage: "Tries to unstuck an account",
Action: runUnstuck,
Flags: flags.SpamFlags,
}

func initApp() *cli.App {
app := cli.NewApp()
app.Name = "tx-fuzz"
Expand All @@ -67,8 +61,8 @@ func initApp() *cli.App {
airdropCommand,
spamCommand,
blobSpamCommand,
unstuckCommand,
createCommand,
unstuckCommand,
}
return app
}
Expand All @@ -83,70 +77,57 @@ func main() {
}
}

func unstuckTransactions(config *Config) {
client := ethclient.NewClient(config.backend)
faucetAddr := crypto.PubkeyToAddress(config.faucet.PublicKey)
var wg sync.WaitGroup
wg.Add(len(config.keys))
for _, key := range config.keys {
go func(key *ecdsa.PrivateKey) {
unstuck(config.faucet, client, faucetAddr, common.Big0, nil)
wg.Done()
}(key)
}
wg.Wait()
}

func runAirdrop(c *cli.Context) error {
config, err := NewConfigFromContext(c)
config, err := spammer.NewConfigFromContext(c)
if err != nil {
return err
}
txPerAccount := config.n
txPerAccount := config.N
airdropValue := new(big.Int).Mul(big.NewInt(int64(txPerAccount*100000)), big.NewInt(params.GWei))
airdrop(config, airdropValue)
spammer.Airdrop(config, airdropValue)
return nil
}

func spam(config *Config, spamFn Spam, airdropValue *big.Int) error {
func spam(config *spammer.Config, spamFn spammer.Spam, airdropValue *big.Int) error {
// Make sure the accounts are unstuck before sending any transactions
spammer.Unstuck(config)
for {
if err := airdrop(config, airdropValue); err != nil {
if err := spammer.Airdrop(config, airdropValue); err != nil {
return err
}
SpamTransactions(config, spamFn)
spammer.SpamTransactions(config, spamFn)
time.Sleep(12 * time.Second)
}
}

func runBasicSpam(c *cli.Context) error {
config, err := NewConfigFromContext(c)
config, err := spammer.NewConfigFromContext(c)
if err != nil {
return err
}
airdropValue := new(big.Int).Mul(big.NewInt(int64((1+config.n)*1000000)), big.NewInt(params.GWei))
return spam(config, SendBasicTransactions, airdropValue)
airdropValue := new(big.Int).Mul(big.NewInt(int64((1+config.N)*1000000)), big.NewInt(params.GWei))
return spam(config, spammer.SendBasicTransactions, airdropValue)
}

func runBlobSpam(c *cli.Context) error {
config, err := NewConfigFromContext(c)
config, err := spammer.NewConfigFromContext(c)
if err != nil {
return err
}
airdropValue := new(big.Int).Mul(big.NewInt(int64((1+config.n)*1000000)), big.NewInt(params.GWei))
airdropValue := new(big.Int).Mul(big.NewInt(int64((1+config.N)*1000000)), big.NewInt(params.GWei))
airdropValue = airdropValue.Mul(airdropValue, big.NewInt(100))
return spam(config, SendBlobTransactions, airdropValue)
return spam(config, spammer.SendBlobTransactions, airdropValue)
}

func runCreate(c *cli.Context) error {
spammer.CreateAddresses(100)
return nil
}

func runUnstuck(c *cli.Context) error {
config, err := NewConfigFromContext(c)
config, err := spammer.NewConfigFromContext(c)
if err != nil {
return err
}
unstuckTransactions(config)
return nil
}

func runCreate(c *cli.Context) error {
createAddresses(100)
return nil
return spammer.Unstuck(config)
}
2 changes: 1 addition & 1 deletion london.go → cmd/london/london.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package txfuzz
package main

import (
"github.com/ethereum/go-ethereum/core/vm"
Expand Down
Loading

0 comments on commit eb98970

Please sign in to comment.