From 57ab5c72551e097e13860ccc9f19022ed1394e3b Mon Sep 17 00:00:00 2001 From: Jianping Wu Date: Wed, 6 Mar 2019 23:15:11 -0800 Subject: [PATCH] WIP: implemented submitblock. --- src/primitives/block.cpp | 22 +++++++- src/rpc/mining.cpp | 110 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 3ad17ce06..787302a70 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -3,7 +3,9 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include +#include #include #include @@ -20,7 +22,25 @@ uint256 CBlockHeader::GetHash() const uint256 CBlockHeader::GetPoWHash() const { uint256 thash; - cn_slow_hash(BEGIN(nVersion), 80, BEGIN(thash), 2, 0, 0); + if (hashPrevBlock.IsNull()) { + // Genesis block + cn_slow_hash(BEGIN(nVersion), 80, BEGIN(thash), 2, 0, 0); + return thash; + } + arith_uint256 blockHash = UintToArith256(GetHash()); + arith_uint256 expectedHash = UintToArith256(cnHeader.prev_id); + // blockHash should be the same as expectedHash. If so, after the + // following XOR operatiosn, the value of expectedHash is not changed. + blockHash ^= expectedHash; + expectedHash ^= blockHash; + CryptoNoteHeader header = cnHeader; + // Cryptonote prev_id is used to store kevacoin block hash. + header.prev_id = ArithToUint256(expectedHash); + + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << header; + std::string blob = stream.str(); + cn_slow_hash(blob.data(), blob.size(), BEGIN(thash), 2, 0, 0); return thash; } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index d3e7ceef1..da20f6e0d 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -971,6 +971,7 @@ protected: } }; +#if 0 UniValue submitblock(const JSONRPCRequest& request) { // We allow 2 arguments for compliance with BIP22. Argument 2 is ignored. @@ -1041,6 +1042,115 @@ UniValue submitblock(const JSONRPCRequest& request) } return BIP22ValidationResult(sc.state); } +#endif + +static uint256 CryptoHashToUint256(const crypto::hash& hash) +{ + std::vector prev_id((unsigned char*)(&hash), (unsigned char*)&(hash) + sizeof(crypto::hash)); + return uint256(prev_id); +} + +// Cryptonote RPC call, only one parameter allowed. +UniValue submitblock(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 1) { + throw std::runtime_error( + "submitblock \"hexdata\"\n" + "\nAttempts to submit new block to network.\n" + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" + + "\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" + "\nResult:\n" + "\nExamples:\n" + + HelpExampleCli("submitblock", "\"mydata\"") + + HelpExampleRpc("submitblock", "\"mydata\"") + ); + } + + cryptonote::blobdata 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)) + { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Wrong block blob"); + } + + cryptonote::tx_extra_keva_block keva_block_blob; + if (!cryptonote::get_keva_block_from_extra(cnblock.miner_tx.extra, keva_block_blob)) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Could not get Kevacoin block"); + } + + std::shared_ptr blockptr = std::make_shared(); + CBlock& block = *blockptr; + if (!DecodeHexBlk(block, keva_block_blob.keva_block)) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); + } + + if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block does not start with a coinbase"); + } + + block.cnHeader.major_version = cnblock.major_version; + block.cnHeader.minor_version = cnblock.minor_version; + block.cnHeader.prev_id = CryptoHashToUint256(cnblock.prev_id); + + block.cnHeader.nonce = cnblock.nonce; + crypto::hash tree_root_hash = get_tx_tree_hash(cnblock); + block.cnHeader.merkle_root = CryptoHashToUint256(tree_root_hash); + uint256 hash = block.GetHash(); + + // Cryptonote prev_id is used to store the block hash of kevacoin. + if (hash != block.cnHeader.prev_id) { + throw JSONRPCError(RPC_VERIFY_ERROR, "Kevacoin block hash does not match cryptnote hash"); + } + + // TODO: fix the return message. + bool fBlockPresent = false; + { + LOCK(cs_main); + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) { + CBlockIndex *pindex = mi->second; + if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) { + return "duplicate"; + } + if (pindex->nStatus & BLOCK_FAILED_MASK) { + return "duplicate-invalid"; + } + // Otherwise, we might only have the header - process the block before returning + fBlockPresent = true; + } + } + + { + LOCK(cs_main); + BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); + if (mi != mapBlockIndex.end()) { + UpdateUncommittedBlockStructures(block, mi->second, Params().GetConsensus()); + } + } + + submitblock_StateCatcher sc(block.GetHash()); + RegisterValidationInterface(&sc); + bool fAccepted = ProcessNewBlock(Params(), blockptr, true, nullptr); + UnregisterValidationInterface(&sc); + if (fBlockPresent) { + if (fAccepted && !sc.found) { + return "duplicate-inconclusive"; + } + return "duplicate"; + } + if (!sc.found) { + return "inconclusive"; + } + return BIP22ValidationResult(sc.state); +} UniValue estimatefee(const JSONRPCRequest& request) {