Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DVT-812] Conformance Fuzzing Library #87

Merged
merged 11 commits into from
Jun 30, 2023
Merged

[DVT-812] Conformance Fuzzing Library #87

merged 11 commits into from
Jun 30, 2023

Conversation

IdrisHanafi
Copy link
Contributor

@IdrisHanafi IdrisHanafi commented Jun 23, 2023

Description

Fuzzing functionality integrated into the arguments of the JSON RPC calls, by running with the --fuzz flag. The fuzzer's effectiveness becomes evident through multiple iterations of running fuzzed tests (default to 100 times), with the expected outcome being an error returned by the RPC.

Jira / Linear Tickets

Testing

Test run:

$ time go run main.go rpcfuzz http://localhost:8545 --fuzz --fuzzn 5
5:32PM INF Loaded private key ethAddress=0x85dA99c8a7C2C95964c8EfD687E95E632Fc533D6
5:32PM INF enabling namespaces namespaces=["eth_","web3_","net_"]
5:32PM TRC Doing test setup
5:32PM TRC current nonce value curNonce=1
5:32PM TRC fetch chainid chainId=1337
...
5:40PM INF 1/1 Test(s) Passed Method=net_version
5:40PM INF 1/1 Test(s) Passed Method=web3_clientVersion
5:40PM INF 1/1 Test(s) Passed Method=web3_sha3
5:40PM INF 1/1 Test(s) Passed Method=web3_sha3
5:40PM INF 1/1 Test(s) Passed Method=net_listening
5:40PM INF 1/1 Test(s) Passed Method=net_peerCount
5:40PM INF 1/1 Test(s) Passed Method=eth_protocolVersion
5:40PM INF 1/1 Test(s) Passed Method=eth_syncing
5:40PM INF 1/1 Test(s) Passed Method=eth_coinbase
5:40PM INF 1/1 Test(s) Passed Method=eth_chainId
5:40PM INF 1/1 Test(s) Passed Method=eth_mining
5:40PM INF 1/1 Test(s) Passed Method=eth_hashrate
5:40PM INF 1/1 Test(s) Passed Method=eth_hashrate
5:40PM INF 1/1 Test(s) Passed Method=eth_gasPrice
5:40PM INF 1/1 Test(s) Passed Method=eth_accounts
5:40PM INF 1/1 Test(s) Passed Method=eth_blockNumber
5:40PM INF 1/1 Test(s) Passed Method=eth_getBalance
5:40PM INF 1/1 Test(s) Passed Method=eth_getBalance
5:40PM INF 1/1 Test(s) Passed Method=eth_getBalance
5:40PM INF 1/1 Test(s) Passed Method=eth_getBalance
5:40PM INF 1/1 Test(s) Passed Method=eth_getStorageAt
5:40PM INF 1/1 Test(s) Passed Method=eth_getStorageAt
5:40PM INF 1/1 Test(s) Passed Method=eth_getStorageAt
5:40PM INF 1/1 Test(s) Passed Method=eth_getStorageAt
5:40PM INF 1/1 Test(s) Passed Method=eth_getTransactionCount
5:40PM INF 1/1 Test(s) Passed Method=eth_getTransactionCount
5:40PM INF 1/1 Test(s) Passed Method=eth_getTransactionCount
5:40PM INF 1/1 Test(s) Passed Method=eth_getTransactionCount
5:40PM INF 1/1 Test(s) Passed Method=eth_getBlockTransactionCountByHash
5:40PM INF 1/1 Test(s) Passed Method=eth_getBlockTransactionCountByHash
5:40PM INF 1/1 Test(s) Passed Method=eth_getBlockTransactionCountByNumber
5:40PM INF 1/1 Test(s) Passed Method=eth_getBlockTransactionCountByNumber
5:40PM INF 1/1 Test(s) Passed Method=eth_getBlockTransactionCountByNumber
5:40PM INF 1/1 Test(s) Passed Method=eth_getBlockTransactionCountByNumber
5:40PM INF 1/1 Test(s) Passed Method=eth_getUncleCountByBlockHash
5:40PM INF 1/1 Test(s) Passed Method=eth_getUncleCountByBlockHash
5:40PM INF 1/1 Test(s) Passed Method=eth_getUncleCountByBlockNumber
5:40PM INF 1/1 Test(s) Passed Method=eth_getUncleCountByBlockNumber
5:40PM INF 1/1 Test(s) Passed Method=eth_getUncleCountByBlockNumber
5:40PM INF 1/1 Test(s) Passed Method=eth_getUncleCountByBlockNumber
5:40PM INF 1/1 Test(s) Passed Method=eth_getCode
5:40PM INF 1/1 Test(s) Passed Method=eth_getCode
5:40PM INF 1/1 Test(s) Passed Method=eth_getCode
5:40PM INF 1/1 Test(s) Passed Method=eth_sign
5:40PM INF 1/1 Test(s) Passed Method=eth_sign
5:40PM INF 1/1 Test(s) Passed Method=eth_signTransaction
5:40PM INF 1/1 Test(s) Passed Method=eth_sendTransaction
5:40PM INF 1/1 Test(s) Passed Method=eth_sendRawTransaction
5:40PM INF 1/1 Test(s) Passed Method=eth_call
5:40PM INF 1/1 Test(s) Passed Method=eth_call
5:40PM INF 1/1 Test(s) Passed Method=eth_call
5:40PM INF 1/1 Test(s) Passed Method=eth_call
5:40PM INF 1/1 Test(s) Passed Method=eth_estimateGas
5:40PM INF 1/1 Test(s) Passed Method=eth_getBlockByHash
5:40PM INF 1/1 Test(s) Passed Method=eth_getBlockByHash
5:40PM INF 1/1 Test(s) Passed Method=eth_getBlockByNumber
5:40PM INF 1/1 Test(s) Passed Method=eth_getBlockByNumber
5:40PM INF 0/1 Test(s) Passed Method=eth_getTransactionByHash
5:40PM INF 0/1 Test(s) Passed Method=eth_getTransactionByBlockHashAndIndex
5:40PM INF 0/1 Test(s) Passed Method=eth_getTransactionByBlockNumberAndIndex
5:40PM INF 0/1 Test(s) Passed Method=eth_getTransactionReceipt
5:40PM INF 1/1 Test(s) Passed Method=eth_getUncleByBlockHashAndIndex
5:40PM INF 1/1 Test(s) Passed Method=eth_getUncleByBlockNumberAndIndex
5:40PM INF 1/1 Test(s) Passed Method=eth_getCompilers
5:40PM INF 1/1 Test(s) Passed Method=eth_compileSolidity
5:40PM INF 1/1 Test(s) Passed Method=eth_compileLLL
5:40PM INF 1/1 Test(s) Passed Method=eth_compileSerpent
5:40PM INF 1/1 Test(s) Passed Method=eth_newFilter
5:40PM INF 1/1 Test(s) Passed Method=eth_newFilter
5:40PM INF 1/1 Test(s) Passed Method=eth_newFilter
5:40PM INF 1/1 Test(s) Passed Method=eth_newFilter
5:40PM INF 1/1 Test(s) Passed Method=eth_newFilter
5:40PM INF 1/1 Test(s) Passed Method=eth_newFilter
5:40PM INF 1/1 Test(s) Passed Method=eth_newBlockFilter
5:40PM INF 1/1 Test(s) Passed Method=eth_newPendingTransactionFilter
5:40PM INF 1/1 Test(s) Passed Method=eth_uninstallFilter
5:40PM INF 1/1 Test(s) Passed Method=eth_uninstallFilter
5:40PM INF 1/1 Test(s) Passed Method=eth_getFilterChanges
5:40PM INF 0/1 Test(s) Passed Method=eth_getFilterLogs
5:40PM INF 0/1 Test(s) Passed Method=eth_getLogs
5:40PM INF 1/1 Test(s) Passed Method=eth_getWork
5:40PM INF 1/1 Test(s) Passed Method=eth_submitWork
5:40PM INF 1/1 Test(s) Passed Method=eth_submitHashrate
5:40PM INF 1/1 Test(s) Passed Method=eth_feeHistory
5:40PM INF 1/1 Test(s) Passed Method=eth_maxPriorityFeePerGas
5:40PM INF 1/1 Test(s) Passed Method=eth_createAccessList
5:40PM INF 1/1 Test(s) Passed Method=eth_getProof
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-net_version
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-web3_clientVersion
5:40PM INF 4/5 Test(s) Passed Method=fuzzed-web3_sha3
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-net_peerCount
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-net_listening
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-web3_sha3
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_syncing
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_protocolVersion
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_coinbase
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_mining
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_chainId
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_hashrate
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_hashrate
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_gasPrice
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_accounts
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_blockNumber
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBalance
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBalance
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBalance
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBalance
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getStorageAt
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getStorageAt
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getStorageAt
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getTransactionCount
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getStorageAt
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getTransactionCount
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getTransactionCount
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getTransactionCount
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBlockTransactionCountByHash
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBlockTransactionCountByHash
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBlockTransactionCountByNumber
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBlockTransactionCountByNumber
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBlockTransactionCountByNumber
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBlockTransactionCountByNumber
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getUncleCountByBlockHash
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getUncleCountByBlockNumber
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getUncleCountByBlockNumber
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getUncleCountByBlockNumber
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getUncleCountByBlockHash
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getUncleCountByBlockNumber
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getCode
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getCode
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getCode
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_sign
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_sign
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_signTransaction
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_sendTransaction
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_sendRawTransaction
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_call
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_call
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_call
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_call
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_estimateGas
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBlockByHash
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBlockByHash
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBlockByNumber
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getBlockByNumber
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getTransactionByHash
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getTransactionByBlockHashAndIndex
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getUncleByBlockHashAndIndex
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_compileSolidity
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getUncleByBlockNumberAndIndex
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getCompilers
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_compileSerpent
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_compileLLL
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_newFilter
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_newFilter
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_newFilter
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_newFilter
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_newFilter
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_newFilter
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_newBlockFilter
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_newPendingTransactionFilter
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_uninstallFilter
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_uninstallFilter
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getFilterChanges
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getFilterLogs
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getWork
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getLogs
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_submitWork
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_submitHashrate
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_feeHistory
5:40PM INF 5/5 Test(s) Passed Method=fuzzed-eth_maxPriorityFeePerGas
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_createAccessList
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getProof
5:40PM INF 0/5 Test(s) Passed Method=fuzzed-eth_getTransactionByBlockNumberAndIndex
go run main.go rpcfuzz http://localhost:8545 --fuzz --fuzzn 5  3.37s user 1.76s system 1% cpu 8:06.41 total

