From 241bebe9fa19411574542a5eb12b50b5ca079c2d Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Sun, 8 Oct 2023 22:15:11 +0200 Subject: [PATCH] cmd/livefuzzer: big refactor of the livefuzzer (#37) * cmd/livefuzzer: big refactor of the livefuzzer * cmd/livefuzzer: cleanup * cmd/livefuzzer: happy lint, happy life --- cmd/livefuzzer/addresslist.go | 12 ++- cmd/livefuzzer/basic.go | 84 ++---------------- cmd/livefuzzer/blob.go | 52 ++--------- cmd/livefuzzer/config.go | 137 +++++++++++++++++++++++++++++ cmd/livefuzzer/flags.go | 21 ++++- cmd/livefuzzer/helper.go | 17 +--- cmd/livefuzzer/main.go | 160 ++++++++-------------------------- cmd/livefuzzer/spam.go | 41 +++++++++ 8 files changed, 254 insertions(+), 270 deletions(-) create mode 100644 cmd/livefuzzer/config.go create mode 100644 cmd/livefuzzer/spam.go diff --git a/cmd/livefuzzer/addresslist.go b/cmd/livefuzzer/addresslist.go index 237d993..e2bbbea 100644 --- a/cmd/livefuzzer/addresslist.go +++ b/cmd/livefuzzer/addresslist.go @@ -5,7 +5,6 @@ import ( "fmt" "math/big" - txfuzz "github.com/MariusVanDerWijden/tx-fuzz" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -14,7 +13,7 @@ import ( ) var ( - keys = []string{ + staticKeys = []string{ "0xaf5ead4413ff4b78bc94191a2926ae9ccbec86ce099d65aaf469e9eb1a0fa87f", "0xe63135ee5310c0b34c551e4683ad926dce90062b15e43275f9189b0f29bc784c", "0xc216a7b5048e6ea2437b20bc9c7f9a57cc8aefd5aaf6a991c4db407218ed9e77", @@ -244,10 +243,9 @@ func createAddresses(N int) ([]string, []string) { return keys, addrs } -func airdrop(value *big.Int) error { - client, sk, _ := getRealBackend() - backend := ethclient.NewClient(client) - sender := common.HexToAddress(txfuzz.ADDR) +func airdrop(config *Config, value *big.Int) error { + backend := ethclient.NewClient(config.backend) + sender := crypto.PubkeyToAddress(config.faucet.PublicKey) var tx *types.Transaction chainid, err := backend.ChainID(context.Background()) if err != nil { @@ -263,7 +261,7 @@ func airdrop(value *big.Int) error { to := common.HexToAddress(addr) gp, _ := backend.SuggestGasPrice(context.Background()) tx2 := types.NewTransaction(nonce, to, value, 21000, gp, nil) - signedTx, _ := types.SignTx(tx2, types.LatestSignerForChainID(chainid), sk) + signedTx, _ := types.SignTx(tx2, types.LatestSignerForChainID(chainid), config.faucet) if err := backend.SendTransaction(context.Background(), signedTx); err != nil { fmt.Printf("error sending transaction; could not airdrop: %v\n", err) return err diff --git a/cmd/livefuzzer/basic.go b/cmd/livefuzzer/basic.go index 3318c9d..c0d983a 100644 --- a/cmd/livefuzzer/basic.go +++ b/cmd/livefuzzer/basic.go @@ -3,96 +3,22 @@ package main import ( "context" "crypto/ecdsa" - crand "crypto/rand" - "encoding/binary" "fmt" "math/big" - "math/rand" - "sync" "time" "github.com/MariusVanDerWijden/FuzzyVM/filler" txfuzz "github.com/MariusVanDerWijden/tx-fuzz" - "github.com/MariusVanDerWijden/tx-fuzz/mutator" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rpc" ) -func setup(backend *rpc.Client, seed int64, N uint64) (int64, *mutator.Mutator, uint64) { - // Setup seed - if seed == 0 { - fmt.Println("No seed provided, creating one") - rnd := make([]byte, 8) - crand.Read(rnd) - s := int64(binary.BigEndian.Uint64(rnd)) - seed = s - } - - // Setup N - client := ethclient.NewClient(backend) - header, err := client.HeaderByNumber(context.Background(), nil) - if err != nil { - panic(err) - } - if N == 0 { - txPerBlock := header.GasLimit / uint64(defaultGas) - txPerAccount := txPerBlock / uint64(len(keys)) - N = txPerAccount - if N == 0 { - N = 1 - } - } - - mut := mutator.NewMutator(rand.New(rand.NewSource(seed))) - return seed, mut, N -} - -func SpamBasicTransactions(N uint64, fromCorpus bool, accessList bool, seed int64) { - backend, _, err := getRealBackend() - if err != nil { - log.Warn("Could not get backend", "error", err) - return - } - - // Set up the randomness - seed, mut, N := setup(backend, seed, N) - random := make([]byte, 10000) - mut.FillBytes(&random) - - fmt.Printf("Spamming %v transactions per account on %v accounts with seed: 0x%x\n", N, len(keys), seed) - // Now let everyone spam baikal transactions - var wg sync.WaitGroup - wg.Add(len(keys)) - for i := range keys { - var f *filler.Filler - if fromCorpus { - elem := corpus[rand.Int31n(int32(len(corpus)))] - mut.MutateBytes(&elem) - f = filler.NewFiller(elem) - } else { - // Use lower entropy randomness for filler - mut.MutateBytes(&random) - f = filler.NewFiller(random) - } - // Start a fuzzing thread - go func(key, addr string, filler *filler.Filler) { - defer wg.Done() - sk := crypto.ToECDSAUnsafe(common.FromHex(key)) - SendBasicTransactions(backend, sk, f, addr, N, accessList) - }(keys[i], addrs[i], f) - } - wg.Wait() -} - -func SendBasicTransactions(client *rpc.Client, key *ecdsa.PrivateKey, f *filler.Filler, addr string, N uint64, al bool) { - backend := ethclient.NewClient(client) - - sender := common.HexToAddress(addr) +func SendBasicTransactions(config *Config, key *ecdsa.PrivateKey, f *filler.Filler) { + backend := ethclient.NewClient(config.backend) + sender := crypto.PubkeyToAddress(key.PublicKey) chainID, err := backend.ChainID(context.Background()) if err != nil { log.Warn("Could not get chainID, using default") @@ -100,13 +26,13 @@ func SendBasicTransactions(client *rpc.Client, key *ecdsa.PrivateKey, f *filler. } var lastTx *types.Transaction - for i := uint64(0); i < N; i++ { + for i := uint64(0); i < config.n; i++ { nonce, err := backend.NonceAt(context.Background(), sender, big.NewInt(-1)) if err != nil { log.Warn("Could not get nonce: %v", nonce) continue } - tx, err := txfuzz.RandomValidTx(client, f, sender, nonce, nil, nil, al) + tx, err := txfuzz.RandomValidTx(config.backend, f, sender, nonce, nil, nil, config.accessList) if err != nil { log.Warn("Could not create valid tx: %v", nonce) continue diff --git a/cmd/livefuzzer/blob.go b/cmd/livefuzzer/blob.go index d0bfa18..0b11d76 100644 --- a/cmd/livefuzzer/blob.go +++ b/cmd/livefuzzer/blob.go @@ -5,62 +5,22 @@ import ( "crypto/ecdsa" "fmt" "math/big" - "math/rand" "strings" - "sync" "time" "github.com/MariusVanDerWijden/FuzzyVM/filler" txfuzz "github.com/MariusVanDerWijden/tx-fuzz" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "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/ethclient" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rpc" ) -func SpamBlobTransactions(N uint64, fromCorpus bool, accessList bool, seed int64) { - backend, _, err := getRealBackend() - if err != nil { - log.Warn("Could not get backend", "error", err) - return - } - // Set up the randomness - random := make([]byte, 10000) - seed, mut, N := setup(backend, seed, N) - - fmt.Printf("Spamming %v blob transactions per account on %v accounts with seed: 0x%x\n", N, len(keys), seed) - // Now let everyone spam blob transactions - var wg sync.WaitGroup - wg.Add(len(keys)) - for i := range keys { - var f *filler.Filler - if fromCorpus { - elem := corpus[rand.Int31n(int32(len(corpus)))] - mut.MutateBytes(&elem) - f = filler.NewFiller(elem) - } else { - // Use lower entropy randomness for filler - mut.MutateBytes(&random) - f = filler.NewFiller(random) - } - // Start a fuzzing thread - go func(key, addr string, filler *filler.Filler) { - defer wg.Done() - sk := crypto.ToECDSAUnsafe(common.FromHex(key)) - SendBlobTransactions(backend, sk, f, addr, N, accessList) - }(keys[i], addrs[i], f) - } - wg.Wait() -} - -func SendBlobTransactions(client *rpc.Client, key *ecdsa.PrivateKey, f *filler.Filler, addr string, N uint64, al bool) { - backend := ethclient.NewClient(client) - - sender := common.HexToAddress(addr) +func SendBlobTransactions(config *Config, key *ecdsa.PrivateKey, f *filler.Filler) { + backend := ethclient.NewClient(config.backend) + sender := crypto.PubkeyToAddress(key.PublicKey) chainID, err := backend.ChainID(context.Background()) if err != nil { log.Warn("Could not get chainID, using default") @@ -68,13 +28,13 @@ func SendBlobTransactions(client *rpc.Client, key *ecdsa.PrivateKey, f *filler.F } var lastTx *types.Transaction - for i := uint64(0); i < N; i++ { + for i := uint64(0); i < config.n; i++ { nonce, err := backend.NonceAt(context.Background(), sender, big.NewInt(-1)) if err != nil { log.Warn("Could not get nonce: %v", nonce) continue } - tx, err := txfuzz.RandomBlobTx(client, f, sender, nonce, nil, nil, al) + tx, err := txfuzz.RandomBlobTx(config.backend, f, sender, nonce, nil, nil, config.accessList) if err != nil { log.Warn("Could not create valid tx: %v", nonce) continue @@ -88,7 +48,7 @@ func SendBlobTransactions(client *rpc.Client, key *ecdsa.PrivateKey, f *filler.F if err != nil { panic(err) } - if err := client.CallContext(context.Background(), nil, "eth_sendRawTransaction", hexutil.Encode(rlpData)); err != nil { + if err := config.backend.CallContext(context.Background(), nil, "eth_sendRawTransaction", hexutil.Encode(rlpData)); err != nil { if strings.Contains(err.Error(), "account limit exceeded") { // Back off for a bit if we send a lot of transactions at once time.Sleep(1 * time.Minute) diff --git a/cmd/livefuzzer/config.go b/cmd/livefuzzer/config.go new file mode 100644 index 0000000..9280f3c --- /dev/null +++ b/cmd/livefuzzer/config.go @@ -0,0 +1,137 @@ +package main + +import ( + "context" + "crypto/ecdsa" + crand "crypto/rand" + "encoding/binary" + "fmt" + "math/rand" + "os" + + txfuzz "github.com/MariusVanDerWijden/tx-fuzz" + "github.com/MariusVanDerWijden/tx-fuzz/mutator" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" + "github.com/urfave/cli/v2" +) + +type Config struct { + backend *rpc.Client // connection to the rpc provider + + n uint64 // number of transactions send per account + faucet *ecdsa.PrivateKey // private key of the faucet account + keys []*ecdsa.PrivateKey // private keys of accounts + corpus [][]byte // optional corpus to use elements from + accessList bool // whether to create accesslist transactions + gasLimit uint64 // gas limit per transaction + + seed int64 // seed used for generating randomness + mut *mutator.Mutator // Mutator based on the seed +} + +func NewConfigFromContext(c *cli.Context) (*Config, error) { + // Setup RPC + rpcAddr := c.String(rpcFlag.Name) + backend, err := rpc.Dial(rpcAddr) + if err != nil { + return nil, err + } + + // Setup faucet + faucet := crypto.ToECDSAUnsafe(common.FromHex(txfuzz.SK)) + if sk := c.String(skFlag.Name); sk != "" { + faucet, err = crypto.ToECDSA(common.FromHex(sk)) + if err != nil { + return nil, err + } + } + + // Setup Keys + var keys []*ecdsa.PrivateKey + nKeys := c.Int(countFlag.Name) + if nKeys == 0 || nKeys > len(staticKeys) { + fmt.Printf("Sanitizing count flag from %v to %v\n", nKeys, len(staticKeys)) + nKeys = len(staticKeys) + } + for i := 0; i < nKeys; i++ { + keys = append(keys, crypto.ToECDSAUnsafe(common.FromHex(staticKeys[i]))) + } + + // Setup gasLimit + gasLimit := c.Int(gasLimitFlag.Name) + + // Setup N + N := c.Int(txCountFlag.Name) + if N == 0 { + N, err = setupN(backend, len(keys), gasLimit) + if err != nil { + return nil, err + } + } + + // Setup seed + seed := c.Int64(seedFlag.Name) + if seed == 0 { + fmt.Println("No seed provided, creating one") + rnd := make([]byte, 8) + crand.Read(rnd) + seed = int64(binary.BigEndian.Uint64(rnd)) + } + + // Setup Mutator + mut := mutator.NewMutator(rand.New(rand.NewSource(seed))) + + // Setup corpus + var corpus [][]byte + if corpusFile := c.String(corpusFlag.Name); corpusFile != "" { + corpus, err = readCorpusElements(corpusFile) + if err != nil { + return nil, err + } + } + + return &Config{ + backend: backend, + n: uint64(N), + faucet: faucet, + accessList: !c.Bool(noALFlag.Name), + gasLimit: uint64(gasLimit), + seed: seed, + keys: keys, + corpus: corpus, + mut: mut, + }, nil +} + +func setupN(backend *rpc.Client, keys int, gasLimit int) (int, error) { + client := ethclient.NewClient(backend) + header, err := client.HeaderByNumber(context.Background(), nil) + if err != nil { + return 0, err + } + txPerBlock := int(header.GasLimit / uint64(gasLimit)) + txPerAccount := txPerBlock / keys + if txPerAccount == 0 { + return 1, nil + } + return txPerAccount, nil +} + +func readCorpusElements(path string) ([][]byte, error) { + stats, err := os.ReadDir(path) + if err != nil { + return nil, err + } + corpus := make([][]byte, 0, len(stats)) + for _, file := range stats { + b, err := os.ReadFile(fmt.Sprintf("%v/%v", path, file.Name())) + if err != nil { + return nil, err + } + corpus = append(corpus, b) + } + return corpus, nil +} diff --git a/cmd/livefuzzer/flags.go b/cmd/livefuzzer/flags.go index b7419b5..ed8c05c 100644 --- a/cmd/livefuzzer/flags.go +++ b/cmd/livefuzzer/flags.go @@ -27,8 +27,8 @@ var ( } countFlag = &cli.IntFlag{ - Name: "count", - Usage: "Count of addresses to create", + Name: "accounts", + Usage: "Count of accounts to send transactions from", Value: 100, } @@ -43,4 +43,21 @@ var ( Usage: "Number of transactions send per account per block, 0 = best estimate", Value: 0, } + + gasLimitFlag = &cli.IntFlag{ + Name: "gaslimit", + Usage: "Gas limit used for transactions", + Value: 100_000, + } + + spamFlags = []cli.Flag{ + skFlag, + seedFlag, + noALFlag, + corpusFlag, + rpcFlag, + txCountFlag, + countFlag, + gasLimitFlag, + } ) diff --git a/cmd/livefuzzer/helper.go b/cmd/livefuzzer/helper.go index fa5e1ec..a6997c5 100644 --- a/cmd/livefuzzer/helper.go +++ b/cmd/livefuzzer/helper.go @@ -11,21 +11,9 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" ) -func getRealBackend() (*rpc.Client, *ecdsa.PrivateKey, error) { - // eth.sendTransaction({from:personal.listAccounts[0], to:"0xb02A2EdA1b317FBd16760128836B0Ac59B560e9D", value: "100000000000000"}) - - sk := crypto.ToECDSAUnsafe(common.FromHex(txfuzz.SK)) - if crypto.PubkeyToAddress(sk.PublicKey).Hex() != txfuzz.ADDR { - panic(fmt.Sprintf("wrong address want %s got %s", crypto.PubkeyToAddress(sk.PublicKey).Hex(), txfuzz.ADDR)) - } - cl, err := rpc.Dial(address) - return cl, sk, err -} - -func sendTx(sk *ecdsa.PrivateKey, backend *ethclient.Client, to common.Address, value *big.Int) error { +func SendTx(sk *ecdsa.PrivateKey, backend *ethclient.Client, to common.Address, value *big.Int) error { sender := common.HexToAddress(txfuzz.ADDR) nonce, err := backend.PendingNonceAt(context.Background(), sender) if err != nil { @@ -42,7 +30,8 @@ func sendTx(sk *ecdsa.PrivateKey, backend *ethclient.Client, to common.Address, return backend.SendTransaction(context.Background(), signedTx) } -func unstuck(sk *ecdsa.PrivateKey, backend *ethclient.Client, sender, to common.Address, value, gasPrice *big.Int) error { +func unstuck(sk *ecdsa.PrivateKey, backend *ethclient.Client, to common.Address, value, gasPrice *big.Int) error { + sender := crypto.PubkeyToAddress(sk.PublicKey) blocknumber, err := backend.BlockNumber(context.Background()) if err != nil { return err diff --git a/cmd/livefuzzer/main.go b/cmd/livefuzzer/main.go index 088da1a..042d7b2 100644 --- a/cmd/livefuzzer/main.go +++ b/cmd/livefuzzer/main.go @@ -1,27 +1,20 @@ package main import ( + "crypto/ecdsa" "fmt" "math/big" "os" "sync" "time" - txfuzz "github.com/MariusVanDerWijden/tx-fuzz" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" ) -var ( - address = "http://127.0.0.1:8545" - corpus [][]byte - defaultGas = 100000 -) - var airdropCommand = &cli.Command{ Name: "airdrop", Usage: "Airdrops to a list of accounts", @@ -36,28 +29,14 @@ var spamCommand = &cli.Command{ Name: "spam", Usage: "Send spam transactions", Action: runBasicSpam, - Flags: []cli.Flag{ - skFlag, - seedFlag, - noALFlag, - corpusFlag, - rpcFlag, - txCountFlag, - }, + Flags: spamFlags, } var blobSpamCommand = &cli.Command{ Name: "blobs", Usage: "Send blob spam transactions", Action: runBlobSpam, - Flags: []cli.Flag{ - skFlag, - seedFlag, - noALFlag, - corpusFlag, - rpcFlag, - txCountFlag, - }, + Flags: spamFlags, } var unstuckCommand = &cli.Command{ @@ -69,15 +48,7 @@ var unstuckCommand = &cli.Command{ rpcFlag, }, } -var sendCommand = &cli.Command{ - Name: "send", - Usage: "Sends a single transaction", - Action: runSend, - Flags: []cli.Flag{ - skFlag, - rpcFlag, - }, -} + var createCommand = &cli.Command{ Name: "create", Usage: "Create ephemeral accounts", @@ -97,7 +68,6 @@ func initApp() *cli.App { spamCommand, blobSpamCommand, unstuckCommand, - sendCommand, createCommand, } return app @@ -113,124 +83,70 @@ func main() { } } -func unstuckTransactions() { - backend, _, err := getRealBackend() - if err != nil { - log.Warn("Could not get backend", "error", err) - return - } - client := ethclient.NewClient(backend) - // Now let everyone spam baikal transactions +func unstuckTransactions(config *Config) { + client := ethclient.NewClient(config.backend) + faucetAddr := crypto.PubkeyToAddress(config.faucet.PublicKey) var wg sync.WaitGroup - wg.Add(len(keys)) - for i, key := range keys { - go func(key, addr string) { - sk := crypto.ToECDSAUnsafe(common.FromHex(key)) - unstuck(sk, client, common.HexToAddress(addr), common.HexToAddress(addr), common.Big0, nil) + 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, addrs[i]) + }(key) } wg.Wait() } -func readCorpusElements(path string) ([][]byte, error) { - stats, err := os.ReadDir(path) +func runAirdrop(c *cli.Context) error { + config, err := NewConfigFromContext(c) if err != nil { - return nil, err + return err } - corpus := make([][]byte, 0, len(stats)) - for _, file := range stats { - b, err := os.ReadFile(fmt.Sprintf("%v/%v", path, file.Name())) - if err != nil { - return nil, err - } - corpus = append(corpus, b) - } - return corpus, nil -} - -func send() { - backend, _, _ := getRealBackend() - client := ethclient.NewClient(backend) - to := common.HexToAddress(txfuzz.ADDR) - sk := crypto.ToECDSAUnsafe(common.FromHex(txfuzz.SK2)) - value := new(big.Int).Mul(big.NewInt(100000), big.NewInt(params.Ether)) - sendTx(sk, client, to, value) -} - -func runAirdrop(c *cli.Context) error { - setupDefaults(c) - txPerAccount := 10000 + txPerAccount := config.n airdropValue := new(big.Int).Mul(big.NewInt(int64(txPerAccount*100000)), big.NewInt(params.GWei)) - airdrop(airdropValue) + airdrop(config, airdropValue) return nil } -func spam(c *cli.Context, basic bool) error { - setupDefaults(c) - noAL := c.Bool(noALFlag.Name) - seed := c.Int64(seedFlag.Name) - txPerAccount := c.Int(txCountFlag.Name) - // Setup corpus if needed - if corpusFile := c.String(corpusFlag.Name); corpusFile != "" { - cp, err := readCorpusElements(corpusFile) - if err != nil { - panic(err) - } - corpus = cp - } - // Limit amount of accounts - keys = keys[:10] - addrs = addrs[:10] - +func spam(config *Config, spamFn Spam, airdropValue *big.Int) error { for { - airdropValue := new(big.Int).Mul(big.NewInt(int64((1+txPerAccount)*1000000)), big.NewInt(params.GWei)) - if !basic { - airdropValue.Mul(airdropValue, big.NewInt(100)) // Blob txs are more expensive - } - if err := airdrop(airdropValue); err != nil { + if err := airdrop(config, airdropValue); err != nil { return err } - if basic { - SpamBasicTransactions(uint64(txPerAccount), false, !noAL, seed) - } else { - SpamBlobTransactions(uint64(txPerAccount), false, !noAL, seed) - } + SpamTransactions(config, spamFn) time.Sleep(12 * time.Second) } } func runBasicSpam(c *cli.Context) error { - return spam(c, true) + config, err := 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) } func runBlobSpam(c *cli.Context) error { - return spam(c, false) + config, err := NewConfigFromContext(c) + if err != nil { + return err + } + 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, SendBasicTransactions, airdropValue) } func runUnstuck(c *cli.Context) error { - setupDefaults(c) - unstuckTransactions() - return nil -} - -func runSend(c *cli.Context) error { - setupDefaults(c) - send() + config, err := NewConfigFromContext(c) + if err != nil { + return err + } + unstuckTransactions(config) return nil } func runCreate(c *cli.Context) error { - setupDefaults(c) createAddresses(100) return nil } - -func setupDefaults(c *cli.Context) { - if sk := c.String(skFlag.Name); sk != "" { - txfuzz.SK = sk - sk := crypto.ToECDSAUnsafe(common.FromHex(txfuzz.SK)) - txfuzz.ADDR = crypto.PubkeyToAddress(sk.PublicKey).Hex() - } - address = c.String(rpcFlag.Name) -} diff --git a/cmd/livefuzzer/spam.go b/cmd/livefuzzer/spam.go new file mode 100644 index 0000000..4391e86 --- /dev/null +++ b/cmd/livefuzzer/spam.go @@ -0,0 +1,41 @@ +package main + +import ( + "crypto/ecdsa" + "fmt" + "math/rand" + "sync" + + "github.com/MariusVanDerWijden/FuzzyVM/filler" +) + +type Spam func(*Config, *ecdsa.PrivateKey, *filler.Filler) + +func SpamTransactions(config *Config, fun Spam) { + fmt.Printf("Spamming %v transactions per account on %v accounts with seed: 0x%x\n", config.n, len(config.keys), config.seed) + + var wg sync.WaitGroup + wg.Add(len(config.keys)) + for _, key := range config.keys { + // Setup randomness uniquely per key + random := make([]byte, 10000) + config.mut.FillBytes(&random) + + var f *filler.Filler + if len(config.corpus) != 0 { + elem := config.corpus[rand.Int31n(int32(len(config.corpus)))] + config.mut.MutateBytes(&elem) + f = filler.NewFiller(elem) + } else { + // Use lower entropy randomness for filler + config.mut.MutateBytes(&random) + f = filler.NewFiller(random) + } + // Start a fuzzing thread + go func(key *ecdsa.PrivateKey, filler *filler.Filler) { + defer wg.Done() + fun(config, key, f) + }(key, f) + } + wg.Wait() +}