Skip to content

Commit

Permalink
API fuzzing. Set fuzz time to 30s (#1759)
Browse files Browse the repository at this point in the history
* API fuzzing. Set fuzz time to 30s

* Added fuzz test for dispatcher

* Filter manager fuzz tests

* CR changes

* Fixed fuzzing argument and seeds
  • Loading branch information
jelacamarko committed Aug 17, 2023
1 parent 689e360 commit ea53ae0
Show file tree
Hide file tree
Showing 6 changed files with 478 additions and 5 deletions.
15 changes: 14 additions & 1 deletion consensus/polybft/stake_manager_fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/0xPolygon/polygon-edge/consensus/polybft/wallet"
"github.com/0xPolygon/polygon-edge/types"
"github.com/hashicorp/go-hclog"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -120,6 +121,12 @@ func FuzzTestStakeManagerPostBlock(f *testing.F) {
BlockID: 11,
StakeValue: 70,
},
{
EpochID: 7,
ValidatorID: 1,
BlockID: 2,
StakeValue: 10,
},
}

for _, seed := range seeds {
Expand Down Expand Up @@ -149,14 +156,20 @@ func FuzzTestStakeManagerPostBlock(f *testing.F) {

validatorSetAddr := types.StringToAddress("0x0001")

bcMock := new(blockchainMock)
for i := 0; i < int(data.BlockID); i++ {
bcMock.On("GetHeaderByNumber", mock.Anything).Return(&types.Header{Hash: types.Hash{6, 4}}, true).Once()
bcMock.On("GetReceiptsByHash", mock.Anything).Return([]*types.Receipt{{}}, error(nil)).Once()
}

stakeManager := newStakeManager(
hclog.NewNullLogger(),
state,
nil,
wallet.NewEcdsaSigner(validators.GetValidator("A").Key()),
validatorSetAddr,
types.StringToAddress("0x0002"),
nil,
bcMock,
5,
)

Expand Down
44 changes: 44 additions & 0 deletions jsonrpc/codec_fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package jsonrpc

import (
"testing"

"github.com/0xPolygon/polygon-edge/types"
"github.com/stretchr/testify/assert"
)

func FuzzBlockNumberOrHashUnmarshalJSON(f *testing.F) {
var blockHash types.Hash
err := blockHash.UnmarshalText([]byte("0xe0ee62fd4a39a6988e24df0b406b90af71932e1b01d5561400a8eab943a33d68"))
assert.NoError(f, err)

seeds := []string{

`{"blockHash": "", "blockNumber": ""}`,

`{"blockHash": "0xe0ee62fd4a39a6988e24df0b406b90af71932e1b01d5561400a8eab943a33d68", "blockNumber": "0x0"}`,

`{"blockNumber": "abc"}`,

`{"blockNumber": ""}`,

`"latest"`,

`{"blockNumber": "0x0"}`,

`"0x0"`,

`{"blockHash": "0xe0ee62fd4a39a6988e24df0b406b90af71932e1b01d5561400a8eab943a33d68"}`,
}

for _, seed := range seeds {
f.Add(seed)
}

f.Fuzz(func(t *testing.T, input string) {
t.Parallel()

bnh := BlockNumberOrHash{}
_ = bnh.UnmarshalJSON([]byte(input))
})
}
256 changes: 256 additions & 0 deletions jsonrpc/dispatcher_fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
package jsonrpc

import (
"fmt"
"testing"

"github.com/0xPolygon/polygon-edge/types"
"github.com/hashicorp/go-hclog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func FuzzDispatcherFuncDecode(f *testing.F) {
srv := &mockService{msgCh: make(chan interface{}, 10)}

dispatcher := newTestDispatcher(f,
hclog.NewNullLogger(),
newMockStore(),
&dispatcherParams{
chainID: 0,
priceLimit: 0,
jsonRPCBatchLengthLimit: 20,
blockRangeLimit: 1000,
},
)

require.NoError(f, dispatcher.registerService("mock", srv))

handleReq := func(typ string, msg string) interface{} {
_, err := dispatcher.handleReq(Request{
Method: "mock_" + typ,
Params: []byte(msg),
})
if err != nil {
return err
}

return <-srv.msgCh
}

addr1 := types.Address{0x1}

seeds := []struct {
typ string
msg string
}{
{
"block",
`["earliest"]`,
},
{
"block",
`["latest"]`,
},
{
"block",
`["0x1"]`,
},
{
"type",
`["` + addr1.String() + `"]`,
},
{
"blockPtr",
`["a"]`,
},
{
"blockPtr",
`["a", "latest"]`,
},
{
"filter",
`[{"fromBlock": "pending", "toBlock": "earliest"}]`,
},
{
"block",
"[\"8\"]",
},
{
"block",
"[\"009\"]",
},
{
"block",
"10",
},
}

for _, seed := range seeds {
f.Add(seed.typ, seed.msg)
}

f.Fuzz(func(t *testing.T, typ string, msg string) {
handleReq(typ, msg)
})
}

func FuzzDispatcherBatchRequest(f *testing.F) {
mock := &mockWsConn{
SetFilterIDFn: func(s string) {
},
GetFilterIDFn: func() string {
return ""
},
WriteMessageFn: func(i int, b []byte) error {
return nil
},
}

seeds := []struct {
batchLimit uint64
blockLimit uint64
params string
}{
{
batchLimit: 10,
blockLimit: 1000,
params: `["0x1", true]`,
},
{
batchLimit: 3,
blockLimit: 1000,
params: `["0x2", true]`,
},
{
batchLimit: 0,
blockLimit: 0,
params: `["0x68656c6c6f20776f726c64"]`,
},
{
batchLimit: 5,
blockLimit: 30,
params: "invalid request",
},
}

for _, seed := range seeds {
f.Add(seed.batchLimit, seed.blockLimit, seed.params)
}

f.Fuzz(func(t *testing.T, batchLimit uint64, blockLimit uint64, params string) {
dispatcher := newTestDispatcher(t,
hclog.NewNullLogger(),
newMockStore(),
&dispatcherParams{
chainID: 0,
priceLimit: 0,
jsonRPCBatchLengthLimit: batchLimit,
blockRangeLimit: blockLimit,
},
)

body := fmt.Sprintf(`[{"id":1,"jsonrpc":"2.0","method":"eth_getBlockByNumber","params": %s}]`, params)

_, err := dispatcher.HandleWs([]byte(body), mock)
assert.NoError(t, err)
_, err = dispatcher.Handle([]byte(body))
assert.NoError(t, err)
})
}

func FuzzDispatcherWebsocketConnectionUnsubscribe(f *testing.F) {
store := newMockStore()
dispatcher := newTestDispatcher(f,
hclog.NewNullLogger(),
store,
&dispatcherParams{
chainID: 0,
priceLimit: 0,
jsonRPCBatchLengthLimit: 20,
blockRangeLimit: 1000,
},
)
mockConn := &mockWsConn{
SetFilterIDFn: func(s string) {
},
GetFilterIDFn: func() string {
return ""
},
WriteMessageFn: func(i int, b []byte) error {
return nil
},
}

seeds := []string{
`{"method": "eth_unsubscribe", "params": ["787832"]}`,
`{"method": "eth_subscribe", "params": ["newHeads"]}`,
}

for _, seed := range seeds {
f.Add(seed)
}

f.Fuzz(func(t *testing.T, request string) {
_, err := dispatcher.HandleWs([]byte(request), mockConn)
assert.NoError(t, err)
})
}

func FuzzDispatcherWebSocketConnectionRequestFormats(f *testing.F) {
store := newMockStore()
dispatcher := newTestDispatcher(f,
hclog.NewNullLogger(),
store,
&dispatcherParams{
chainID: 0,
priceLimit: 0,
jsonRPCBatchLengthLimit: 20,
blockRangeLimit: 1000,
},
)
mockConnection, _ := newMockWsConnWithMsgCh()

seeds := []string{
`{
"method": "eth_subscribe",
"params": ["newHeads"],
"id": "abc"
}`,
`{
"method": "eth_subscribe",
"params": ["newHeads"],
"id": null
}`,
`{
"method": "eth_subscribe",
"params": ["newHeads"],
"id": 2.1
}`,
`{
"method": "eth_subscribe",
"params": ["newHeads"]
}`,
`{
"method": "eth_subscribe",
"params": ["newHeads"],
"id": 2.0
}`,
`{
}`,
`{
"x": "x",
"y": "y",
"z": "z",
}`,
}

for _, seed := range seeds {
f.Add(seed)
}

f.Fuzz(func(t *testing.T, request string) {
_, _ = dispatcher.HandleWs([]byte(request), mockConnection)
})
}
6 changes: 3 additions & 3 deletions jsonrpc/dispatcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -557,11 +557,11 @@ func TestDispatcher_WebsocketConnection_Unsubscribe(t *testing.T) {
assert.Equal(t, "true", string(resp.Result))
}

func newTestDispatcher(t *testing.T, logger hclog.Logger, store JSONRPCStore, params *dispatcherParams) *Dispatcher {
t.Helper()
func newTestDispatcher(tb testing.TB, logger hclog.Logger, store JSONRPCStore, params *dispatcherParams) *Dispatcher {
tb.Helper()

d, err := newDispatcher(logger, store, params)
require.NoError(t, err)
require.NoError(tb, err)

return d
}
Loading

0 comments on commit ea53ae0

Please sign in to comment.