Debug a contract
The debug
and host_debug
features are meant for debugging while writing the contracts. They allow developers to print logs to stdout from the contract, making inspecting the state a bit easier.
WASM tools
Useful WASM tools can be found here.
Of those, WebAssembly text format (WAT) is a “friendly” representation of WASM which can be used with wasm-tools print foo.wasm
.
Troubleshooting
Error 500: PolynomialDegreeTooLarge
When trying to call a method on a contract, the PolynomialDegreeTooLarge
error indicates an issue with proving in Plonk proving system. It likely means that an attempt was made to prove something incorrect, such as proving ownership of something not actually owned or violating Dusk conservation rules.
When trying to avoid incorporating the source code of rusk-abi in the workspace by using it as a regular crate, the compiler complains that ContractId
in rusk-abi
library is ambiguous and to either define it as host::ContractId
or abi::ContractId
.
The suggestion is using the rusk codebase as a submodule and building against it.
Unexpected information returned
If code fails when passing in a vector but correctly executes when passing an array, you may see that unexpected information is returned, similarly to:
The issue arises because the argument buffer is written to before it is read from. The rusk_abi::debug
function writes a string (“Entering constructor”) to the argument buffer. Then, the rusk_abi::wrap_call
function reads an argument from the buffer, passes it to the closure, and writes the closure’s return value back to the same buffer. This sequence of operations is incorrect and leads to the corrupted output seen in the returned struct.
The reason why this may happen with an array but not with a vector, is that when STATE.init
takes an array, the serialization process simply serializes the bytes of the array.
When it takes a Vec
, the length of the vector must also be serialized. This difference in handling results in the observed behavior where using an array does not cause a panic, but using a Vec
does.
Suggested Fix: Ensure that the buffer is read before any writing operations are performed. This will prevent the corruption of data and ensure that the deserialized information is accurate. Use the unsafe keyword judiciously to manage these operations, ensuring that the sequence of reading and writing to the buffer is correct.
Transaction error: Unknown
You may encounter an issue in which the proving operation is performed correctly and the transaction is sent to the node, but then it fails with Transaction error: Unknown
and showing on rusk logs:
rusk::chain::rusk: Tx ... executed with 2900000000 gas and err Some("Unknown")
.
The transaction has clearly been processed successfully as it can be seen by the gas being paid, but something went wrong while calling the contract. The recommendation would be to use the debug and host_debug features and litter the contract code with piecrust_uplink::debug!
calls to see exactly where the contract crashes. If this doesn’t yield results, then it is recommended to print out the result of inter-contract calls in piecrust directly, just to see what error is actually being returned. The error is likely the result of an error on the host, which has to pass through the contract barrier before being returned as a response.
TokenAddress is just a [u8; 22]
If you’re facing the following issue:
The rkyv
traits for the TokenAddress
type need to be implemented, so that they are passable through the VM boundary automatically. The easiest way to do this is to derive them. Here’s an example from implementing the traits for a Note
: