monero/src/cryptonote_core/cryptonote_basic.h
moneromooo-monero 6376627530
hardfork: switch voting to block minor version
Using major version would cause older daemons to reject those
blocks as they fail to deserialize blocks with a major version
which is not 1. There is no such restriction on the minor
version, so switching allows older daemons to coexist with
newer ones till the actual fork date, when most will hopefully
have updated already.

Also, for the same reason, we consider a vote for 0 to be a
vote for 1, since older daemons set minor version to 0.
2015-10-21 19:21:14 +01:00

375 lines
10 KiB
C++

// Copyright (c) 2014-2015, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include <boost/variant.hpp>
#include <boost/functional/hash/hash.hpp>
#include <vector>
#include <cstring> // memcmp
#include <sstream>
#include "serialization/serialization.h"
#include "serialization/variant.h"
#include "serialization/vector.h"
#include "serialization/binary_archive.h"
#include "serialization/json_archive.h"
#include "serialization/debug_archive.h"
#include "serialization/crypto.h"
#include "serialization/keyvalue_serialization.h" // eepe named serialization
#include "string_tools.h"
#include "cryptonote_config.h"
#include "crypto/crypto.h"
#include "crypto/hash.h"
#include "misc_language.h"
#include "tx_extra.h"
#define DB_MEMORY 1
#define DB_LMDB 2
namespace cryptonote
{
const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash);
const static crypto::hash8 null_hash8 = AUTO_VAL_INIT(null_hash8);
const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey);
typedef std::vector<crypto::signature> ring_signature;
/* outputs */
struct txout_to_script
{
std::vector<crypto::public_key> keys;
std::vector<uint8_t> script;
BEGIN_SERIALIZE_OBJECT()
FIELD(keys)
FIELD(script)
END_SERIALIZE()
};
struct txout_to_scripthash
{
crypto::hash hash;
};
struct txout_to_key
{
txout_to_key() { }
txout_to_key(const crypto::public_key &_key) : key(_key) { }
crypto::public_key key;
};
/* inputs */
struct txin_gen
{
size_t height;
BEGIN_SERIALIZE_OBJECT()
VARINT_FIELD(height)
END_SERIALIZE()
};
struct txin_to_script
{
crypto::hash prev;
size_t prevout;
std::vector<uint8_t> sigset;
BEGIN_SERIALIZE_OBJECT()
FIELD(prev)
VARINT_FIELD(prevout)
FIELD(sigset)
END_SERIALIZE()
};
struct txin_to_scripthash
{
crypto::hash prev;
size_t prevout;
txout_to_script script;
std::vector<uint8_t> sigset;
BEGIN_SERIALIZE_OBJECT()
FIELD(prev)
VARINT_FIELD(prevout)
FIELD(script)
FIELD(sigset)
END_SERIALIZE()
};
struct txin_to_key
{
uint64_t amount;
std::vector<uint64_t> key_offsets;
crypto::key_image k_image; // double spending protection
BEGIN_SERIALIZE_OBJECT()
VARINT_FIELD(amount)
FIELD(key_offsets)
FIELD(k_image)
END_SERIALIZE()
};
typedef boost::variant<txin_gen, txin_to_script, txin_to_scripthash, txin_to_key> txin_v;
typedef boost::variant<txout_to_script, txout_to_scripthash, txout_to_key> txout_target_v;
//typedef std::pair<uint64_t, txout> out_t;
struct tx_out
{
uint64_t amount;
txout_target_v target;
BEGIN_SERIALIZE_OBJECT()
VARINT_FIELD(amount)
FIELD(target)
END_SERIALIZE()
};
class transaction_prefix
{
public:
// tx information
size_t version;
uint64_t unlock_time; //number of block (or time), used as a limitation like: spend this tx not early then block/time
std::vector<txin_v> vin;
std::vector<tx_out> vout;
//extra
std::vector<uint8_t> extra;
BEGIN_SERIALIZE()
VARINT_FIELD(version)
if(CURRENT_TRANSACTION_VERSION < version) return false;
VARINT_FIELD(unlock_time)
FIELD(vin)
FIELD(vout)
FIELD(extra)
END_SERIALIZE()
protected:
transaction_prefix(){}
};
class transaction: public transaction_prefix
{
public:
std::vector<std::vector<crypto::signature> > signatures; //count signatures always the same as inputs count
transaction();
virtual ~transaction();
void set_null();
BEGIN_SERIALIZE_OBJECT()
FIELDS(*static_cast<transaction_prefix *>(this))
ar.tag("signatures");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures);
bool signatures_not_expected = signatures.empty();
if (!signatures_not_expected && vin.size() != signatures.size())
return false;
for (size_t i = 0; i < vin.size(); ++i)
{
size_t signature_size = get_signature_size(vin[i]);
if (signatures_not_expected)
{
if (0 == signature_size)
continue;
else
return false;
}
PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]);
if (signature_size != signatures[i].size())
return false;
FIELDS(signatures[i]);
if (vin.size() - i > 1)
ar.delimit_array();
}
ar.end_array();
END_SERIALIZE()
private:
static size_t get_signature_size(const txin_v& tx_in);
};
inline
transaction::transaction()
{
set_null();
}
inline
transaction::~transaction()
{
//set_null();
}
inline
void transaction::set_null()
{
version = 0;
unlock_time = 0;
vin.clear();
vout.clear();
extra.clear();
signatures.clear();
}
inline
size_t transaction::get_signature_size(const txin_v& tx_in)
{
struct txin_signature_size_visitor : public boost::static_visitor<size_t>
{
size_t operator()(const txin_gen& txin) const{return 0;}
size_t operator()(const txin_to_script& txin) const{return 0;}
size_t operator()(const txin_to_scripthash& txin) const{return 0;}
size_t operator()(const txin_to_key& txin) const {return txin.key_offsets.size();}
};
return boost::apply_visitor(txin_signature_size_visitor(), tx_in);
}
/************************************************************************/
/* */
/************************************************************************/
struct block_header
{
uint8_t major_version;
uint8_t minor_version; // now used as a voting mechanism, rather than how this particular block is built
uint64_t timestamp;
crypto::hash prev_id;
uint32_t nonce;
BEGIN_SERIALIZE()
VARINT_FIELD(major_version)
VARINT_FIELD(minor_version)
VARINT_FIELD(timestamp)
FIELD(prev_id)
FIELD(nonce)
END_SERIALIZE()
};
struct block: public block_header
{
transaction miner_tx;
std::vector<crypto::hash> tx_hashes;
BEGIN_SERIALIZE_OBJECT()
FIELDS(*static_cast<block_header *>(this))
FIELD(miner_tx)
FIELD(tx_hashes)
END_SERIALIZE()
};
/************************************************************************/
/* */
/************************************************************************/
struct account_public_address
{
crypto::public_key m_spend_public_key;
crypto::public_key m_view_public_key;
BEGIN_SERIALIZE_OBJECT()
FIELD(m_spend_public_key)
FIELD(m_view_public_key)
END_SERIALIZE()
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_public_key)
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_public_key)
END_KV_SERIALIZE_MAP()
};
struct keypair
{
crypto::public_key pub;
crypto::secret_key sec;
static inline keypair generate()
{
keypair k;
generate_keys(k.pub, k.sec);
return k;
}
};
//---------------------------------------------------------------
}
BLOB_SERIALIZER(cryptonote::txout_to_key);
BLOB_SERIALIZER(cryptonote::txout_to_scripthash);
VARIANT_TAG(binary_archive, cryptonote::txin_gen, 0xff);
VARIANT_TAG(binary_archive, cryptonote::txin_to_script, 0x0);
VARIANT_TAG(binary_archive, cryptonote::txin_to_scripthash, 0x1);
VARIANT_TAG(binary_archive, cryptonote::txin_to_key, 0x2);
VARIANT_TAG(binary_archive, cryptonote::txout_to_script, 0x0);
VARIANT_TAG(binary_archive, cryptonote::txout_to_scripthash, 0x1);
VARIANT_TAG(binary_archive, cryptonote::txout_to_key, 0x2);
VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc);
VARIANT_TAG(binary_archive, cryptonote::block, 0xbb);
VARIANT_TAG(json_archive, cryptonote::txin_gen, "gen");
VARIANT_TAG(json_archive, cryptonote::txin_to_script, "script");
VARIANT_TAG(json_archive, cryptonote::txin_to_scripthash, "scripthash");
VARIANT_TAG(json_archive, cryptonote::txin_to_key, "key");
VARIANT_TAG(json_archive, cryptonote::txout_to_script, "script");
VARIANT_TAG(json_archive, cryptonote::txout_to_scripthash, "scripthash");
VARIANT_TAG(json_archive, cryptonote::txout_to_key, "key");
VARIANT_TAG(json_archive, cryptonote::transaction, "tx");
VARIANT_TAG(json_archive, cryptonote::block, "block");
VARIANT_TAG(debug_archive, cryptonote::txin_gen, "gen");
VARIANT_TAG(debug_archive, cryptonote::txin_to_script, "script");
VARIANT_TAG(debug_archive, cryptonote::txin_to_scripthash, "scripthash");
VARIANT_TAG(debug_archive, cryptonote::txin_to_key, "key");
VARIANT_TAG(debug_archive, cryptonote::txout_to_script, "script");
VARIANT_TAG(debug_archive, cryptonote::txout_to_scripthash, "scripthash");
VARIANT_TAG(debug_archive, cryptonote::txout_to_key, "key");
VARIANT_TAG(debug_archive, cryptonote::transaction, "tx");
VARIANT_TAG(debug_archive, cryptonote::block, "block");