carrot_impl: add consensus rule for unique output pubkeys in tx

Required by Carrot to mitigate burning bugs, described in section 4.3 of the Carrot spec:
https://github.com/jeffro256/carrot/blob/master/carrot.md#43-transaction-model

Also remove 0-out check in `check_output_types()`, which I added in and technically constitutes a retroactive network split.

Co-authored-by: j-berman <justinberman@protonmail.com>
This commit is contained in:
jeffro256
2025-04-03 13:54:05 -05:00
committed by akildemir
parent 939fd068c5
commit 4eecccee04
5 changed files with 60 additions and 27 deletions
@@ -1193,31 +1193,14 @@ namespace cryptonote
if (tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::STAKE) {
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "audit and stake transactions should have 1 output");
}
CHECK_AND_ASSERT_MES(tx.vout.size() > 0, false, "no outputs in transaction");
for (const auto &o: tx.vout)
{
if (hf_version > HF_VERSION_CARROT)
if (hf_version >= HF_VERSION_CARROT)
{
// from v18, require outputs be carrot outputs
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_carrot_v1), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_carrot_v1 in transaction id=" << get_transaction_hash(tx));
}
else if (hf_version == HF_VERSION_CARROT)
{
// during v17, require outputs be of type txout_to_tagged_key OR txout_to_carrot_v1
// to allow grace period before requiring all to be txout_to_carrot_v1
CHECK_AND_ASSERT_MES(
o.target.type() == typeid(txout_to_carrot_v1) ||
o.target.type() == typeid(txout_to_tagged_key) ||
o.target.type() == typeid(txout_to_key),
false, "wrong variant type: " << o.target.type().name()
<< ", expected txout_to_key or txout_to_tagged_key in transaction id=" << get_transaction_hash(tx));
// require all outputs in a tx be of the same type
CHECK_AND_ASSERT_MES(o.target.type() == tx.vout[0].target.type(), false, "non-matching variant types: "
<< o.target.type().name() << " and " << tx.vout[0].target.type().name() << ", "
<< "expected matching variant types in transaction id=" << get_transaction_hash(tx));
} else {
// require outputs be of type txout_to_key OR txout_to_tagged_key
// to allow grace period before requiring all to be txout_to_tagged_key