In Bitcoin Core the notion of a "null" amount (and therefore a "null"
txout) is one which cannot be serialized or deserialized. In Core this
is implemented using a value of -1.
In Elements we use the CT notion of "nullness" which is that the flag on
the confidential value is 0. See d53479c9ff
which implemented this. This is reasonable, but because we don't have
checks on deserialization, we can deserialize objects that cannot be
reserialized.
In particular, in coins.h, we deserialize a coin by deserializing its
txout. When reserializing we assert that !out.IsNull(). This assertion
is hit by the `coins_deserialize` fuzztest.
There are a few potential fixes here:
* Remove the assertion from coins.h, which is there to catch logic bugs
in Core, on the assumption that if they have no bugs then we don't
either. This seems like a bad idea.
* Change "nullness" for amounts to be an encoding of -1, like in Core.
This seems dangerous because we call `GetAmount` all over the place,
and if this could return the -1 amount, this will likely blow
something up. Probably this is safe for the same reason it is in Core
-- that is, we never create null txouts except as sentinel values. But
do you wanna bet that this is true now? That it'll always be true?
* Same as above, but assert that the amount is not null. This is safer
than just blindly hoping that no overflows will occur but still not
obviously safe.
* Refuse to deserialize null CT objects. This is impossible because we
use null nonce values in txouts.
* Refuse to deserialize null CT values. Similarly, this is impossible
because we use null values in null asset issuances, which are legal.
* Refused to deserialize CTxOuts with null values or assets.
We are going with the latter solution, because it is narrowly scoped,
does not increase the "crash surface" (we throw an exception, and we
already throw exceptions for other kinds of invalid serializations),
and is very unlikely to cause bugs (null values are invalid on the
network anyway; this is the first check in VerifyAmounts) (so are null
assets for that matter, which we maybe also should refuse to
deserialize).