diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index 4639da3b3..5abe141b6 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -52,6 +52,13 @@ namespace cryptonote { + // These are guaranteed ceilings for the entire chain. Some fork rules may limit some further. + constexpr size_t COINBASE_VIN_COUNT = 1; + constexpr size_t MAX_VIN_COUNT = CRYPTONOTE_MAX_TX_SIZE / sizeof(crypto::key_image); + constexpr size_t MAX_NON_COINBASE_VOUT_COUNT = CRYPTONOTE_MAX_TX_SIZE / sizeof(crypto::public_key); + constexpr size_t MAX_COINBASE_VOUT_COUNT = /*LEVIN_DEFAULT_MAX_PACKET_SIZE=*/100000000 / sizeof(crypto::public_key); + constexpr size_t MAX_TOTAL_KEY_OFFSETS = CRYPTONOTE_MAX_TX_SIZE / sizeof(crypto::public_key); + /* outputs */ struct txout_to_script @@ -139,7 +146,7 @@ namespace cryptonote BEGIN_SERIALIZE_OBJECT() VARINT_FIELD(amount) - FIELD(key_offsets) + CONTAINER_FIELD_CAPPED(key_offsets, MAX_TOTAL_KEY_OFFSETS) FIELD(k_image) END_SERIALIZE() }; @@ -179,11 +186,102 @@ namespace cryptonote VARINT_FIELD(version) if((version == 0 || CURRENT_TRANSACTION_VERSION < version)) return false; VARINT_FIELD(unlock_time) - FIELD(vin) - FIELD(vout) + if constexpr (W) + { + // Serializing... + FIELD(vin) + FIELD(vout) + } + else + { + // De-serializing... + // vin + if (!this->deserialize_vin(ar)) + { + ar.set_fail(); + return false; + } + + // vout + const size_t MAX_VOUT_COUNT = (this->is_coinbase() || vin.empty()) ? MAX_COINBASE_VOUT_COUNT : MAX_NON_COINBASE_VOUT_COUNT; + CONTAINER_FIELD_CAPPED(vout, MAX_VOUT_COUNT) + } FIELD(extra) END_SERIALIZE() + //----------------------------------------------------------------------- + bool is_coinbase() const + { + if (vin.size() != COINBASE_VIN_COUNT) + return false; + + if (vin.at(0).type() != typeid(txin_gen)) + return false; + + return true; + } + //----------------------------------------------------------------------- + private: + // Do some validation on vin before doing allocations and reading the archive: + // 1. Can't exceed MAX_VIN_COUNT. + // 2. If coinbase, only 1 txin_gen. + // 3. If not coinbase: type txin_to_key (see check_inputs_types_supported). + // 4. If not coinbase: key offsets don't exceed max allowed for whole tx. + // Note: can't enforce non-empty because wallets may store empty vin. + template