mirror of
https://github.com/kvazar-network/kevacoin.git
synced 2025-09-03 10:22:09 +00:00
WIP: merged mining.
This commit is contained in:
parent
b9335132b0
commit
fce6d8ea6d
@ -87,3 +87,7 @@ void hash_extra_jh(const void *data, size_t length, char *hash);
|
||||
void hash_extra_skein(const void *data, size_t length, char *hash);
|
||||
|
||||
void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash);
|
||||
|
||||
size_t tree_depth(size_t count);
|
||||
void tree_branch(const char (*hashes)[HASH_SIZE], size_t count, char (*branch)[HASH_SIZE]);
|
||||
void tree_hash_from_branch(const char (*branch)[HASH_SIZE], size_t depth, const char* leaf, const void* path, char* root_hash);
|
||||
|
@ -1,21 +1,21 @@
|
||||
// Copyright (c) 2014-2018, 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
|
||||
@ -25,7 +25,7 @@
|
||||
// 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
|
||||
|
||||
#include <assert.h>
|
||||
@ -43,7 +43,7 @@
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
/***
|
||||
/***
|
||||
* Round to power of two, for count>=3 and for count being not too large (as reasonable for tree hash calculations)
|
||||
*/
|
||||
size_t tree_hash_cnt(size_t count) {
|
||||
@ -112,3 +112,98 @@ void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) {
|
||||
cn_fast_hash(ints[0], 64, root_hash);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************************/
|
||||
/* Helper functions for merged mining - for merkle tree branch compuation. */
|
||||
|
||||
size_t tree_depth(size_t count)
|
||||
{
|
||||
size_t i;
|
||||
size_t depth = 0;
|
||||
assert(count > 0);
|
||||
for (i = sizeof(size_t) << 2; i > 0; i >>= 1)
|
||||
{
|
||||
if (count >> i > 0)
|
||||
{
|
||||
count >>= i;
|
||||
depth += i;
|
||||
}
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
void tree_branch(const char (*hashes)[HASH_SIZE], size_t count, char (*branch)[HASH_SIZE])
|
||||
{
|
||||
size_t i, j;
|
||||
size_t cnt = 1;
|
||||
size_t depth = 0;
|
||||
char (*ints)[HASH_SIZE];
|
||||
assert(count > 0);
|
||||
for (i = sizeof(size_t) << 2; i > 0; i >>= 1)
|
||||
{
|
||||
if (cnt << i <= count)
|
||||
{
|
||||
cnt <<= i;
|
||||
depth += i;
|
||||
}
|
||||
}
|
||||
assert(cnt == 1ULL << depth);
|
||||
assert(depth == tree_depth(count));
|
||||
ints = alloca((cnt - 1) * HASH_SIZE);
|
||||
memcpy(ints, hashes + 1, (2 * cnt - count - 1) * HASH_SIZE);
|
||||
for (i = 2 * cnt - count, j = 2 * cnt - count - 1; j < cnt - 1; i += 2, ++j)
|
||||
{
|
||||
cn_fast_hash(hashes[i], 2 * HASH_SIZE, ints[j]);
|
||||
}
|
||||
assert(i == count);
|
||||
while (depth > 0)
|
||||
{
|
||||
assert(cnt == 1ULL << depth);
|
||||
cnt >>= 1;
|
||||
--depth;
|
||||
memcpy(branch[depth], ints[0], HASH_SIZE);
|
||||
for (i = 1, j = 0; j < cnt - 1; i += 2, ++j)
|
||||
{
|
||||
cn_fast_hash(ints[i], 2 * HASH_SIZE, ints[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tree_hash_from_branch(const char (*branch)[HASH_SIZE], size_t depth, const char* leaf, const void* path, char* root_hash)
|
||||
{
|
||||
if (depth == 0)
|
||||
{
|
||||
memcpy(root_hash, leaf, HASH_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
char buffer[2][HASH_SIZE];
|
||||
int from_leaf = 1;
|
||||
char *leaf_path, *branch_path;
|
||||
while (depth > 0)
|
||||
{
|
||||
--depth;
|
||||
if (path && (((const char*) path)[depth >> 3] & (1 << (depth & 7))) != 0)
|
||||
{
|
||||
leaf_path = buffer[1];
|
||||
branch_path = buffer[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
leaf_path = buffer[0];
|
||||
branch_path = buffer[1];
|
||||
}
|
||||
if (from_leaf)
|
||||
{
|
||||
memcpy(leaf_path, leaf, HASH_SIZE);
|
||||
from_leaf = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cn_fast_hash(buffer, 2 * HASH_SIZE, leaf_path);
|
||||
}
|
||||
memcpy(branch_path, branch[depth], HASH_SIZE);
|
||||
}
|
||||
cn_fast_hash(buffer, 2 * HASH_SIZE, root_hash);
|
||||
}
|
||||
}
|
||||
|
@ -618,6 +618,32 @@ namespace cryptonote
|
||||
return find_tx_extra_field_by_type(tx_extra_fields, keva_block);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool append_keva_blockhash_to_extra(std::vector<uint8_t>& tx_extra, const tx_extra_keva_blockhash& keva_blockhash)
|
||||
{
|
||||
// convert to variant
|
||||
tx_extra_field field = tx_extra_keva_blockhash{ keva_blockhash };
|
||||
// serialize
|
||||
std::ostringstream oss;
|
||||
binary_archive<true> ar(oss);
|
||||
bool r = ::do_serialize(ar, field);
|
||||
CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra keva blockhash");
|
||||
// append
|
||||
std::string tx_extra_str = oss.str();
|
||||
size_t pos = tx_extra.size();
|
||||
tx_extra.resize(tx_extra.size() + tx_extra_str.size());
|
||||
memcpy(&tx_extra[pos], tx_extra_str.data(), tx_extra_str.size());
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_keva_blockhash_from_extra(const std::vector<uint8_t>& tx_extra, tx_extra_keva_blockhash& keva_blockhash)
|
||||
{
|
||||
std::vector<tx_extra_field> tx_extra_fields;
|
||||
if (!parse_tx_extra(tx_extra, tx_extra_fields))
|
||||
return false;
|
||||
|
||||
return find_tx_extra_field_by_type(tx_extra_fields, keva_blockhash);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_inputs_money_amount(const transaction& tx, uint64_t& money)
|
||||
{
|
||||
money = 0;
|
||||
|
@ -76,6 +76,8 @@ namespace cryptonote
|
||||
bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce);
|
||||
bool append_keva_block_to_extra(std::vector<uint8_t>& tx_extra, const tx_extra_keva_block& keva_block);
|
||||
bool get_keva_block_from_extra(const std::vector<uint8_t>& tx_extra, tx_extra_keva_block& keva_block);
|
||||
bool append_keva_blockhash_to_extra(std::vector<uint8_t>& tx_extra, const tx_extra_keva_blockhash& keva_blockhash);
|
||||
bool get_keva_blockhash_from_extra(const std::vector<uint8_t>& tx_extra, tx_extra_keva_blockhash& keva_blockhash);
|
||||
bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type);
|
||||
void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id);
|
||||
void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id);
|
||||
|
@ -38,10 +38,17 @@
|
||||
#define TX_EXTRA_TAG_PUBKEY 0x01
|
||||
#define TX_EXTRA_NONCE 0x02
|
||||
#define TX_EXTRA_MERGE_MINING_TAG 0x03
|
||||
|
||||
// TX_EXTRA_KEVA_BLOCK_HASH_TAG is exactly the same as
|
||||
// TX_EXTRA_MERGE_MINING_TAG
|
||||
#define TX_EXTRA_KEVA_BLOCKHASH_TAG 0x03
|
||||
|
||||
#define TX_EXTRA_TAG_ADDITIONAL_PUBKEYS 0x04
|
||||
#define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE
|
||||
|
||||
#define TX_EXTRA_KEVA_BLOCK_TAG 0xa1
|
||||
// TX_EXTRA_KEVA_BLOCK_TAG is exactly the same as
|
||||
// TX_EXTRA_MYSTERIOUS_MINERGATE_TAG
|
||||
#define TX_EXTRA_KEVA_BLOCK_TAG 0xDE
|
||||
|
||||
#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
|
||||
#define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID 0x01
|
||||
@ -162,6 +169,8 @@ namespace cryptonote
|
||||
}
|
||||
};
|
||||
|
||||
typedef tx_extra_merge_mining_tag tx_extra_keva_blockhash;
|
||||
|
||||
// per-output additional tx pubkey for multi-destination transfers involving at least one subaddress
|
||||
struct tx_extra_additional_pub_keys
|
||||
{
|
||||
@ -181,21 +190,13 @@ namespace cryptonote
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_keva_block
|
||||
{
|
||||
std::string keva_block;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(keva_block)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
typedef tx_extra_mysterious_minergate tx_extra_keva_block;
|
||||
|
||||
// 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_merge_mining_tag, tx_extra_additional_pub_keys, tx_extra_mysterious_minergate, tx_extra_keva_block> tx_extra_field;
|
||||
typedef boost::variant<tx_extra_padding, tx_extra_pub_key, tx_extra_nonce, tx_extra_merge_mining_tag, tx_extra_additional_pub_keys, tx_extra_mysterious_minergate, tx_extra_keva_block, tx_extra_keva_blockhash> tx_extra_field;
|
||||
}
|
||||
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING);
|
||||
@ -204,4 +205,3 @@ VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_additional_pub_keys, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_keva_block, TX_EXTRA_KEVA_BLOCK_TAG);
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
extern "C" void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, uint64_t height);
|
||||
|
||||
const uint256 CBlockHeader::DIFFICULTY_1 = uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
|
||||
uint256 CBlockHeader::GetHash() const
|
||||
{
|
||||
CHashWriter hashWriter(SER_GETHASH, PROTOCOL_VERSION);
|
||||
@ -30,13 +32,43 @@ uint256 CBlockHeader::GetPoWHash() const
|
||||
return thash;
|
||||
}
|
||||
|
||||
// prev_id of CN header is used to store the kevacoin block hash.
|
||||
// The value of prev_id and block hash must be the same to prove
|
||||
// that PoW has been properly done.
|
||||
if (GetHash() != cnHeader.prev_id) {
|
||||
memset(thash.begin(), 0xff, thash.size());
|
||||
if (!IsAuxpow()) {
|
||||
// prev_id of CN header is used to store the kevacoin block hash.
|
||||
// The value of prev_id and block hash must be the same to prove
|
||||
// that PoW has been properly done.
|
||||
if (GetHash() != cnHeader.prev_id) {
|
||||
return DIFFICULTY_1;
|
||||
}
|
||||
cryptonote::blobdata blob = cryptonote::t_serializable_object_to_blob(cnHeader);
|
||||
cn_slow_hash(blob.data(), blob.size(), BEGIN(thash), 2, 0, 0);
|
||||
return thash;
|
||||
}
|
||||
|
||||
// Merged mining.
|
||||
cryptonote::tx_extra_keva_blockhash keva_blockhash;
|
||||
if (!cryptonote::get_keva_blockhash_from_extra(cnHeader.aux_pow->miner_tx.extra, keva_blockhash)) {
|
||||
return DIFFICULTY_1;
|
||||
}
|
||||
uint256 actualHash = GetHash();
|
||||
if (memcmp(keva_blockhash.merkle_root.data, actualHash.begin(), thash.size()) != 0) {
|
||||
return DIFFICULTY_1;
|
||||
}
|
||||
|
||||
crypto::hash miner_tx_hash;
|
||||
if (!cryptonote::get_transaction_hash(cnHeader.aux_pow->miner_tx, miner_tx_hash)) {
|
||||
return DIFFICULTY_1;
|
||||
}
|
||||
|
||||
crypto::hash aux_blocks_merkle_root;
|
||||
crypto::tree_hash_from_branch(
|
||||
reinterpret_cast<const char (*)[32]>(cnHeader.aux_pow->merkle_branch.data()),
|
||||
cnHeader.aux_pow->merkle_branch.size(),
|
||||
reinterpret_cast<char*>(&miner_tx_hash), 0,
|
||||
reinterpret_cast<char*>(&aux_blocks_merkle_root));
|
||||
|
||||
if (memcmp(aux_blocks_merkle_root.data, cnHeader.merkle_root.begin(), cnHeader.merkle_root.size()) != 0) {
|
||||
return DIFFICULTY_1;
|
||||
}
|
||||
cryptonote::blobdata blob = cryptonote::t_serializable_object_to_blob(cnHeader);
|
||||
cn_slow_hash(blob.data(), blob.size(), BEGIN(thash), 2, 0, 0);
|
||||
return thash;
|
||||
|
@ -12,6 +12,56 @@
|
||||
|
||||
#include <cryptonote_basic/cryptonote_format_utils.h>
|
||||
|
||||
class CAuxPow
|
||||
{
|
||||
public:
|
||||
// Cryptnote coinbase tx, which contains the block hash of kevacoin block.
|
||||
cryptonote::transaction miner_tx;
|
||||
|
||||
// Merkle branch is used to establish that miner_tx is part of the
|
||||
// merkel tree whose root is merkle_root.
|
||||
std::vector<crypto::hash> merkle_branch;
|
||||
|
||||
uint256 CheckMerkleBranch (uint256 hash,
|
||||
const std::vector<uint256>& vMerkleBranch,
|
||||
int nIndex)
|
||||
{
|
||||
if (nIndex == -1) {
|
||||
return uint256();
|
||||
}
|
||||
#if 0
|
||||
for (std::vector<uint256>::const_iterator it(vMerkleBranch.begin());
|
||||
it != vMerkleBranch.end(); ++it) {
|
||||
if (nIndex & 1) {
|
||||
hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash));
|
||||
} else {
|
||||
hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it));
|
||||
}
|
||||
nIndex >>= 1;
|
||||
}
|
||||
return hash;
|
||||
#endif
|
||||
}
|
||||
|
||||
// load
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<false>& ar)
|
||||
{
|
||||
FIELD(miner_tx)
|
||||
FIELD(merkle_branch)
|
||||
return true;
|
||||
}
|
||||
|
||||
// store
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<true>& ar)
|
||||
{
|
||||
FIELD(miner_tx)
|
||||
FIELD(merkle_branch)
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This header is to store the proof-of-work of cryptonote mining.
|
||||
* Kevacoin uses Cryptonight PoW and uses its existing infrastructure
|
||||
@ -28,11 +78,27 @@ public:
|
||||
uint256 merkle_root;
|
||||
size_t nTxes; // Number of transactions.
|
||||
|
||||
CryptoNoteHeader()
|
||||
private:
|
||||
bool is_aux_block;
|
||||
|
||||
public:
|
||||
std::unique_ptr<CAuxPow> aux_pow; // It is used only is_aux_block is true.
|
||||
|
||||
CryptoNoteHeader() : is_aux_block(false)
|
||||
{
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetAuxBlock(bool isAuxBlock)
|
||||
{
|
||||
is_aux_block = isAuxBlock;
|
||||
}
|
||||
|
||||
bool IsAuxBlock()
|
||||
{
|
||||
return is_aux_block;
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
major_version = 0;
|
||||
@ -64,6 +130,10 @@ public:
|
||||
FIELD(merkle_hash)
|
||||
memcpy(merkle_root.begin(), &merkle_hash, merkle_root.size());
|
||||
VARINT_FIELD(nTxes)
|
||||
if (is_aux_block) {
|
||||
aux_pow_ptr = std::make_unique<CAuxPow>();
|
||||
FIELD(*aux_pow_ptr)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -82,6 +152,9 @@ public:
|
||||
memcpy(&merkle_hash, merkle_root.begin(), merkle_root.size());
|
||||
FIELD(merkle_hash)
|
||||
VARINT_FIELD(nTxes)
|
||||
if (is_aux_block) {
|
||||
FIELD(*aux_pow)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -124,6 +197,7 @@ public:
|
||||
uint256 hashMerkleRoot;
|
||||
uint32_t nTime;
|
||||
uint32_t nBits;
|
||||
// nNonce is used to store chainID in merged mining.
|
||||
uint32_t nNonce;
|
||||
|
||||
// CryptoNote header for emulation or merged mining
|
||||
@ -146,6 +220,7 @@ public:
|
||||
READWRITE(nNonce);
|
||||
// Genesis block does not have cnHeader.
|
||||
if (!hashPrevBlock.IsNull()) {
|
||||
cnHeader.SetAuxBlock(IsAuxpow());
|
||||
READWRITE(cnHeader);
|
||||
}
|
||||
}
|
||||
@ -173,6 +248,30 @@ public:
|
||||
{
|
||||
return (int64_t)nTime;
|
||||
}
|
||||
|
||||
static const int32_t DEFAULT_AUXPOW_CHAIN_ID = 0x000000AD;
|
||||
|
||||
// ChainID is used for merged mining.
|
||||
inline void SetChainID(uint32_t chainID = CBlockHeader::DEFAULT_AUXPOW_CHAIN_ID)
|
||||
{
|
||||
nNonce = chainID;
|
||||
}
|
||||
|
||||
inline uint32_t GetChainID() const
|
||||
{
|
||||
return nNonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the auxpow flag is set in the version.
|
||||
* @return True iff this block version is marked as auxpow.
|
||||
*/
|
||||
inline bool IsAuxpow() const
|
||||
{
|
||||
return nNonce != 0;
|
||||
}
|
||||
|
||||
static const uint256 DIFFICULTY_1;
|
||||
};
|
||||
|
||||
|
||||
@ -193,7 +292,13 @@ public:
|
||||
CBlock(const CBlockHeader &header)
|
||||
{
|
||||
SetNull();
|
||||
*((CBlockHeader*)this) = header;
|
||||
//*((CBlockHeader*)this) = header;
|
||||
nVersion = header.nVersion;
|
||||
hashPrevBlock = header.hashPrevBlock;
|
||||
hashMerkleRoot = header.hashMerkleRoot;
|
||||
nTime = header.nTime;
|
||||
nBits = header.nBits;
|
||||
nNonce = header.nNonce;
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
@ -302,8 +302,8 @@ std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
|
||||
UniValue getblocktemplate(const JSONRPCRequest& request)
|
||||
{
|
||||
// JSON-RPC2 request
|
||||
// {reserve_size: 8, wallet_address: poolAddress}
|
||||
if (request.fHelp || request.params.size() != 2)
|
||||
// {reserve_size: 8, wallet_address: poolAddress, aux_block: true | false}
|
||||
if (request.fHelp || request.params.size() < 2)
|
||||
throw std::runtime_error(
|
||||
"getblocktemplate ( TemplateRequest )\n"
|
||||
"\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
|
||||
@ -405,6 +405,14 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMS, "Invalid wallet address");
|
||||
}
|
||||
|
||||
bool is_aux_block = false;
|
||||
if (request.params.size() == 3) {
|
||||
if (request.params[2].getType() != UniValue::VBOOL) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMS, "Incorrect is_autx_block type, boolean expected");
|
||||
}
|
||||
is_aux_block = request.params[2].get_bool();
|
||||
}
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
std::string strMode = "template";
|
||||
@ -448,7 +456,12 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
|
||||
|
||||
// Update nTime
|
||||
UpdateTime(pblock, consensusParams, pindexPrev);
|
||||
pblock->nNonce = 0;
|
||||
if (is_aux_block) {
|
||||
// Mark it as auxpow block.
|
||||
pblock->SetChainID();
|
||||
} else {
|
||||
pblock->nNonce = 0;
|
||||
}
|
||||
|
||||
std::set<std::string> setClientRules;
|
||||
UniValue aRules(UniValue::VARR);
|
||||
@ -544,7 +557,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
|
||||
stream << *pblock;
|
||||
std::string kevaBlockData = stream.str();
|
||||
cryptonote::tx_extra_keva_block extra_keva_block;
|
||||
extra_keva_block.keva_block = kevaBlockData;
|
||||
extra_keva_block.data = kevaBlockData;
|
||||
if (!cryptonote::append_keva_block_to_extra(cn_block.miner_tx.extra, extra_keva_block)) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal error: failed to add block");
|
||||
}
|
||||
@ -608,7 +621,7 @@ static uint256 CryptoHashToUint256(const crypto::hash& hash)
|
||||
// Cryptonote RPC call, only one parameter allowed.
|
||||
UniValue submitblock(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() != 1) {
|
||||
if (request.fHelp || request.params.size() < 2) {
|
||||
throw std::runtime_error(
|
||||
"submitblock \"hexdata\"\n"
|
||||
"\nAttempts to submit new block to network.\n"
|
||||
@ -616,7 +629,7 @@ UniValue submitblock(const JSONRPCRequest& request)
|
||||
|
||||
"\nArguments\n"
|
||||
"1. \"hexdata\" (string, required) the hex-encoded block data to submit\n"
|
||||
"2. \"dummy\" (optional) dummy value, for compatibility with BIP22. This value is ignored.\n"
|
||||
"2. \"auxpow\" (string, optional) block auxpow data for merged mining.\n"
|
||||
"\nResult:\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("submitblock", "\"mydata\"")
|
||||
@ -624,15 +637,26 @@ UniValue submitblock(const JSONRPCRequest& request)
|
||||
);
|
||||
}
|
||||
|
||||
std::unique_ptr<CAuxPow> auxPow = std::make_unique<CAuxPow>();
|
||||
bool isAuxPow = false;
|
||||
if (request.params.size() == 2) {
|
||||
if (request.params[1].getType() != UniValue::VSTR) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "auxpow must be string type");
|
||||
}
|
||||
std::stringstream ss;
|
||||
ss << request.params[1].get_str();
|
||||
// load
|
||||
binary_archive<false> ba(ss);
|
||||
isAuxPow = ::serialization::serialize(ba, *auxPow);
|
||||
}
|
||||
|
||||
cryptonote::blobdata blockblob;
|
||||
if(!epee::string_tools::parse_hexstr_to_binbuff(request.params[0].get_str(), blockblob))
|
||||
{
|
||||
if(!epee::string_tools::parse_hexstr_to_binbuff(request.params[0].get_str(), blockblob)) {
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Wrong block blob");
|
||||
}
|
||||
|
||||
cryptonote::block cnblock = AUTO_VAL_INIT(cnblock);
|
||||
if(!cryptonote::parse_and_validate_block_from_blob(blockblob, cnblock))
|
||||
{
|
||||
if(!cryptonote::parse_and_validate_block_from_blob(blockblob, cnblock)) {
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Wrong block blob");
|
||||
}
|
||||
|
||||
@ -643,7 +667,7 @@ UniValue submitblock(const JSONRPCRequest& request)
|
||||
|
||||
std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
|
||||
CBlock& block = *blockptr;
|
||||
const std::vector<char> keva_block(keva_block_blob.keva_block.begin(), keva_block_blob.keva_block.end());
|
||||
const std::vector<char> keva_block(keva_block_blob.data.begin(), keva_block_blob.data.end());
|
||||
CDataStream ssBlock(keva_block, SER_NETWORK, PROTOCOL_VERSION);
|
||||
try {
|
||||
ssBlock >> block;
|
||||
@ -672,6 +696,11 @@ UniValue submitblock(const JSONRPCRequest& request)
|
||||
throw JSONRPCError(RPC_VERIFY_ERROR, "Kevacoin block hash does not match cryptnote hash");
|
||||
}
|
||||
|
||||
block.cnHeader.SetAuxBlock(isAuxPow);
|
||||
if (isAuxPow) {
|
||||
block.cnHeader.aux_pow = std::move(auxPow);
|
||||
}
|
||||
|
||||
// TODO: fix the return message.
|
||||
bool fBlockPresent = false;
|
||||
{
|
||||
@ -924,8 +953,8 @@ static const CRPCCommand commands[] =
|
||||
{ "mining", "getnetworkhashps", &getnetworkhashps, {"nblocks","height"} },
|
||||
{ "mining", "getmininginfo", &getmininginfo, {} },
|
||||
{ "mining", "prioritisetransaction", &prioritisetransaction, {"txid","dummy","fee_delta"} },
|
||||
{ "mining", "getblocktemplate", &getblocktemplate, {"reserve_size", "wallet_address"} },
|
||||
{ "mining", "submitblock", &submitblock, {"hexdata","dummy"} },
|
||||
{ "mining", "getblocktemplate", &getblocktemplate, {"reserve_size", "wallet_address", "is_aux_block"} },
|
||||
{ "mining", "submitblock", &submitblock, {"hexdata","auxpow"} },
|
||||
|
||||
|
||||
{ "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },
|
||||
|
Loading…
x
Reference in New Issue
Block a user