Co-authored-by: Emmanuel T Odeke <emmanuel@orijtech.com> Closes #5907 - add init-corpus to blockchain reactor - remove validator-set FromBytes test now that we have proto, we don't need to test it! bye amino - simplify mempool test do we want to test remote ABCI app? - do not recreate mux on every crash in jsonrpc test - update p2p pex reactor test - remove p2p/listener test the API has changed + I did not understand what it's tested anyway - update secretconnection test - add readme and makefile - list inputs in readme - add nightly workflow - remove blockchain fuzz test EncodeMsg / DecodeMsg no longer existpull/5961/head
@ -0,0 +1,63 @@ | |||
# Runs fuzzing nightly. | |||
name: fuzz-nightly | |||
on: | |||
workflow_dispatch: # allow running workflow manually | |||
schedule: | |||
- cron: '0 3 * * *' | |||
jobs: | |||
fuzz-nightly-test: | |||
runs-on: ubuntu-latest | |||
steps: | |||
- uses: actions/setup-go@v2 | |||
with: | |||
go-version: '1.15' | |||
- uses: actions/checkout@v2 | |||
- name: Install go-fuzz | |||
working-directory: test/fuzz | |||
run: go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build | |||
- name: Fuzz mempool | |||
working-directory: test/fuzz | |||
run: timeout 10m make fuzz-mempool | |||
- name: Fuzz p2p-addrbook | |||
working-directory: test/fuzz | |||
run: timeout 10m make fuzz-p2p-addrbook | |||
- name: Fuzz p2p-pex | |||
working-directory: test/fuzz | |||
run: timeout 10m make fuzz-p2p-pex | |||
- name: Fuzz p2p-sc | |||
working-directory: test/fuzz | |||
run: timeout 10m make fuzz-p2p-sc | |||
- name: Fuzz p2p-rpc-server | |||
working-directory: test/fuzz | |||
run: timeout 10m make fuzz-rpc-server | |||
- name: Set crashers count | |||
working-directory: test/fuzz | |||
run: echo "::set-output name=crashers-count::$(find . -type d -name "crashers" | xargs -I % sh -c 'ls % | wc -l' | awk '{total += $1} END {print total}')" | |||
id: set-crashers-count | |||
outputs: | |||
crashers_count: ${{ steps.set-crashers-count.outputs.crashers-count }} | |||
fuzz-nightly-fail: | |||
needs: fuzz-nightly-test | |||
if: ${{ needs.set-crashers-count.outputs.crashers-count != 0 }} | |||
runs-on: ubuntu-latest | |||
steps: | |||
- name: Notify Slack if any crashers | |||
uses: rtCamp/action-slack-notify@ae4223259071871559b6e9d08b24a63d71b3f0c0 | |||
env: | |||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} | |||
SLACK_CHANNEL: tendermint-internal | |||
SLACK_USERNAME: Nightly Fuzz Tests | |||
SLACK_ICON_EMOJI: ':skull:' | |||
SLACK_COLOR: danger | |||
SLACK_MESSAGE: Crashers found in Nightly Fuzz tests | |||
SLACK_FOOTER: '' |
@ -0,0 +1,39 @@ | |||
#!/usr/bin/make -f | |||
.PHONY: fuzz-mempool | |||
fuzz-mempool: | |||
cd mempool && \ | |||
rm -f *-fuzz.zip && \ | |||
go-fuzz-build && \ | |||
go-fuzz | |||
.PHONY: fuzz-p2p-addrbook | |||
fuzz-p2p-addrbook: | |||
cd p2p/addrbook && \ | |||
rm -f *-fuzz.zip && \ | |||
go run ./init-corpus/main.go && \ | |||
go-fuzz-build && \ | |||
go-fuzz | |||
.PHONY: fuzz-p2p-pex | |||
fuzz-p2p-pex: | |||
cd p2p/pex && \ | |||
rm -f *-fuzz.zip && \ | |||
go run ./init-corpus/main.go && \ | |||
go-fuzz-build && \ | |||
go-fuzz | |||
.PHONY: fuzz-p2p-sc | |||
fuzz-p2p-sc: | |||
cd p2p/secret_connection && \ | |||
rm -f *-fuzz.zip && \ | |||
go run ./init-corpus/main.go && \ | |||
go-fuzz-build && \ | |||
go-fuzz | |||
.PHONY: fuzz-rpc-server | |||
fuzz-rpc-server: | |||
cd rpc/jsonrpc/server && \ | |||
rm -f *-fuzz.zip && \ | |||
go-fuzz-build && \ | |||
go-fuzz |
@ -0,0 +1,72 @@ | |||
# fuzz | |||
Fuzzing for various packages in Tendermint using [go-fuzz](https://github.com/dvyukov/go-fuzz) library. | |||
Inputs: | |||
- mempool `CheckTx` (using kvstore in-process ABCI app) | |||
- p2p `Addrbook#AddAddress` | |||
- p2p `pex.Reactor#Receive` | |||
- p2p `SecretConnection#Read` and `SecretConnection#Write` | |||
- rpc jsonrpc server | |||
## Directory structure | |||
``` | |||
| test | |||
| |- corpus/ | |||
| |- crashers/ | |||
| |- init-corpus/ | |||
| |- suppressions/ | |||
| |- testdata/ | |||
| |- <testname>.go | |||
``` | |||
`/corpus` directory contains corpus data. The idea is to help the fuzzier to | |||
understand what bytes sequences are semantically valid (e.g. if we're testing | |||
PNG decoder, then we would put black-white PNG into corpus directory; with | |||
blockchain reactor - we would put blockchain messages into corpus). | |||
`/init-corpus` (if present) contains a script for generating corpus data. | |||
`/testdata` directory may contain an additional data (like `addrbook.json`). | |||
Upon running the fuzzier, `/crashers` and `/suppressions` dirs will be created, | |||
along with <testname>.zip archive. `/crashers` will show any inputs, which have | |||
lead to panics (plus a trace). `/suppressions` will show any suppressed inputs. | |||
## Running | |||
```sh | |||
make fuzz-mempool | |||
make fuzz-p2p-addrbook | |||
make fuzz-p2p-pex | |||
make fuzz-p2p-sc | |||
make fuzz-rpc-server | |||
``` | |||
Each command will create corpus data (if needed), generate a fuzz archive and | |||
call `go-fuzz` executable. | |||
Then watch out for the respective outputs in the fuzzer output to announce new | |||
crashers which can be found in the directory `crashers`. | |||
For example if we find | |||
```sh | |||
ls crashers/ | |||
61bde465f47c93254d64d643c3b2480e0a54666e | |||
61bde465f47c93254d64d643c3b2480e0a54666e.output | |||
61bde465f47c93254d64d643c3b2480e0a54666e.quoted | |||
da39a3ee5e6b4b0d3255bfef95601890afd80709 | |||
da39a3ee5e6b4b0d3255bfef95601890afd80709.output | |||
da39a3ee5e6b4b0d3255bfef95601890afd80709.quoted | |||
``` | |||
the crashing bytes generated by the fuzzer will be in | |||
`61bde465f47c93254d64d643c3b2480e0a54666e` the respective crash report in | |||
`61bde465f47c93254d64d643c3b2480e0a54666e.output` | |||
and the bug report can be created by retrieving the bytes in | |||
`61bde465f47c93254d64d643c3b2480e0a54666e` and feeding those back into the | |||
`Fuzz` function. |
@ -0,0 +1,34 @@ | |||
package checktx | |||
import ( | |||
"github.com/tendermint/tendermint/abci/example/kvstore" | |||
"github.com/tendermint/tendermint/config" | |||
mempl "github.com/tendermint/tendermint/mempool" | |||
"github.com/tendermint/tendermint/proxy" | |||
) | |||
var mempool mempl.Mempool | |||
func init() { | |||
app := kvstore.NewApplication() | |||
cc := proxy.NewLocalClientCreator(app) | |||
appConnMem, _ := cc.NewABCIClient() | |||
err := appConnMem.Start() | |||
if err != nil { | |||
panic(err) | |||
} | |||
cfg := config.DefaultMempoolConfig() | |||
cfg.Broadcast = false | |||
mempool = mempl.NewCListMempool(cfg, appConnMem, 0) | |||
} | |||
func Fuzz(data []byte) int { | |||
err := mempool.CheckTx(data, nil, mempl.TxInfo{}) | |||
if err != nil { | |||
return 0 | |||
} | |||
return 1 | |||
} |
@ -0,0 +1,35 @@ | |||
// nolint: gosec | |||
package addr | |||
import ( | |||
"encoding/json" | |||
"fmt" | |||
"math/rand" | |||
"github.com/tendermint/tendermint/p2p" | |||
"github.com/tendermint/tendermint/p2p/pex" | |||
) | |||
var addrBook = pex.NewAddrBook("./testdata/addrbook.json", true) | |||
func Fuzz(data []byte) int { | |||
addr := new(p2p.NetAddress) | |||
if err := json.Unmarshal(data, addr); err != nil { | |||
return -1 | |||
} | |||
// Fuzz AddAddress. | |||
err := addrBook.AddAddress(addr, addr) | |||
if err != nil { | |||
return 0 | |||
} | |||
// Also, make sure PickAddress always returns a non-nil address. | |||
bias := rand.Intn(100) | |||
if p := addrBook.PickAddress(bias); p == nil { | |||
panic(fmt.Sprintf("picked a nil address (bias: %d, addrBook size: %v)", | |||
bias, addrBook.Size())) | |||
} | |||
return 1 | |||
} |
@ -0,0 +1,58 @@ | |||
// nolint: gosec | |||
package main | |||
import ( | |||
"encoding/json" | |||
"flag" | |||
"fmt" | |||
"io/ioutil" | |||
"log" | |||
"net" | |||
"os" | |||
"path/filepath" | |||
"github.com/tendermint/tendermint/crypto/ed25519" | |||
"github.com/tendermint/tendermint/p2p" | |||
) | |||
func main() { | |||
baseDir := flag.String("base", ".", `where the "corpus" directory will live`) | |||
flag.Parse() | |||
initCorpus(*baseDir) | |||
} | |||
func initCorpus(baseDir string) { | |||
log.SetFlags(0) | |||
// create "corpus" directory | |||
corpusDir := filepath.Join(baseDir, "corpus") | |||
if err := os.MkdirAll(corpusDir, 0755); err != nil { | |||
log.Fatalf("Creating %q err: %v", corpusDir, err) | |||
} | |||
// create corpus | |||
privKey := ed25519.GenPrivKey() | |||
addrs := []*p2p.NetAddress{ | |||
{ID: p2p.NodeIDFromPubKey(privKey.PubKey()), IP: net.IPv4(0, 0, 0, 0), Port: 0}, | |||
{ID: p2p.NodeIDFromPubKey(privKey.PubKey()), IP: net.IPv4(127, 0, 0, 0), Port: 80}, | |||
{ID: p2p.NodeIDFromPubKey(privKey.PubKey()), IP: net.IPv4(213, 87, 10, 200), Port: 8808}, | |||
{ID: p2p.NodeIDFromPubKey(privKey.PubKey()), IP: net.IPv4(111, 111, 111, 111), Port: 26656}, | |||
{ID: p2p.NodeIDFromPubKey(privKey.PubKey()), IP: net.ParseIP("2001:db8::68"), Port: 26656}, | |||
} | |||
for i, addr := range addrs { | |||
filename := filepath.Join(corpusDir, fmt.Sprintf("%d.json", i)) | |||
bz, err := json.Marshal(addr) | |||
if err != nil { | |||
log.Fatalf("can't marshal %v: %v", addr, err) | |||
} | |||
if err := ioutil.WriteFile(filename, bz, 0644); err != nil { | |||
log.Fatalf("can't write %v to %q: %v", addr, filename, err) | |||
} | |||
log.Printf("wrote %q", filename) | |||
} | |||
} |
@ -0,0 +1,82 @@ | |||
// nolint: gosec | |||
package main | |||
import ( | |||
"flag" | |||
"fmt" | |||
"io/ioutil" | |||
"log" | |||
"math/rand" | |||
"os" | |||
"path/filepath" | |||
"github.com/tendermint/tendermint/crypto/ed25519" | |||
"github.com/tendermint/tendermint/p2p" | |||
tmp2p "github.com/tendermint/tendermint/proto/tendermint/p2p" | |||
) | |||
func main() { | |||
baseDir := flag.String("base", ".", `where the "corpus" directory will live`) | |||
flag.Parse() | |||
initCorpus(*baseDir) | |||
} | |||
func initCorpus(rootDir string) { | |||
log.SetFlags(0) | |||
corpusDir := filepath.Join(rootDir, "corpus") | |||
if err := os.MkdirAll(corpusDir, 0755); err != nil { | |||
log.Fatalf("Creating %q err: %v", corpusDir, err) | |||
} | |||
sizes := []int{0, 1, 2, 17, 5, 31} | |||
// Make the PRNG predictable | |||
rand.Seed(10) | |||
for _, n := range sizes { | |||
var addrs []*p2p.NetAddress | |||
// IPv4 addresses | |||
for i := 0; i < n; i++ { | |||
privKey := ed25519.GenPrivKey() | |||
addr := fmt.Sprintf( | |||
"%s@%v.%v.%v.%v:26656", | |||
p2p.NodeIDFromPubKey(privKey.PubKey()), | |||
rand.Int()%256, | |||
rand.Int()%256, | |||
rand.Int()%256, | |||
rand.Int()%256, | |||
) | |||
netAddr, _ := p2p.NewNetAddressString(addr) | |||
addrs = append(addrs, netAddr) | |||
} | |||
// IPv6 addresses | |||
privKey := ed25519.GenPrivKey() | |||
ipv6a, err := p2p.NewNetAddressString( | |||
fmt.Sprintf("%s@[ff02::1:114]:26656", p2p.NodeIDFromPubKey(privKey.PubKey()))) | |||
if err != nil { | |||
log.Fatalf("can't create a new netaddress: %v", err) | |||
} | |||
addrs = append(addrs, ipv6a) | |||
msg := tmp2p.Message{ | |||
Sum: &tmp2p.Message_PexAddrs{ | |||
PexAddrs: &tmp2p.PexAddrs{Addrs: p2p.NetAddressesToProto(addrs)}, | |||
}, | |||
} | |||
bz, err := msg.Marshal() | |||
if err != nil { | |||
log.Fatalf("unable to marshal: %v", err) | |||
} | |||
filename := filepath.Join(rootDir, "corpus", fmt.Sprintf("%d", n)) | |||
if err := ioutil.WriteFile(filename, bz, 0644); err != nil { | |||
log.Fatalf("can't write %X to %q: %v", bz, filename, err) | |||
} | |||
log.Printf("wrote %q", filename) | |||
} | |||
} |
@ -0,0 +1,86 @@ | |||
package pex | |||
import ( | |||
"net" | |||
"github.com/tendermint/tendermint/config" | |||
"github.com/tendermint/tendermint/crypto/ed25519" | |||
"github.com/tendermint/tendermint/libs/log" | |||
"github.com/tendermint/tendermint/libs/service" | |||
"github.com/tendermint/tendermint/p2p" | |||
"github.com/tendermint/tendermint/p2p/pex" | |||
"github.com/tendermint/tendermint/version" | |||
) | |||
var ( | |||
pexR *pex.Reactor | |||
peer p2p.Peer | |||
) | |||
func init() { | |||
addrB := pex.NewAddrBook("./testdata/addrbook1", false) | |||
pexR := pex.NewReactor(addrB, &pex.ReactorConfig{SeedMode: false}) | |||
if pexR == nil { | |||
panic("NewReactor returned nil") | |||
} | |||
pexR.SetLogger(log.NewNopLogger()) | |||
peer := newFuzzPeer() | |||
pexR.AddPeer(peer) | |||
} | |||
func Fuzz(data []byte) int { | |||
// MakeSwitch uses log.TestingLogger which can't be executed in init() | |||
cfg := config.DefaultP2PConfig() | |||
cfg.PexReactor = true | |||
sw := p2p.MakeSwitch(cfg, 0, "127.0.0.1", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { | |||
return sw | |||
}) | |||
pexR.SetSwitch(sw) | |||
pexR.Receive(pex.PexChannel, peer, data) | |||
return 1 | |||
} | |||
type fuzzPeer struct { | |||
*service.BaseService | |||
m map[string]interface{} | |||
} | |||
var _ p2p.Peer = (*fuzzPeer)(nil) | |||
func newFuzzPeer() *fuzzPeer { | |||
fp := &fuzzPeer{m: make(map[string]interface{})} | |||
fp.BaseService = service.NewBaseService(nil, "fuzzPeer", fp) | |||
return fp | |||
} | |||
var privKey = ed25519.GenPrivKey() | |||
var nodeID = p2p.NodeIDFromPubKey(privKey.PubKey()) | |||
var defaultNodeInfo = p2p.NodeInfo{ | |||
ProtocolVersion: p2p.NewProtocolVersion( | |||
version.P2PProtocol, | |||
version.BlockProtocol, | |||
0, | |||
), | |||
NodeID: nodeID, | |||
ListenAddr: "0.0.0.0:98992", | |||
Moniker: "foo1", | |||
} | |||
func (fp *fuzzPeer) FlushStop() {} | |||
func (fp *fuzzPeer) ID() p2p.NodeID { return nodeID } | |||
func (fp *fuzzPeer) RemoteIP() net.IP { return net.IPv4(0, 0, 0, 0) } | |||
func (fp *fuzzPeer) RemoteAddr() net.Addr { | |||
return &net.TCPAddr{IP: fp.RemoteIP(), Port: 98991, Zone: ""} | |||
} | |||
func (fp *fuzzPeer) IsOutbound() bool { return false } | |||
func (fp *fuzzPeer) IsPersistent() bool { return false } | |||
func (fp *fuzzPeer) CloseConn() error { return nil } | |||
func (fp *fuzzPeer) NodeInfo() p2p.NodeInfo { return defaultNodeInfo } | |||
func (fp *fuzzPeer) Status() p2p.ConnectionStatus { var cs p2p.ConnectionStatus; return cs } | |||
func (fp *fuzzPeer) SocketAddr() *p2p.NetAddress { return p2p.NewNetAddress(fp.ID(), fp.RemoteAddr()) } | |||
func (fp *fuzzPeer) Send(byte, []byte) bool { return true } | |||
func (fp *fuzzPeer) TrySend(byte, []byte) bool { return true } | |||
func (fp *fuzzPeer) Set(key string, value interface{}) { fp.m[key] = value } | |||
func (fp *fuzzPeer) Get(key string) interface{} { return fp.m[key] } |
@ -0,0 +1,48 @@ | |||
// nolint: gosec | |||
package main | |||
import ( | |||
"flag" | |||
"fmt" | |||
"io/ioutil" | |||
"log" | |||
"os" | |||
"path/filepath" | |||
) | |||
func main() { | |||
baseDir := flag.String("base", ".", `where the "corpus" directory will live`) | |||
flag.Parse() | |||
initCorpus(*baseDir) | |||
} | |||
func initCorpus(baseDir string) { | |||
log.SetFlags(0) | |||
corpusDir := filepath.Join(baseDir, "corpus") | |||
if err := os.MkdirAll(corpusDir, 0755); err != nil { | |||
log.Fatal(err) | |||
} | |||
data := []string{ | |||
"dadc04c2-cfb1-4aa9-a92a-c0bf780ec8b6", | |||
"", | |||
" ", | |||
" a ", | |||
`{"a": 12, "tsp": 999, k: "blue"}`, | |||
`9999.999`, | |||
`""`, | |||
`Tendermint fuzzing`, | |||
} | |||
for i, datum := range data { | |||
filename := filepath.Join(corpusDir, fmt.Sprintf("%d", i)) | |||
if err := ioutil.WriteFile(filename, []byte(datum), 0644); err != nil { | |||
log.Fatalf("can't write %v to %q: %v", datum, filename, err) | |||
} | |||
log.Printf("wrote %q", filename) | |||
} | |||
} |
@ -0,0 +1,107 @@ | |||
package secretconnection | |||
import ( | |||
"bytes" | |||
"fmt" | |||
"io" | |||
"log" | |||
"github.com/tendermint/tendermint/crypto/ed25519" | |||
"github.com/tendermint/tendermint/libs/async" | |||
sc "github.com/tendermint/tendermint/p2p/conn" | |||
) | |||
func Fuzz(data []byte) int { | |||
if len(data) == 0 { | |||
return -1 | |||
} | |||
fooConn, barConn := makeSecretConnPair() | |||
n, err := fooConn.Write(data) | |||
if err != nil { | |||
panic(err) | |||
} | |||
dataRead := make([]byte, n) | |||
m, err := barConn.Read(dataRead) | |||
if err != nil { | |||
panic(err) | |||
} | |||
if !bytes.Equal(data[:n], dataRead[:m]) { | |||
panic(fmt.Sprintf("bytes written %X != read %X", data[:n], dataRead[:m])) | |||
} | |||
return 1 | |||
} | |||
type kvstoreConn struct { | |||
*io.PipeReader | |||
*io.PipeWriter | |||
} | |||
func (drw kvstoreConn) Close() (err error) { | |||
err2 := drw.PipeWriter.CloseWithError(io.EOF) | |||
err1 := drw.PipeReader.Close() | |||
if err2 != nil { | |||
return err | |||
} | |||
return err1 | |||
} | |||
// Each returned ReadWriteCloser is akin to a net.Connection | |||
func makeKVStoreConnPair() (fooConn, barConn kvstoreConn) { | |||
barReader, fooWriter := io.Pipe() | |||
fooReader, barWriter := io.Pipe() | |||
return kvstoreConn{fooReader, fooWriter}, kvstoreConn{barReader, barWriter} | |||
} | |||
func makeSecretConnPair() (fooSecConn, barSecConn *sc.SecretConnection) { | |||
var ( | |||
fooConn, barConn = makeKVStoreConnPair() | |||
fooPrvKey = ed25519.GenPrivKey() | |||
fooPubKey = fooPrvKey.PubKey() | |||
barPrvKey = ed25519.GenPrivKey() | |||
barPubKey = barPrvKey.PubKey() | |||
) | |||
// Make connections from both sides in parallel. | |||
var trs, ok = async.Parallel( | |||
func(_ int) (val interface{}, abort bool, err error) { | |||
fooSecConn, err = sc.MakeSecretConnection(fooConn, fooPrvKey) | |||
if err != nil { | |||
log.Printf("failed to establish SecretConnection for foo: %v", err) | |||
return nil, true, err | |||
} | |||
remotePubBytes := fooSecConn.RemotePubKey() | |||
if !remotePubBytes.Equals(barPubKey) { | |||
err = fmt.Errorf("unexpected fooSecConn.RemotePubKey. Expected %v, got %v", | |||
barPubKey, fooSecConn.RemotePubKey()) | |||
log.Print(err) | |||
return nil, true, err | |||
} | |||
return nil, false, nil | |||
}, | |||
func(_ int) (val interface{}, abort bool, err error) { | |||
barSecConn, err = sc.MakeSecretConnection(barConn, barPrvKey) | |||
if barSecConn == nil { | |||
log.Printf("failed to establish SecretConnection for bar: %v", err) | |||
return nil, true, err | |||
} | |||
remotePubBytes := barSecConn.RemotePubKey() | |||
if !remotePubBytes.Equals(fooPubKey) { | |||
err = fmt.Errorf("unexpected barSecConn.RemotePubKey. Expected %v, got %v", | |||
fooPubKey, barSecConn.RemotePubKey()) | |||
log.Print(err) | |||
return nil, true, err | |||
} | |||
return nil, false, nil | |||
}, | |||
) | |||
if trs.FirstError() != nil { | |||
log.Fatalf("unexpected error: %v", trs.FirstError()) | |||
} | |||
if !ok { | |||
log.Fatal("Unexpected task abortion") | |||
} | |||
return fooSecConn, barSecConn | |||
} |
@ -0,0 +1,44 @@ | |||
package handler | |||
import ( | |||
"bytes" | |||
"encoding/json" | |||
"io/ioutil" | |||
"net/http" | |||
"net/http/httptest" | |||
"github.com/tendermint/tendermint/libs/log" | |||
rs "github.com/tendermint/tendermint/rpc/jsonrpc/server" | |||
types "github.com/tendermint/tendermint/rpc/jsonrpc/types" | |||
) | |||
var rpcFuncMap = map[string]*rs.RPCFunc{ | |||
"c": rs.NewRPCFunc(func(s string, i int) (string, int) { return "foo", 200 }, "s,i"), | |||
} | |||
var mux *http.ServeMux | |||
func init() { | |||
mux := http.NewServeMux() | |||
buf := new(bytes.Buffer) | |||
lgr := log.NewTMLogger(buf) | |||
rs.RegisterRPCFuncs(mux, rpcFuncMap, lgr) | |||
} | |||
func Fuzz(data []byte) int { | |||
req, _ := http.NewRequest("POST", "http://localhost/", bytes.NewReader(data)) | |||
rec := httptest.NewRecorder() | |||
mux.ServeHTTP(rec, req) | |||
res := rec.Result() | |||
blob, err := ioutil.ReadAll(res.Body) | |||
if err != nil { | |||
panic(err) | |||
} | |||
if err := res.Body.Close(); err != nil { | |||
panic(err) | |||
} | |||
recv := new(types.RPCResponse) | |||
if err := json.Unmarshal(blob, recv); err != nil { | |||
panic(err) | |||
} | |||
return 1 | |||
} |