What's next?

  • Summarizing test results

@IdrisHanafi IdrisHanafi changed the title Initial Fuzzer Initial Fuzzer Library Jun 23, 2023
Base automatically changed from jhilliard/extended-conformance to main June 26, 2023 19:29
@IdrisHanafi IdrisHanafi marked this pull request as ready for review June 27, 2023 21:56
@IdrisHanafi IdrisHanafi marked this pull request as draft June 27, 2023 22:00
@IdrisHanafi IdrisHanafi marked this pull request as ready for review June 27, 2023 22:02
@IdrisHanafi IdrisHanafi changed the title Initial Fuzzer Library [DVT-812] Conformance Fuzzing Library Jun 27, 2023
Copy link
Member

@praetoriansentry praetoriansentry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Headed in the right direction but i had a few questions.

)

func MutateExecutor(arg []byte, c fuzz.Continue) []byte {
switch rand.Intn(10) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a little brittle. I.e. you need to keep this hard coded number and the number of cases in this switch statement in sync. It might be worth making an interface of the various mutators and putting them into a list at somepoint.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

}

func ByteMutator(arg []byte, c fuzz.Continue) []byte {
if arg == nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is interesting. Does this mean you can't mutate nil input? It seems like you'd still want that the be mutable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated it so that it can take nil's now. see below comment!

Comment on lines 57 to 59
if d == nil {
continue
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above. Given that we're fuzzing, it seems like you would fuzz a nil the same way that you would fuzz anything else especially since the fuzzer can produce nil outputs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true...i just updated it so that if it's nil, it will be set to a random string then go through the regular mutator. I wonder what would be a better approach here, i.e. set it to a random value (int, string, etc.) then run it through the mutators?

Comment on lines 147 to 149
if n == 0 {
return arg
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This base case seems a little odd. Same potential consider as the other nil checks. If the input is empty you're not doing any mutation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point! updated, this base case should only happen on delete mutators as there wouldn't be anything to delete in an empty byte slice

Comment on lines 1681 to 1688
currTestResult := testreporter.TestResult{
Name: currTest.GetName(),
Method: currTest.GetMethod(),
Args: make([][]interface{}, n),
Result: make([]interface{}, n),
Errors: make([]error, n),
NumberOfTestsRan: n,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say, if you're going to go through the trouble of creating a type of test results, you might want to have an actual constructor to avoid this constructions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added! 🧠 💡

}

if err != nil {
currTestResult.NumberOfTestsFailed++
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thought with all this ++. YOu might want something like

r := testreporter.New(curTest) // it should be able to get all of the information that it needs from the test interface
r.Passed()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the suggestion, i updated it to incorporate that.

Comment on lines 161 to 162
wg sync.WaitGroup
mutex sync.Mutex
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These aren't helpful names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

- updated mutation support for nils, float32, and float64
- cleaned up testreporter for pass/fail tests
- improved code readability and maintainability via refactors and docs
@IdrisHanafi IdrisHanafi merged commit ab47b71 into main Jun 30, 2023
@gatsbyz gatsbyz deleted the feat/fuzz-testing branch June 30, 2023 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants