Background
Currently most mining software uses the graffiti field as a nonce when mining Iron Fish blocks. The block header is serialized as follows before being passed to the blake3 hashing algorithm.
writeBigU64BE(header.randomness) // 8
writeU32(header.sequence) // 4
writeHash(header.previousBlockHash) // 32
writeHash(header.noteCommitment) // 32
writeHash(header.transactionCommitment) // 32
writeBigU256BE(header.target.asBigInt()) // 32
writeU64(header.timestamp.getTime()) // 8
writeBytes(header.graffiti) // 32
We can see the randomness
field (the intended nonce) is at the beginning of the serialized bytes while graffiti
is at the end. Because blake3 hashes data in chunks it is prone to ‘mid-state’ optimization. If the beginning portions of the data are kept constant while the end of the data changes, the intermediate result of hashing the beginning can be re-used for multiple hashes. Because randomness
is in the initial bytes and graffiti
is in the final bytes it is optimal to keep the randomness
constant while changing the graffiti
over and over again to mine. This leads the graffiti
fields being unrecognizable in their ASCI form and essentially random bytes which was not the original intent of the field. Sha-3 in Bitcoin is succeptible to this as well as described further in this post.
Proposal
With the switch to the FishHash algorithm for mining the order in which these two fields appear can also easily be changed. Moving the graffiti
to the front and randomness
to the end will allow using randomness
as the nonce to be more optimal than graffiti
and the graffiti
can be used for its intended purpose. The new serialization before passing to the FishHash function would be
writeBytes(header.graffiti) // 32
writeU32(header.sequence) // 4
writeHash(header.previousBlockHash) // 32
writeHash(header.noteCommitment) // 32
writeHash(header.transactionCommitment) // 32
writeBigU256BE(header.target.asBigInt()) // 32
writeU64(header.timestamp.getTime()) // 8
writeBigU64BE(header.randomness) // 8