---
# System prepended metadata

title: Further notes

---

We have a protobuf description of an ABI value, so something like:

```
message VboolPB {
  required bool = 1;
}

message VUIntPB {
  required uint64 = 1;
}

...

message AbiValuePB {
  oneof types_oneof {
    VboolPB = 1;
    VUIntPB = 2;
    ...
  }
}
```


So we can for example represent a value of type ``(uint256,uint256[])`` with values ``(42, [1, 2, 3, 4])``.



During fuzzing we will end up having an Entry point that's called with a message of type ``AbiTypePB``.

This ends up in a C++ entry point like:

```
DEFINE_PROTO_FUZZER(AbiValue const& _input)
{

    std::vector<char> binaryProtobufMessage = _input.serialize();
    // or however this is actually done
    // it may even be possible to catch the binary message before it
    // is de-serialized somewhere "before" "DEFINE_PROTO_FUZZER"
	
    std::string result = executeHaskellProcess("/path/to/haskell/encoder/binary", toHex(binaryProtobufMessage));
    // so we just pass the binary message as argument to a haskell binary.
    // We receive a hex string of the binary encoding of _input.
	
	/*
	 * The following is supposed to generate a contract from
         * message _input, that in the example case looks like this:
	 * contract C {
	 *    function test(uint256 a,uint256[] b) public returns (int) {
	 *        if (a != 42) return 1;
	 *        if (b.length != 4) return 2;
	 *        if (b[0] != 1) return 3;
	 *        if (b[1] != 2) return 4;
	 *        if (b[2] != 3) return 5;
	 *        if (b[3] != 4) return 6;
	 *        return 0;
	 *    }
	 * }
	*/
	std::string contract_source = ProtobufConverter{}.generateContractForAbiValue(_input);
	
	// now we compile the contract contract_source and pass it fromHex(result) as input.
	// The contract will return 0 on success or an error code otherwise.
}
```

This would effectively fuzz the abi decoder for validly encoded data.

===========================

Next to fuzz the encoder we can do the following (assuming the same input):

```
DEFINE_PROTO_FUZZER(AbiValue const& _input)
{

	std::vector<char> binaryProtobufMessage = _input.serialize();
	
	/*
	 * The following is supposed to generate a contract
         * from message _input, that in the example case looks like this:
         *
	 * contract C {
	 *    function f(uint256 a,uint256[] b) public returns (bytes memory msg) {
	 *        return bytes(msg.data[4:]);
	 *        return 0;
	 *    }
	 *    function test(bytes calldata verifiedEncoding) external returns (int) {
	 *       uint256 a = 42;
	 *       bytes b = new bytes(4);
	 *       b[0] = 1;
	 *       b[1] = 2;
	 *       b[2] = 3;
	 *       b[3] = 4;
	 *		 bytes memory solidityEncoding = this.f(a, b);
	 *       if (verifiedEncoding.length != solidityEncoding.length) return 1;
	 *       for (int i = 0; i < verifiedEncoding.length; i++)
	 *       	if (verifiedEncoding[i] != solidityEncoding[i]) return 1000 + i;
	 *       return 0;
	 *    }
	 * }
	*/
	std::string contract_source = ProtobufConverter{}.generateContractForAbiValue(_input);
	
	// now we compile the contract contract_source and pass it fromHex(result) as input.
	// The contract will return 0 on success or an error code otherwise.
}
```

===========================

But even better we can actually try fuzzing on *invalid* data:


```
DEFINE_PROTO_FUZZER(AbiValue const& _input)
{

	std::vector<char> binaryProtobufMessage = _input.serialize();
    
	std::string encoding = executeHaskellProcess("/path/to/haskell/encoder/binary", toHex(binaryProtobufMessage));
	flipRandomBits(encoding);
        // So we flip random bits in result - what we get may still be
        // a valid encoding, but also may no longer be valid!
        // Alternatively we can just choose an encoding at random instead.
        // Maybe we can actually do both.
	
	std::string result = executeHaskellProcess("/path/to/haskell/decoder/binary", toHex(binaryProtobufMessage), toHex(encoding));
        // So we call a second haskell binary that will just return 1
        // if ``encoding`` is a valid encoding of the same type as
        // the AbiValue in ``encoding``.
	
	/*
	 * The following is supposed to generate a contract from message _input, that in the example case looks like this:
	 * contract C {
	 *    function test(uint256 a,uint256[] b) public returns (int) {
	 *        return 0;
	 *    }
	 * }
	*/
	std::string contract_source = ProtobufConverter{}.generateContractForAbiValue(_input);
	
	// Now we compile the contract contract_source and pass it fromHex(encoding) as input.
	// Now if ``result == "1"`` we expect the call to return 0.
	// Now if ``result == "0"`` we expect the call to revert.
}
```

Further notes
===================

- Only the call to the solidity compiler would be instrumented (if at all), not the calls to the haskell binaries.

- The main challenge in this, of course, would be to write the haskell binaries /path/to/haskell/encoder/binary and /path/to/haskell/decoder/binary :-).

- Having written the above I realize: actually it doesn't even need to be standalone haskell binaries anymore - a C to haskell calls with byte strings should be enough for this :-).