New "Halfway RingCT" outputs for coinbase transactions

When RingCT is enabled, outputs from coinbase transactions
are created as a single output, and stored as RingCT output,
with a fake mask. Their amount is not hidden on the blockchain
itself, but they are then able to be used as fake inputs in
a RingCT ring. Since the output amounts are hidden, their
"dustiness" is not an obstacle anymore to mixing, and this
makes the coinbase transactions a lot smaller, as well as
helping the TXO set to grow more slowly.

Also add a new "Null" type of rct signature, which decreases
the size required when no signatures are to be stored, as
in a coinbase tx.
This commit is contained in:
moneromooo-monero 2016-08-12 18:45:07 +01:00
parent 6f526cdff8
commit c3b3260ae5
No known key found for this signature in database
GPG Key ID: 686F07454D6CEFC3
19 changed files with 120 additions and 36 deletions

View File

@ -46,6 +46,7 @@ void BlockchainDB::pop_block()
void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr) void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr)
{ {
bool miner_tx = false;
crypto::hash tx_hash; crypto::hash tx_hash;
if (!tx_hash_ptr) if (!tx_hash_ptr)
{ {
@ -67,6 +68,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
else if (tx_input.type() == typeid(txin_gen)) else if (tx_input.type() == typeid(txin_gen))
{ {
/* nothing to do here */ /* nothing to do here */
miner_tx = true;
} }
else else
{ {
@ -89,10 +91,23 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
// iterate tx.vout using indices instead of C++11 foreach syntax because // iterate tx.vout using indices instead of C++11 foreach syntax because
// we need the index // we need the index
for (uint64_t i = 0; i < tx.vout.size(); ++i) for (uint64_t i = 0; i < tx.vout.size(); ++i)
{
// miner v2 txes have their coinbase output in one single out to save space,
// and we store them as rct outputs with an identity mask
if (miner_tx && tx.version == 2)
{
cryptonote::tx_out vout = tx.vout[i];
rct::key commitment = rct::zeroCommit(vout.amount);
vout.amount = 0;
amount_output_indices.push_back(add_output(tx_hash, vout, i, tx.unlock_time,
&commitment));
}
else
{ {
amount_output_indices.push_back(add_output(tx_hash, tx.vout[i], i, tx.unlock_time, amount_output_indices.push_back(add_output(tx_hash, tx.vout[i], i, tx.unlock_time,
tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL)); tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL));
} }
}
add_tx_amount_output_indices(tx_id, amount_output_indices); add_tx_amount_output_indices(tx_id, amount_output_indices);
} }

View File

@ -959,7 +959,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
money_in_use += o.amount; money_in_use += o.amount;
partial_block_reward = false; partial_block_reward = false;
if (version >= 3) { if (version == 3) {
for (auto &o: b.miner_tx.vout) { for (auto &o: b.miner_tx.vout) {
if (!is_valid_decomposed_amount(o.amount)) { if (!is_valid_decomposed_amount(o.amount)) {
LOG_PRINT_L1("miner tx output " << print_money(o.amount) << " is not a valid decomposed amount"); LOG_PRINT_L1("miner tx output " << print_money(o.amount) << " is not a valid decomposed amount");
@ -1128,7 +1128,9 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
block size, so first miner transaction generated with fake amount of money, and with phase we know think we know expected block size block size, so first miner transaction generated with fake amount of money, and with phase we know think we know expected block size
*/ */
//make blocks coin-base tx looks close to real coinbase tx to get truthful blob size //make blocks coin-base tx looks close to real coinbase tx to get truthful blob size
bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, 11, m_hardfork->get_current_version()); uint8_t hf_version = m_hardfork->get_current_version();
size_t max_outs = hf_version >= 4 ? 1 : 11;
bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version);
CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance"); CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance");
size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx); size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx);
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE) #if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
@ -1137,7 +1139,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
#endif #endif
for (size_t try_count = 0; try_count != 10; ++try_count) for (size_t try_count = 0; try_count != 10; ++try_count)
{ {
r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, 11, m_hardfork->get_current_version()); r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version);
CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance"); CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance");
size_t coinbase_blob_size = get_object_blobsize(b.miner_tx); size_t coinbase_blob_size = get_object_blobsize(b.miner_tx);
@ -2354,17 +2356,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
} }
} }
// for v3, we force txes with all mixable inputs to be rct
if (m_hardfork->get_current_version() >= 4)
{
if (n_unmixable == 0 && tx.version == 1)
{
LOG_PRINT_L1("Tx " << get_transaction_hash(tx) << " is not rct and does not have unmixable inputs");
tvc.m_not_rct = true;
return false;
}
}
if (mixin < 2) if (mixin < 2)
{ {
if (n_unmixable == 0) if (n_unmixable == 0)
@ -2543,6 +2534,11 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
const rct::rctSig &rv = tx.rct_signatures; const rct::rctSig &rv = tx.rct_signatures;
switch (rv.type) switch (rv.type)
{ {
case rct::RCTTypeNull: {
// we only accept no signatures for coinbase txes
LOG_PRINT_L1("Null rct signature on non-coinbase tx");
return false;
}
case rct::RCTTypeSimple: { case rct::RCTTypeSimple: {
// check all this, either recontructed (so should really pass), or not // check all this, either recontructed (so should really pass), or not
{ {

View File

@ -233,6 +233,8 @@ namespace cryptonote
FIELD(rct_signatures) FIELD(rct_signatures)
switch (rct_signatures.type) switch (rct_signatures.type)
{ {
case rct::RCTTypeNull:
break;
case rct::RCTTypeSimple: case rct::RCTTypeSimple:
if (rct_signatures.mixRing.size() && rct_signatures.mixRing.size() != vin.size()) if (rct_signatures.mixRing.size() && rct_signatures.mixRing.size() != vin.size())
return false; return false;
@ -276,6 +278,7 @@ namespace cryptonote
vout.clear(); vout.clear();
extra.clear(); extra.clear();
signatures.clear(); signatures.clear();
rct_signatures.type = rct::RCTTypeNull;
} }
inline inline

View File

@ -249,6 +249,8 @@ namespace boost
inline void serialize(Archive &a, rct::rctSigBase &x, const boost::serialization::version_type ver) inline void serialize(Archive &a, rct::rctSigBase &x, const boost::serialization::version_type ver)
{ {
a & x.type; a & x.type;
if (x.type == rct::RCTTypeNull)
return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple) if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type"); throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data // a & x.message; message is not serialized, as it can be reconstructed from the tx data
@ -264,6 +266,8 @@ namespace boost
inline void serialize(Archive &a, rct::rctSig &x, const boost::serialization::version_type ver) inline void serialize(Archive &a, rct::rctSig &x, const boost::serialization::version_type ver)
{ {
a & x.type; a & x.type;
if (x.type == rct::RCTTypeNull)
return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple) if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type"); throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data // a & x.message; message is not serialized, as it can be reconstructed from the tx data

View File

@ -136,7 +136,10 @@ namespace cryptonote
// from hard fork 2, we cut out the low significant digits. This makes the tx smaller, and // from hard fork 2, we cut out the low significant digits. This makes the tx smaller, and
// keeps the paid amount almost the same. The unpaid remainder gets pushed back to the // keeps the paid amount almost the same. The unpaid remainder gets pushed back to the
// emission schedule // emission schedule
if (hard_fork_version >= 2) { // from hard fork 4, we use a single "dusty" output. This makes the tx even smaller,
// and avoids the quantization. These outputs will be added as rct outputs with identity
// masks, to they can be used as rct inputs.
if (hard_fork_version >= 2 && hard_fork_version < 4) {
block_reward = block_reward - block_reward % ::config::BASE_REWARD_CLAMP_THRESHOLD; block_reward = block_reward - block_reward % ::config::BASE_REWARD_CLAMP_THRESHOLD;
} }
@ -146,12 +149,16 @@ namespace cryptonote
[&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); });
CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero"); CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero");
if (height == 0) if (height == 0 || hard_fork_version >= 4)
{ {
// the genesis block was not decomposed, for unknown reasons // the genesis block was not decomposed, for unknown reasons
while (max_outs < out_amounts.size()) while (max_outs < out_amounts.size())
{ {
out_amounts[out_amounts.size() - 2] += out_amounts.back(); //out_amounts[out_amounts.size() - 2] += out_amounts.back();
//out_amounts.resize(out_amounts.size() - 1);
out_amounts[1] += out_amounts[0];
for (size_t n = 1; n < out_amounts.size(); ++n)
out_amounts[n - 1] = out_amounts[n];
out_amounts.resize(out_amounts.size() - 1); out_amounts.resize(out_amounts.size() - 1);
} }
} }
@ -182,7 +189,11 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(summary_amounts == block_reward, false, "Failed to construct miner tx, summary_amounts = " << summary_amounts << " not equal block_reward = " << block_reward); CHECK_AND_ASSERT_MES(summary_amounts == block_reward, false, "Failed to construct miner tx, summary_amounts = " << summary_amounts << " not equal block_reward = " << block_reward);
if (hard_fork_version >= 4)
tx.version = 2;
else
tx.version = 1; tx.version = 1;
//lock //lock
tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
tx.vin.push_back(in); tx.vin.push_back(in);
@ -726,7 +737,7 @@ namespace cryptonote
// zero out all amounts to mask rct outputs, real amounts are now encrypted // zero out all amounts to mask rct outputs, real amounts are now encrypted
for (size_t i = 0; i < tx.vin.size(); ++i) for (size_t i = 0; i < tx.vin.size(); ++i)
{ {
if (!(sources[i].mask == rct::identity())) if (sources[i].rct)
boost::get<txin_to_key>(tx.vin[i]).amount = 0; boost::get<txin_to_key>(tx.vin[i]).amount = 0;
} }
for (size_t i = 0; i < tx.vout.size(); ++i) for (size_t i = 0; i < tx.vout.size(); ++i)

View File

@ -58,6 +58,7 @@ namespace cryptonote
crypto::public_key real_out_tx_key; //incoming real tx public key crypto::public_key real_out_tx_key; //incoming real tx public key
size_t real_output_in_tx_index; //index in transaction outputs vector size_t real_output_in_tx_index; //index in transaction outputs vector
uint64_t amount; //money uint64_t amount; //money
bool rct; //true if the output is rct
rct::key mask; //ringct amount mask rct::key mask; //ringct amount mask
void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount) { outputs.push_back(std::make_pair(idx, rct::ctkey({rct::pk2rct(k), rct::zeroCommit(amount)}))); } void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount) { outputs.push_back(std::make_pair(idx, rct::ctkey({rct::pk2rct(k), rct::zeroCommit(amount)}))); }

View File

@ -174,8 +174,9 @@ namespace rct {
// outPk contains public keypairs which are destinations (P, C), // outPk contains public keypairs which are destinations (P, C),
// P = address, C = commitment to amount // P = address, C = commitment to amount
enum { enum {
RCTTypeFull = 0, RCTTypeNull = 0,
RCTTypeSimple = 1, RCTTypeFull = 1,
RCTTypeSimple = 2,
}; };
struct rctSigBase { struct rctSigBase {
uint8_t type; uint8_t type;
@ -189,6 +190,8 @@ namespace rct {
BEGIN_SERIALIZE() BEGIN_SERIALIZE()
FIELD(type) FIELD(type)
if (type == RCTTypeNull)
return true;
// FIELD(message) - not serialized, it can be reconstructed // FIELD(message) - not serialized, it can be reconstructed
// FIELD(mixRing) - not serialized, it can be reconstructed // FIELD(mixRing) - not serialized, it can be reconstructed
if (type == RCTTypeSimple) if (type == RCTTypeSimple)
@ -224,6 +227,8 @@ namespace rct {
BEGIN_SERIALIZE_OBJECT() BEGIN_SERIALIZE_OBJECT()
FIELDS(*static_cast<rctSigBase *>(this)) FIELDS(*static_cast<rctSigBase *>(this))
if (type == RCTTypeNull)
return true;
FIELDS(p); FIELDS(p);
END_SERIALIZE() END_SERIALIZE()
}; };

View File

@ -489,10 +489,17 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
{ {
td.m_mask = mask[o]; td.m_mask = mask[o];
td.m_amount = amount[o]; td.m_amount = amount[o];
td.m_rct = true;
}
else if (miner_tx && tx.version == 2)
{
td.m_mask = rct::identity();
td.m_rct = true;
} }
else else
{ {
td.m_mask = rct::identity(); td.m_mask = rct::identity();
td.m_rct = false;
} }
set_unspent(td); set_unspent(td);
m_key_images[td.m_key_image] = m_transfers.size()-1; m_key_images[td.m_key_image] = m_transfers.size()-1;
@ -529,10 +536,17 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
{ {
td.m_mask = mask[o]; td.m_mask = mask[o];
td.m_amount = amount[o]; td.m_amount = amount[o];
td.m_rct = true;
}
else if (miner_tx && tx.version == 2)
{
td.m_mask = rct::identity();
td.m_rct = true;
} }
else else
{ {
td.m_mask = rct::identity(); td.m_mask = rct::identity();
td.m_rct = false;
} }
THROW_WALLET_EXCEPTION_IF(td.m_key_image != ki[o], error::wallet_internal_error, "Inconsistent key images"); THROW_WALLET_EXCEPTION_IF(td.m_key_image != ki[o], error::wallet_internal_error, "Inconsistent key images");
THROW_WALLET_EXCEPTION_IF(td.m_spent, error::wallet_internal_error, "Inconsistent spent status"); THROW_WALLET_EXCEPTION_IF(td.m_spent, error::wallet_internal_error, "Inconsistent spent status");
@ -2847,6 +2861,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
cryptonote::tx_source_entry& src = sources.back(); cryptonote::tx_source_entry& src = sources.back();
transfer_details& td = *it; transfer_details& td = *it;
src.amount = td.amount(); src.amount = td.amount();
src.rct = td.is_rct();
//paste keys (fake and real) //paste keys (fake and real)
for (size_t n = 0; n < fake_outputs_count + 1; ++n) for (size_t n = 0; n < fake_outputs_count + 1; ++n)
@ -3037,6 +3052,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
cryptonote::tx_source_entry& src = sources.back(); cryptonote::tx_source_entry& src = sources.back();
transfer_details& td = *it; transfer_details& td = *it;
src.amount = td.amount(); src.amount = td.amount();
src.rct = td.is_rct();
//paste mixin transaction //paste mixin transaction
if(it->is_rct()) if(it->is_rct())
{ {
@ -3732,6 +3748,7 @@ void wallet2::transfer_from(const std::vector<size_t> &outs, size_t num_outputs,
cryptonote::tx_source_entry& src = sources.back(); cryptonote::tx_source_entry& src = sources.back();
transfer_details& td = *it; transfer_details& td = *it;
src.amount = td.amount(); src.amount = td.amount();
src.rct = td.is_rct();
//paste real transaction to the random index //paste real transaction to the random index
auto it_to_insert = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a) auto it_to_insert = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a)

View File

@ -108,8 +108,9 @@ namespace tools
crypto::key_image m_key_image; //TODO: key_image stored twice :( crypto::key_image m_key_image; //TODO: key_image stored twice :(
rct::key m_mask; rct::key m_mask;
uint64_t m_amount; uint64_t m_amount;
bool m_rct;
bool is_rct() const { return m_tx.vout[m_internal_output_index].amount == 0; } bool is_rct() const { return m_rct; }
uint64_t amount() const { return m_amount; } uint64_t amount() const { return m_amount; }
}; };
@ -502,7 +503,7 @@ namespace tools
}; };
} }
BOOST_CLASS_VERSION(tools::wallet2, 14) BOOST_CLASS_VERSION(tools::wallet2, 14)
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 3) BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 4)
BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1) BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1)
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 5) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 5)
BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 2) BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 2)
@ -527,6 +528,10 @@ namespace boost
{ {
x.m_spent_height = 0; x.m_spent_height = 0;
} }
if (ver < 4)
{
x.m_rct = x.m_tx.vout[x.m_internal_output_index].amount == 0;
}
} }
template <class Archive> template <class Archive>
@ -563,8 +568,17 @@ namespace boost
} }
a & x.m_spent_height; a & x.m_spent_height;
if (ver < 3) if (ver < 3)
{
initialize_transfer_details(a, x, ver);
return; return;
}
a & x.m_txid; a & x.m_txid;
if (ver < 4)
{
initialize_transfer_details(a, x, ver);
return;
}
a & x.m_rct;
} }
template <class Archive> template <class Archive>
@ -770,6 +784,7 @@ namespace tools
cryptonote::tx_source_entry& src = sources.back(); cryptonote::tx_source_entry& src = sources.back();
transfer_details& td = *it; transfer_details& td = *it;
src.amount = td.amount(); src.amount = td.amount();
src.rct = false;
//paste mixin transaction //paste mixin transaction
if(daemon_resp.outs.size()) if(daemon_resp.outs.size())
{ {

View File

@ -337,6 +337,7 @@ bool gen_block_miner_tx_has_2_in::generate(std::vector<test_event_entry>& events
se.amount = blk_0.miner_tx.vout[0].amount; se.amount = blk_0.miner_tx.vout[0].amount;
se.push_output(0, boost::get<txout_to_key>(blk_0.miner_tx.vout[0].target).key, se.amount); se.push_output(0, boost::get<txout_to_key>(blk_0.miner_tx.vout[0].target).key, se.amount);
se.real_output = 0; se.real_output = 0;
se.rct = false;
se.real_out_tx_key = get_tx_pub_key_from_extra(blk_0.miner_tx); se.real_out_tx_key = get_tx_pub_key_from_extra(blk_0.miner_tx);
se.real_output_in_tx_index = 0; se.real_output_in_tx_index = 0;
std::vector<tx_source_entry> sources; std::vector<tx_source_entry> sources;
@ -379,6 +380,7 @@ bool gen_block_miner_tx_with_txin_to_key::generate(std::vector<test_event_entry>
se.amount = blk_1.miner_tx.vout[0].amount; se.amount = blk_1.miner_tx.vout[0].amount;
se.push_output(0, boost::get<txout_to_key>(blk_1.miner_tx.vout[0].target).key, se.amount); se.push_output(0, boost::get<txout_to_key>(blk_1.miner_tx.vout[0].target).key, se.amount);
se.real_output = 0; se.real_output = 0;
se.rct = false;
se.real_out_tx_key = get_tx_pub_key_from_extra(blk_1.miner_tx); se.real_out_tx_key = get_tx_pub_key_from_extra(blk_1.miner_tx);
se.real_output_in_tx_index = 0; se.real_output_in_tx_index = 0;
std::vector<tx_source_entry> sources; std::vector<tx_source_entry> sources;

View File

@ -458,6 +458,7 @@ bool fill_tx_sources(std::vector<tx_source_entry>& sources, const std::vector<te
continue; continue;
ts.real_output = realOutput; ts.real_output = realOutput;
ts.rct = false;
sources.push_back(ts); sources.push_back(ts);

View File

@ -130,6 +130,7 @@ bool gen_double_spend_in_tx<txs_keeped_by_block>::generate(std::vector<test_even
se.amount = tx_0.vout[0].amount; se.amount = tx_0.vout[0].amount;
se.push_output(0, boost::get<cryptonote::txout_to_key>(tx_0.vout[0].target).key, se.amount); se.push_output(0, boost::get<cryptonote::txout_to_key>(tx_0.vout[0].target).key, se.amount);
se.real_output = 0; se.real_output = 0;
se.rct = false;
se.real_out_tx_key = get_tx_pub_key_from_extra(tx_0); se.real_out_tx_key = get_tx_pub_key_from_extra(tx_0);
se.real_output_in_tx_index = 0; se.real_output_in_tx_index = 0;
sources.push_back(se); sources.push_back(se);

View File

@ -63,6 +63,7 @@ namespace
se.amount = tx.vout[out_idx].amount; se.amount = tx.vout[out_idx].amount;
se.push_output(0, boost::get<cryptonote::txout_to_key>(tx.vout[out_idx].target).key, se.amount); se.push_output(0, boost::get<cryptonote::txout_to_key>(tx.vout[out_idx].target).key, se.amount);
se.real_output = 0; se.real_output = 0;
se.rct = false;
se.real_out_tx_key = get_tx_pub_key_from_extra(tx); se.real_out_tx_key = get_tx_pub_key_from_extra(tx);
se.real_output_in_tx_index = out_idx; se.real_output_in_tx_index = out_idx;

View File

@ -57,8 +57,8 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
miner_accounts[n].generate(); miner_accounts[n].generate();
CHECK_AND_ASSERT_MES(generator.construct_block_manually(blocks[n], *prev_block, miner_accounts[n], CHECK_AND_ASSERT_MES(generator.construct_block_manually(blocks[n], *prev_block, miner_accounts[n],
test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version,
4, 4, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long 2, 2, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long
crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 0, 4), crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 0, 2),
false, "Failed to generate block"); false, "Failed to generate block");
events.push_back(blocks[n]); events.push_back(blocks[n]);
prev_block = blocks + n; prev_block = blocks + n;
@ -74,8 +74,8 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
cryptonote::block blk; cryptonote::block blk;
CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account, CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account,
test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version,
4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long 2, 2, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long
crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 0, 4), crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 0, 2),
false, "Failed to generate block"); false, "Failed to generate block");
events.push_back(blk); events.push_back(blk);
blk_last = blk; blk_last = blk;
@ -104,6 +104,7 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
src.real_output = n; src.real_output = n;
src.real_output_in_tx_index = index_in_tx; src.real_output_in_tx_index = index_in_tx;
src.mask = rct::identity(); src.mask = rct::identity();
src.rct = false;
//fill outputs entry //fill outputs entry
tx_destination_entry td; tx_destination_entry td;
@ -135,9 +136,9 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
} }
CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account, CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account,
test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_tx_hashes | test_generator::bf_hf_version, test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_tx_hashes | test_generator::bf_hf_version | test_generator::bf_max_outs,
4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long 4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long
crypto::hash(), 0, transaction(), starting_rct_tx_hashes, 0, 0, 4), crypto::hash(), 0, transaction(), starting_rct_tx_hashes, 0, 6, 4),
false, "Failed to generate block"); false, "Failed to generate block");
events.push_back(blk_txes[n]); events.push_back(blk_txes[n]);
blk_last = blk_txes[n]; blk_last = blk_txes[n];
@ -149,9 +150,9 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
{ {
cryptonote::block blk; cryptonote::block blk;
CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account, CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account,
test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version | test_generator::bf_max_outs,
4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long 4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long
crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 0, 4), crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 6, 4),
false, "Failed to generate block"); false, "Failed to generate block");
events.push_back(blk); events.push_back(blk);
blk_last = blk; blk_last = blk;
@ -161,7 +162,9 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
// create a tx from the requested ouputs // create a tx from the requested ouputs
std::vector<tx_source_entry> sources; std::vector<tx_source_entry> sources;
size_t rct_idx = 0, pre_rct_idx = 0; size_t global_rct_idx = 6; // skip first coinbase (6 outputs)
size_t rct_idx = 0;
size_t pre_rct_idx = 0;
for (size_t out_idx_idx = 0; out_idx[out_idx_idx] >= 0; ++out_idx_idx) { for (size_t out_idx_idx = 0; out_idx[out_idx_idx] >= 0; ++out_idx_idx) {
sources.resize(sources.size()+1); sources.resize(sources.size()+1);
tx_source_entry& src = sources.back(); tx_source_entry& src = sources.back();
@ -173,12 +176,16 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
src.real_out_tx_key = get_tx_pub_key_from_extra(rct_txes[rct_idx/4]); src.real_out_tx_key = get_tx_pub_key_from_extra(rct_txes[rct_idx/4]);
src.real_output_in_tx_index = rct_idx&3; src.real_output_in_tx_index = rct_idx&3;
src.mask = rct_tx_masks[rct_idx]; src.mask = rct_tx_masks[rct_idx];
src.rct = true;
for (int m = 0; m <= mixin; ++m) { for (int m = 0; m <= mixin; ++m) {
rct::ctkey ctkey; rct::ctkey ctkey;
ctkey.dest = rct::pk2rct(boost::get<txout_to_key>(rct_txes[rct_idx/4].vout[rct_idx&3].target).key); ctkey.dest = rct::pk2rct(boost::get<txout_to_key>(rct_txes[rct_idx/4].vout[rct_idx&3].target).key);
ctkey.mask = rct_txes[rct_idx/4].rct_signatures.outPk[rct_idx&3].mask; ctkey.mask = rct_txes[rct_idx/4].rct_signatures.outPk[rct_idx&3].mask;
src.outputs.push_back(std::make_pair(rct_idx, ctkey)); src.outputs.push_back(std::make_pair(global_rct_idx, ctkey));
++rct_idx; ++rct_idx;
++global_rct_idx;
if (global_rct_idx % 10 == 0)
global_rct_idx += 6; // skip the coinbase
} }
} }
else else
@ -188,6 +195,7 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[pre_rct_idx].miner_tx); src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[pre_rct_idx].miner_tx);
src.real_output_in_tx_index = 4; src.real_output_in_tx_index = 4;
src.mask = rct::identity(); src.mask = rct::identity();
src.rct = false;
for (int m = 0; m <= mixin; ++m) { for (int m = 0; m <= mixin; ++m) {
src.push_output(m, boost::get<txout_to_key>(blocks[pre_rct_idx].miner_tx.vout[4].target).key, src.amount); src.push_output(m, boost::get<txout_to_key>(blocks[pre_rct_idx].miner_tx.vout[4].target).key, src.amount);
++pre_rct_idx; ++pre_rct_idx;

View File

@ -81,7 +81,7 @@ private:
template<> template<>
struct get_test_options<gen_rct_tx_validation_base> { struct get_test_options<gen_rct_tx_validation_base> {
const std::pair<uint8_t, uint64_t> hard_forks[2] = {std::make_pair(1, 0), std::make_pair(4, 1)}; const std::pair<uint8_t, uint64_t> hard_forks[3] = {std::make_pair(1, 0), std::make_pair(2, 1), std::make_pair(4, 65)};
const cryptonote::test_options test_options = { const cryptonote::test_options test_options = {
hard_forks hard_forks
}; };

View File

@ -97,6 +97,7 @@ bool test_transaction_generation_and_ring_signature()
src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(tx_mine_2); src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(tx_mine_2);
src.real_output = 1; src.real_output = 1;
src.rct = false;
src.real_output_in_tx_index = 0; src.real_output_in_tx_index = 0;
} }
//fill outputs entry //fill outputs entry

View File

@ -96,6 +96,7 @@ bool gen_v2_tx_validation_base::generate_with(std::vector<test_event_entry>& eve
} }
src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[0].miner_tx); src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[0].miner_tx);
src.real_output = 0; src.real_output = 0;
src.rct = false;
src.real_output_in_tx_index = out_idx[out_idx_idx]; src.real_output_in_tx_index = out_idx[out_idx_idx];
} }

View File

@ -113,6 +113,7 @@ bool make_tx(blockchain_storage& bch)
src.real_out_tx_key = td.m_tx.tx_pub_key; src.real_out_tx_key = td.m_tx.tx_pub_key;
src.real_output = interted_it - src.outputs.begin(); src.real_output = interted_it - src.outputs.begin();
src.real_output_in_tx_index = td.m_internal_output_index; src.real_output_in_tx_index = td.m_internal_output_index;
src.rct = false;
++i; ++i;
} }

View File

@ -72,6 +72,7 @@ public:
source_entry.real_output_in_tx_index = 0; source_entry.real_output_in_tx_index = 0;
source_entry.outputs.swap(output_entries); source_entry.outputs.swap(output_entries);
source_entry.real_output = real_source_idx; source_entry.real_output = real_source_idx;
source_entry.rct = false;
m_sources.push_back(source_entry); m_sources.push_back(source_entry);