This can be especially confusing where AccessCoin() is used with logic like this:
while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
const Coin& alternate = view.AccessCoin(iter);
if (!alternate.IsSpent()) return alternate;
This can be especially confusing where AccessCoin() is used with logic like this:
while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
const Coin& alternate = view.AccessCoin(iter);
if (!alternate.IsSpent()) return alternate;
Alternatively we could remove the use of static const Coin coinEmpty and disable the empty Coin constructor.
I think I prefer the second option (remove the use of static const Coin coinEmpty). I think the only time that we can get a never-existing coin from the cache is with AccessCoin(). We could change that to return a const pointer instead of a const reference and return nullptr if the coin doesn't exist. That's what AccessCoins() did before we changed to per-txout coinsdb.
Perhaps @sipa had a reason for introducing the coinEmpty that I don't understand though?
How about rename to IsNull()?
How about rename to
IsNull()?
I think this is a more accurate name and just renaming is the smaller change, so I think this could be a good middle-ground solution. The downside of this name specifically is that this makes it harder to grep for this function. Maybe IsSpentOrEmpty() would be even a little bit better.
or maybe turn it around and call the function isSpendable or something? Because it's kind of intuitive that a coin that doesn't exist can't be spent
72 | @@ -73,6 +73,8 @@ class Coin 73 | ::Unserialize(s, Using<TxOutCompression>(out)); 74 | } 75 | 76 | + // Either this coin never existed (see e.g. coinEmpty in coins.cpp), or it
Please use doxygen function description syntax: /** ... */
Done
ACK 1404c574037da331c233317618b9b90d3329ed33
I think I prefer the second option (remove the use of
static const Coin coinEmpty). I think the only time that we can get a never-existing coin from the cache is withAccessCoin(). We could change that to return a const pointer instead of a const reference and returnnullptrif the coin doesn't exist. That's whatAccessCoins()did before we changed to per-txout coinsdb.Perhaps @sipa had a reason for introducing the
coinEmptythat I don't understand though?
Wouldn't std::optional make more sense? See also #20833 (review)
ACK 1404c574037da331c233317618b9b90d3329ed33
utACK 1404c574037da331c233317618b9b90d3329ed33
It's a much bigger change, but how about replacing IsSpent() with the bool operator, and using that everywhere? If we're using a Coin in the null state to indicate "no UTXO", then it seems natural to define truthiness on the Coin object where false indicates no UTXO and true indicates UTXO.
Even after this PR, there are still places where this is confusing, eg:
Better to update the interface to be intuitive than keep the outdated name and add comments about why it's confusing.
I think an optional API sounds nice, not a huge fan of making coin itself a bool operator since I don't think there's a straightforward "truthiness" that a coin would have in all contexts.
If you're going to consider an std::optional based interface, please benchmark it very well - this code is very performance critical.
I don't think there is a need; Coin has a well-defined "empty" state on its own (the current IsSpent; a name that's indeed outdated and confusing), so I don't think there is a need for a way to signal failure separately.
since I don't think there's a straightforward "truthiness" that a coin would have in all contexts.
What other thruthiness do you imagine besides the "exists and is isn't spent" there is now?