aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2016-08-12 18:45:07 +0100
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2016-08-28 21:30:26 +0100
commitc3b3260ae5b5acde445fa88a6f0909f582903754 (patch)
tree7b8b6977d84045568980b8d01169281c4a79c073 /src/cryptonote_core
parentrct: log why verification fails (diff)
downloadmonero-c3b3260ae5b5acde445fa88a6f0909f582903754.tar.xz
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.
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r--src/cryptonote_core/blockchain.cpp24
-rw-r--r--src/cryptonote_core/cryptonote_basic.h3
-rw-r--r--src/cryptonote_core/cryptonote_boost_serialization.h4
-rw-r--r--src/cryptonote_core/cryptonote_format_utils.cpp21
-rw-r--r--src/cryptonote_core/cryptonote_format_utils.h1
5 files changed, 34 insertions, 19 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 44dde7759..82691eb6b 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -959,7 +959,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
money_in_use += o.amount;
partial_block_reward = false;
- if (version >= 3) {
+ if (version == 3) {
for (auto &o: b.miner_tx.vout) {
if (!is_valid_decomposed_amount(o.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
*/
//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");
size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx);
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
@@ -1137,7 +1139,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
#endif
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");
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 (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;
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: {
// check all this, either recontructed (so should really pass), or not
{
diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h
index b68040597..f54b8c2b3 100644
--- a/src/cryptonote_core/cryptonote_basic.h
+++ b/src/cryptonote_core/cryptonote_basic.h
@@ -233,6 +233,8 @@ namespace cryptonote
FIELD(rct_signatures)
switch (rct_signatures.type)
{
+ case rct::RCTTypeNull:
+ break;
case rct::RCTTypeSimple:
if (rct_signatures.mixRing.size() && rct_signatures.mixRing.size() != vin.size())
return false;
@@ -276,6 +278,7 @@ namespace cryptonote
vout.clear();
extra.clear();
signatures.clear();
+ rct_signatures.type = rct::RCTTypeNull;
}
inline
diff --git a/src/cryptonote_core/cryptonote_boost_serialization.h b/src/cryptonote_core/cryptonote_boost_serialization.h
index 09e9a7fa7..c91f78c58 100644
--- a/src/cryptonote_core/cryptonote_boost_serialization.h
+++ b/src/cryptonote_core/cryptonote_boost_serialization.h
@@ -249,6 +249,8 @@ namespace boost
inline void serialize(Archive &a, rct::rctSigBase &x, const boost::serialization::version_type ver)
{
a & x.type;
+ if (x.type == rct::RCTTypeNull)
+ return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple)
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
@@ -264,6 +266,8 @@ namespace boost
inline void serialize(Archive &a, rct::rctSig &x, const boost::serialization::version_type ver)
{
a & x.type;
+ if (x.type == rct::RCTTypeNull)
+ return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple)
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
diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp
index 6a3172d4e..cbaf11398 100644
--- a/src/cryptonote_core/cryptonote_format_utils.cpp
+++ b/src/cryptonote_core/cryptonote_format_utils.cpp
@@ -136,7 +136,10 @@ namespace cryptonote
// 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
// 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;
}
@@ -146,12 +149,16 @@ namespace cryptonote
[&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");
- if (height == 0)
+ if (height == 0 || hard_fork_version >= 4)
{
// the genesis block was not decomposed, for unknown reasons
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);
}
}
@@ -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);
- tx.version = 1;
+ if (hard_fork_version >= 4)
+ tx.version = 2;
+ else
+ tx.version = 1;
+
//lock
tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
tx.vin.push_back(in);
@@ -726,7 +737,7 @@ namespace cryptonote
// zero out all amounts to mask rct outputs, real amounts are now encrypted
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;
}
for (size_t i = 0; i < tx.vout.size(); ++i)
diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h
index 5da256921..e6a3bfba4 100644
--- a/src/cryptonote_core/cryptonote_format_utils.h
+++ b/src/cryptonote_core/cryptonote_format_utils.h
@@ -58,6 +58,7 @@ namespace cryptonote
crypto::public_key real_out_tx_key; //incoming real tx public key
size_t real_output_in_tx_index; //index in transaction outputs vector
uint64_t amount; //money
+ bool rct; //true if the output is rct
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)}))); }