aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r--src/cryptonote_core/blockchain_storage.cpp63
-rw-r--r--src/cryptonote_core/checkpoints_create.h3
-rw-r--r--src/cryptonote_core/cryptonote_format_utils.cpp139
-rw-r--r--src/cryptonote_core/cryptonote_format_utils.h21
-rw-r--r--src/cryptonote_core/difficulty.cpp2
-rw-r--r--src/cryptonote_core/tx_extra.h87
-rw-r--r--src/cryptonote_core/tx_pool.h3
7 files changed, 245 insertions, 73 deletions
diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp
index c1b9619f2..0e20b454b 100644
--- a/src/cryptonote_core/blockchain_storage.cpp
+++ b/src/cryptonote_core/blockchain_storage.cpp
@@ -582,6 +582,42 @@ bool blockchain_storage::create_block_template(block& b, const account_public_ad
if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee)) {
return false;
}
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ size_t real_txs_size = 0;
+ uint64_t real_fee = 0;
+ CRITICAL_REGION_BEGIN(m_tx_pool.m_transactions_lock);
+ BOOST_FOREACH(crypto::hash &cur_hash, b.tx_hashes) {
+ auto cur_res = m_tx_pool.m_transactions.find(cur_hash);
+ if (cur_res == m_tx_pool.m_transactions.end()) {
+ LOG_ERROR("Creating block template: error: transaction not found");
+ continue;
+ }
+ tx_memory_pool::tx_details &cur_tx = cur_res->second;
+ real_txs_size += cur_tx.blob_size;
+ real_fee += cur_tx.fee;
+ if (cur_tx.blob_size != get_object_blobsize(cur_tx.tx)) {
+ LOG_ERROR("Creating block template: error: invalid transaction size");
+ }
+ uint64_t inputs_amount;
+ if (!get_inputs_money_amount(cur_tx.tx, inputs_amount)) {
+ LOG_ERROR("Creating block template: error: cannot get inputs amount");
+ } else if (cur_tx.fee != inputs_amount - get_outs_money_amount(cur_tx.tx)) {
+ LOG_ERROR("Creating block template: error: invalid fee");
+ }
+ }
+ if (txs_size != real_txs_size) {
+ LOG_ERROR("Creating block template: error: wrongly calculated transaction size");
+ }
+ if (fee != real_fee) {
+ LOG_ERROR("Creating block template: error: wrongly calculated fee");
+ }
+ CRITICAL_REGION_END();
+ LOG_PRINT_L1("Creating block template: height " << height <<
+ ", median size " << median_size <<
+ ", already generated coins " << already_generated_coins <<
+ ", transaction size " << txs_size <<
+ ", fee " << fee);
+#endif
/*
two-phase miner transaction generation: we don't know exact block size until we prepare block, but we don't know reward until we know
@@ -590,27 +626,32 @@ bool blockchain_storage::create_block_template(block& b, const account_public_ad
//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);
CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance");
-#ifdef _DEBUG
- std::list<size_t> try_val;
- try_val.push_back(get_object_blobsize(b.miner_tx));
-#endif
-
size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx);
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ LOG_PRINT_L1("Creating block template: miner tx size " << get_object_blobsize(b.miner_tx) <<
+ ", cumulative size " << cumulative_size);
+#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);
-#ifdef _DEBUG
- try_val.push_back(get_object_blobsize(b.miner_tx));
-#endif
CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance");
size_t coinbase_blob_size = get_object_blobsize(b.miner_tx);
if (coinbase_blob_size > cumulative_size - txs_size) {
cumulative_size = txs_size + coinbase_blob_size;
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size <<
+ ", cumulative size " << cumulative_size << " is greater then before");
+#endif
continue;
}
if (coinbase_blob_size < cumulative_size - txs_size) {
size_t delta = cumulative_size - txs_size - coinbase_blob_size;
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size <<
+ ", cumulative size " << txs_size + coinbase_blob_size <<
+ " is less then before, adding " << delta << " zero bytes");
+#endif
b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0);
//here could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len.
if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx)) {
@@ -626,6 +667,10 @@ bool blockchain_storage::create_block_template(block& b, const account_public_ad
}
}
CHECK_AND_ASSERT_MES(cumulative_size == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx));
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size <<
+ ", cumulative size " << cumulative_size << " is now good");
+#endif
return true;
}
LOG_ERROR("Failed to create_block_template with " << 10 << " tries");
@@ -1603,4 +1648,4 @@ bool blockchain_storage::add_new_block(const block& bl_, block_verification_cont
}
return handle_block_to_main_chain(bl, id, bvc);
-}
+} \ No newline at end of file
diff --git a/src/cryptonote_core/checkpoints_create.h b/src/cryptonote_core/checkpoints_create.h
index 8dff85d84..304096ef2 100644
--- a/src/cryptonote_core/checkpoints_create.h
+++ b/src/cryptonote_core/checkpoints_create.h
@@ -11,7 +11,8 @@
namespace cryptonote {
inline bool create_checkpoints(cryptonote::checkpoints& checkpoints)
- {
+ {
+ ADD_CHECKPOINT(22231, "d69526de16c58b07058bd80a9a8c99389814d17b1935623223b0d6e4a311b80f");
return true;
}
}
diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp
index a231f9c75..aa2c82b2a 100644
--- a/src/cryptonote_core/cryptonote_format_utils.cpp
+++ b/src/cryptonote_core/cryptonote_format_utils.cpp
@@ -61,8 +61,8 @@ namespace cryptonote
keypair txkey = keypair::generate();
add_tx_pub_key_to_extra(tx, txkey.pub);
- if(extra_nonce.size())
- if(!add_tx_extra_nonce(tx, extra_nonce))
+ if(!extra_nonce.empty())
+ if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
return false;
txin_gen in;
@@ -74,6 +74,10 @@ namespace cryptonote
LOG_PRINT_L0("Block is too big");
return false;
}
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ LOG_PRINT_L1("Creating block template: reward " << block_reward <<
+ ", fee " << fee)
+#endif
block_reward += fee;
std::vector<size_t> out_amounts;
@@ -204,53 +208,52 @@ namespace cryptonote
return r;
}
//---------------------------------------------------------------
- crypto::public_key get_tx_pub_key_from_extra(const transaction& tx)
+ bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields)
{
- crypto::public_key pk = null_pkey;
- parse_and_validate_tx_extra(tx, pk);
- return pk;
- }
- //---------------------------------------------------------------
- bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key)
- {
- tx_pub_key = null_pkey;
- bool padding_started = false; //let the padding goes only at the end
- bool tx_extra_tag_pubkey_found = false;
- bool tx_extra_extra_nonce_found = false;
- for(size_t i = 0; i != tx.extra.size();)
+ tx_extra_fields.clear();
+
+ if(tx_extra.empty())
+ return true;
+
+ std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size());
+ std::istringstream iss(extra_str);
+ binary_archive<false> ar(iss);
+
+ bool eof = false;
+ while (!eof)
{
- if(padding_started)
- {
- CHECK_AND_ASSERT_MES(!tx.extra[i], false, "Failed to parse transaction extra (not 0 after padding) in tx " << get_transaction_hash(tx));
- }
- else if(tx.extra[i] == TX_EXTRA_TAG_PUBKEY)
- {
- CHECK_AND_ASSERT_MES(sizeof(crypto::public_key) <= tx.extra.size()-1-i, false, "Failed to parse transaction extra (TX_EXTRA_TAG_PUBKEY have not enough bytes) in tx " << get_transaction_hash(tx));
- CHECK_AND_ASSERT_MES(!tx_extra_tag_pubkey_found, false, "Failed to parse transaction extra (duplicate TX_EXTRA_TAG_PUBKEY entry) in tx " << get_transaction_hash(tx));
- tx_pub_key = *reinterpret_cast<const crypto::public_key*>(&tx.extra[i+1]);
- i += 1 + sizeof(crypto::public_key);
- tx_extra_tag_pubkey_found = true;
- continue;
- }else if(tx.extra[i] == TX_EXTRA_NONCE)
- {
- //CHECK_AND_ASSERT_MES(is_coinbase(tx), false, "Failed to parse transaction extra (TX_EXTRA_NONCE can be only in coinbase) in tx " << get_transaction_hash(tx));
- CHECK_AND_ASSERT_MES(!tx_extra_extra_nonce_found, false, "Failed to parse transaction extra (duplicate TX_EXTRA_NONCE entry) in tx " << get_transaction_hash(tx));
- CHECK_AND_ASSERT_MES(tx.extra.size()-1-i >= 1, false, "Failed to parse transaction extra (TX_EXTRA_NONCE have not enough bytes) in tx " << get_transaction_hash(tx));
- ++i;
- CHECK_AND_ASSERT_MES(tx.extra.size()-1-i >= tx.extra[i], false, "Failed to parse transaction extra (TX_EXTRA_NONCE have wrong bytes counter) in tx " << get_transaction_hash(tx));
- tx_extra_extra_nonce_found = true;
- i += tx.extra[i];//actually don't need to extract it now, just skip
- }
- else if(!tx.extra[i])
- {
- padding_started = true;
- continue;
- }
- ++i;
+ tx_extra_field field;
+ bool r = ::do_serialize(ar, field);
+ CHECK_AND_NO_ASSERT_MES(r, false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
+ tx_extra_fields.push_back(field);
+
+ std::ios_base::iostate state = iss.rdstate();
+ eof = (EOF == iss.peek());
+ iss.clear(state);
}
+ CHECK_AND_NO_ASSERT_MES(::serialization::check_stream_state(ar), false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
+
return true;
}
//---------------------------------------------------------------
+ crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra)
+ {
+ std::vector<tx_extra_field> tx_extra_fields;
+ if (!parse_tx_extra(tx_extra, tx_extra_fields))
+ return null_pkey;
+
+ tx_extra_pub_key pub_key_field;
+ if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field))
+ return null_pkey;
+
+ return pub_key_field.pub_key;
+ }
+ //---------------------------------------------------------------
+ crypto::public_key get_tx_pub_key_from_extra(const transaction& tx)
+ {
+ return get_tx_pub_key_from_extra(tx.extra);
+ }
+ //---------------------------------------------------------------
bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key)
{
tx.extra.resize(tx.extra.size() + 1 + sizeof(crypto::public_key));
@@ -259,32 +262,50 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
- bool add_tx_extra_nonce(transaction& tx, const blobdata& extra_nonce)
+ bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce)
{
- CHECK_AND_ASSERT_MES(extra_nonce.size() <=255, false, "extra nonce could be 255 bytes max");
- size_t start_pos = tx.extra.size();
- tx.extra.resize(tx.extra.size() + 2 + extra_nonce.size());
+ CHECK_AND_ASSERT_MES(extra_nonce.size() <= TX_EXTRA_NONCE_MAX_COUNT, false, "extra nonce could be 255 bytes max");
+ size_t start_pos = tx_extra.size();
+ tx_extra.resize(tx_extra.size() + 2 + extra_nonce.size());
//write tag
- tx.extra[start_pos] = TX_EXTRA_NONCE;
+ tx_extra[start_pos] = TX_EXTRA_NONCE;
//write len
++start_pos;
- tx.extra[start_pos] = static_cast<uint8_t>(extra_nonce.size());
+ tx_extra[start_pos] = static_cast<uint8_t>(extra_nonce.size());
//write data
++start_pos;
- memcpy(&tx.extra[start_pos], extra_nonce.data(), extra_nonce.size());
+ memcpy(&tx_extra[start_pos], extra_nonce.data(), extra_nonce.size());
+ return true;
+ }
+ //---------------------------------------------------------------
+ void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id)
+ {
+ extra_nonce.clear();
+ extra_nonce.push_back(TX_EXTRA_NONCE_PAYMENT_ID);
+ const uint8_t* payment_id_ptr = reinterpret_cast<const uint8_t*>(&payment_id);
+ std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce));
+ }
+ //---------------------------------------------------------------
+ bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id)
+ {
+ if(sizeof(crypto::hash) + 1 != extra_nonce.size())
+ return false;
+ if(TX_EXTRA_NONCE_PAYMENT_ID != extra_nonce[0])
+ return false;
+ payment_id = *reinterpret_cast<const crypto::hash*>(extra_nonce.data() + 1);
return true;
}
//---------------------------------------------------------------
- bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, transaction& tx, uint64_t unlock_time)
+ bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time)
{
tx.vin.clear();
tx.vout.clear();
tx.signatures.clear();
- tx.extra.clear();
tx.version = CURRENT_TRANSACTION_VERSION;
tx.unlock_time = unlock_time;
+ tx.extra = extra;
keypair txkey = keypair::generate();
add_tx_pub_key_to_extra(tx, txkey.pub);
@@ -506,7 +527,10 @@ namespace cryptonote
//---------------------------------------------------------------
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered)
{
- return lookup_acc_outs(acc, tx, get_tx_pub_key_from_extra(tx), outs, money_transfered);
+ crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
+ if(null_pkey == tx_pub_key)
+ return false;
+ return lookup_acc_outs(acc, tx, tx_pub_key, outs, money_transfered);
}
//---------------------------------------------------------------
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered)
@@ -594,6 +618,7 @@ namespace cryptonote
//genesis block
bl = boost::value_initialized<block>();
+
account_public_address ac = boost::value_initialized<account_public_address>();
std::vector<size_t> sz;
construct_miner_tx(0, 0, 0, 0, 0, ac, bl.miner_tx); // zero fee in genesis
@@ -601,16 +626,16 @@ namespace cryptonote
std::string hex_tx_represent = string_tools::buff_to_hex_nodelimer(txb);
//hard code coinbase tx in genesis block, because "tru" generating tx use random, but genesis should be always the same
- std::string genesis_coinbase_tx_hex = "013c01ff0001ffffffffffff03029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121017767aafcde9be00dcfd098715ebcf7f410daebc582fda69d24a28e9d0bc890d1";
+ std::string genesis_coinbase_tx_hex = "010a01ff0001ffffffffffff0f029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121013c086a48c15fb637a96991bc6d53caf77068b5ba6eeb3c82357228c49790584a";
blobdata tx_bl;
string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl);
bool r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx);
CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
- bl.major_version = 1;
- bl.minor_version = 0;
+ bl.major_version = CURRENT_BLOCK_MAJOR_VERSION;
+ bl.minor_version = CURRENT_BLOCK_MINOR_VERSION;
bl.timestamp = 0;
- bl.nonce = 10000;
+ bl.nonce = 70;
miner::find_nonce_for_given_block(bl, 1, 0);
return true;
}
diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h
index 5873d2943..138fb5224 100644
--- a/src/cryptonote_core/cryptonote_format_utils.h
+++ b/src/cryptonote_core/cryptonote_format_utils.h
@@ -41,11 +41,26 @@ namespace cryptonote
};
//---------------------------------------------------------------
- bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, transaction& tx, uint64_t unlock_time);
- bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key);
+ bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time);
+
+ template<typename T>
+ bool find_tx_extra_field_by_type(const std::vector<tx_extra_field>& tx_extra_fields, T& field)
+ {
+ auto it = std::find_if(tx_extra_fields.begin(), tx_extra_fields.end(), [](const tx_extra_field& f) { return typeid(T) == f.type(); });
+ if(tx_extra_fields.end() == it)
+ return false;
+
+ field = boost::get<T>(*it);
+ return true;
+ }
+
+ bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields);
+ crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra);
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx);
bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key);
- bool add_tx_extra_nonce(transaction& tx, const blobdata& extra_nonce);
+ bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce);
+ void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id);
+ bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id);
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
diff --git a/src/cryptonote_core/difficulty.cpp b/src/cryptonote_core/difficulty.cpp
index 052f46662..3dde6ad6c 100644
--- a/src/cryptonote_core/difficulty.cpp
+++ b/src/cryptonote_core/difficulty.cpp
@@ -24,7 +24,7 @@ namespace cryptonote {
#include <winnt.h>
static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) {
- low = UnsignedMultiply128(a, b, &high);
+ low = mul128(a, b, &high);
}
#else
diff --git a/src/cryptonote_core/tx_extra.h b/src/cryptonote_core/tx_extra.h
index 7e27cbc7f..8cff085dc 100644
--- a/src/cryptonote_core/tx_extra.h
+++ b/src/cryptonote_core/tx_extra.h
@@ -2,10 +2,93 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#pragma once
+#pragma once
+#define TX_EXTRA_PADDING_MAX_COUNT 255
+#define TX_EXTRA_NONCE_MAX_COUNT 255
-#define TX_EXTRA_PADDING_MAX_COUNT 40
+#define TX_EXTRA_TAG_PADDING 0x00
#define TX_EXTRA_TAG_PUBKEY 0x01
#define TX_EXTRA_NONCE 0x02
+
+#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
+
+namespace cryptonote
+{
+ struct tx_extra_padding
+ {
+ size_t size;
+
+ // load
+ template <template <bool> class Archive>
+ bool do_serialize(Archive<false>& ar)
+ {
+ // size - 1 - because of variant tag
+ for (size = 1; size <= TX_EXTRA_PADDING_MAX_COUNT; ++size)
+ {
+ std::ios_base::iostate state = ar.stream().rdstate();
+ bool eof = EOF == ar.stream().peek();
+ ar.stream().clear(state);
+
+ if (eof)
+ break;
+
+ uint8_t zero;
+ if (!::do_serialize(ar, zero))
+ return false;
+
+ if (0 != zero)
+ return false;
+ }
+
+ return size <= TX_EXTRA_PADDING_MAX_COUNT;
+ }
+
+ // store
+ template <template <bool> class Archive>
+ bool do_serialize(Archive<true>& ar)
+ {
+ if(TX_EXTRA_PADDING_MAX_COUNT < size)
+ return false;
+
+ // i = 1 - because of variant tag
+ for (size_t i = 1; i < size; ++i)
+ {
+ uint8_t zero = 0;
+ if (!::do_serialize(ar, zero))
+ return false;
+ }
+ return true;
+ }
+ };
+
+ struct tx_extra_pub_key
+ {
+ crypto::public_key pub_key;
+
+ BEGIN_SERIALIZE()
+ FIELD(pub_key)
+ END_SERIALIZE()
+ };
+
+ struct tx_extra_nonce
+ {
+ std::string nonce;
+
+ BEGIN_SERIALIZE()
+ FIELD(nonce)
+ if(TX_EXTRA_NONCE_MAX_COUNT < nonce.size()) return false;
+ END_SERIALIZE()
+ };
+
+ // tx_extra_field format, except tx_extra_padding and tx_extra_pub_key:
+ // varint tag;
+ // varint size;
+ // varint data[];
+ typedef boost::variant<tx_extra_padding, tx_extra_pub_key, tx_extra_nonce> tx_extra_field;
+}
+
+VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING);
+VARIANT_TAG(binary_archive, cryptonote::tx_extra_pub_key, TX_EXTRA_TAG_PUBKEY);
+VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index 3ac1331bd..3978dfb96 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -141,6 +141,9 @@ namespace cryptonote
uint64_t operator()(const txin_to_scripthash& tx) const {return 0;}
};
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ friend class blockchain_storage;
+#endif
};
}