diff --git a/src/Makefile.am b/src/Makefile.am index acdb10fff..207cade95 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,6 +22,7 @@ BITCOIN_INCLUDES=-I$(builddir) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFL BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS) +BITCOIN_INCLUDES += -I$(srcdir)/cn_utils -I$(srcdir)/cn_utils/contrib -I$(srcdir)/cn_utils/contrib/epee/include LIBBITCOIN_SERVER=libbitcoin_server.a LIBBITCOIN_COMMON=libbitcoin_common.a diff --git a/src/cn_utils/cnutils.cpp b/src/cn_utils/cnutils.cpp index 0a515fc32..4df7cba4e 100644 --- a/src/cn_utils/cnutils.cpp +++ b/src/cn_utils/cnutils.cpp @@ -9,6 +9,7 @@ #include "crypto/hash.h" #include "common/base58.h" #include "serialization/binary_utils.h" +#include "cnutils.h" uint32_t convert_blob(const char *blob, size_t len, char *out) { diff --git a/src/cn_utils/cnutils.h b/src/cn_utils/cnutils.h new file mode 100644 index 000000000..91fa1a2bb --- /dev/null +++ b/src/cn_utils/cnutils.h @@ -0,0 +1,4 @@ +#pragma once + +uint32_t convert_blob(const char *blob, size_t len, char *out); +bool validate_address(const char *addr, size_t len); \ No newline at end of file diff --git a/src/cn_utils/cryptonote_core/cryptonote_basic.h b/src/cn_utils/cryptonote_core/cryptonote_basic.h index 39c12fff6..bd9119c53 100644 --- a/src/cn_utils/cryptonote_core/cryptonote_basic.h +++ b/src/cn_utils/cryptonote_core/cryptonote_basic.h @@ -17,7 +17,7 @@ #include "serialization/json_archive.h" #include "serialization/debug_archive.h" #include "serialization/crypto.h" -#include "serialization/keyvalue_serialization.h" // eepe named serialization +#include "epee/include/serialization/keyvalue_serialization.h" // eepe named serialization #include "string_tools.h" #include "cryptonote_config.h" #include "crypto/crypto.h" @@ -562,12 +562,12 @@ namespace cryptonote struct integrated_address { account_public_address adr; crypto::hash8 payment_id; - + BEGIN_SERIALIZE_OBJECT() FIELD(adr) FIELD(payment_id) END_SERIALIZE() - + BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(adr) KV_SERIALIZE(payment_id) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 4a6d597dc..e1d418f39 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -29,6 +29,10 @@ #include #include +#include +#include +#include + unsigned int ParseConfirmTarget(const UniValue& value) { int target = value.get_int(); @@ -291,6 +295,7 @@ std::string gbt_vb_name(const Consensus::DeploymentPos pos) { return s; } +#if 0 UniValue getblocktemplate(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 1) @@ -680,6 +685,235 @@ UniValue getblocktemplate(const JSONRPCRequest& request) return result; } +#endif + +UniValue getblocktemplate(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() > 1) + 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" + "It returns data needed to construct a block to work on.\n" + "For full specification, see BIPs 22, 23, 9, and 145:\n" + " https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n" + " https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki\n" + " https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n" + " https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n" + + "\nArguments:\n" + "1. template_request (json object, optional) A json object in the following spec\n" + " {\n" + " \"mode\":\"template\" (string, optional) This must be set to \"template\", \"proposal\" (see BIP 23), or omitted\n" + " \"capabilities\":[ (array, optional) A list of strings\n" + " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n" + " ,...\n" + " ],\n" + " \"rules\":[ (array, optional) A list of strings\n" + " \"support\" (string) client side supported softfork deployment\n" + " ,...\n" + " ]\n" + " }\n" + "\n" + + "\nResult:\n" + "{\n" + " \"version\" : n, (numeric) The preferred block version\n" + " \"rules\" : [ \"rulename\", ... ], (array of strings) specific block rules that are to be enforced\n" + " \"vbavailable\" : { (json object) set of pending, supported versionbit (BIP 9) softfork deployments\n" + " \"rulename\" : bitnumber (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule\n" + " ,...\n" + " },\n" + " \"vbrequired\" : n, (numeric) bit mask of versionbits the server requires set in submissions\n" + " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n" + " \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n" + " {\n" + " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n" + " \"txid\" : \"xxxx\", (string) transaction id encoded in little-endian hexadecimal\n" + " \"hash\" : \"xxxx\", (string) hash encoded in little-endian hexadecimal (including witness data)\n" + " \"depends\" : [ (array) array of numbers \n" + " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n" + " ,...\n" + " ],\n" + " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n" + " \"sigops\" : n, (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero\n" + " \"weight\" : n, (numeric) total transaction weight, as counted for purposes of block limits\n" + " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n" + " }\n" + " ,...\n" + " ],\n" + " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n" + " \"flags\" : \"xx\" (string) key name is to be ignored, and value included in scriptSig\n" + " },\n" + " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)\n" + " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n" + " \"target\" : \"xxxx\", (string) The hash target\n" + " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"mutable\" : [ (array of string) list of ways the block template may be changed \n" + " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n" + " ,...\n" + " ],\n" + " \"noncerange\" : \"00000000ffffffff\",(string) A range of valid nonces\n" + " \"sigoplimit\" : n, (numeric) limit of sigops in blocks\n" + " \"sizelimit\" : n, (numeric) limit of block size\n" + " \"weightlimit\" : n, (numeric) limit of block weight\n" + " \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n" + " \"bits\" : \"xxxxxxxx\", (string) compressed target of next block\n" + " \"height\" : n (numeric) The height of the next block\n" + "}\n" + + "\nExamples:\n" + + HelpExampleCli("getblocktemplate", "") + + HelpExampleRpc("getblocktemplate", "") + ); + + LOCK(cs_main); + + std::string strMode = "template"; +#if 0 + if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) + throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Kevacoin is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Kevacoin is downloading blocks..."); +#endif + static unsigned int nTransactionsUpdatedLast; + bool fSupportsSegwit = true; + + // Update block + static CBlockIndex* pindexPrev; + static int64_t nStart; + static std::unique_ptr pblocktemplate; + if (pindexPrev != chainActive.Tip() || + (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) + { + // Clear pindexPrev so future calls make a new block, despite any failures from here on + pindexPrev = nullptr; + + // Store the pindexBest used before CreateNewBlock, to avoid races + nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); + CBlockIndex* pindexPrevNew = chainActive.Tip(); + nStart = GetTime(); + + // Create new block + CScript scriptDummy = CScript() << OP_TRUE; + pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy, fSupportsSegwit); + if (!pblocktemplate) + throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); + + // Need to update only after we know CreateNewBlock succeeded + pindexPrev = pindexPrevNew; + } + CBlock* pblock = &pblocktemplate->block; // pointer for convenience + const Consensus::Params& consensusParams = Params().GetConsensus(); + + // Update nTime + UpdateTime(pblock, consensusParams, pindexPrev); + pblock->nNonce = 0; + + UniValue transactions(UniValue::VARR); + std::map setTxIndex; + int i = 0; + for (const auto& it : pblock->vtx) { + const CTransaction& tx = *it; + uint256 txHash = tx.GetHash(); + setTxIndex[txHash] = i++; + + if (tx.IsCoinBase()) + continue; + + UniValue entry(UniValue::VOBJ); + + entry.push_back(Pair("data", EncodeHexTx(tx))); + entry.push_back(Pair("txid", txHash.GetHex())); + entry.push_back(Pair("hash", tx.GetWitnessHash().GetHex())); + + UniValue deps(UniValue::VARR); + for (const CTxIn &in : tx.vin) + { + if (setTxIndex.count(in.prevout.hash)) + deps.push_back(setTxIndex[in.prevout.hash]); + } + entry.push_back(Pair("depends", deps)); + + int index_in_template = i - 1; + entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); + int64_t nTxSigOps = pblocktemplate->vTxSigOpsCost[index_in_template]; + entry.push_back(Pair("sigops", nTxSigOps)); + entry.push_back(Pair("weight", GetTransactionWeight(tx))); + + transactions.push_back(entry); + } + + UniValue aux(UniValue::VOBJ); + aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); + + arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); + + UniValue aMutable(UniValue::VARR); + aMutable.push_back("time"); + aMutable.push_back("transactions"); + aMutable.push_back("prevblock"); + + UniValue result(UniValue::VOBJ); + + UniValue aRules(UniValue::VARR); + UniValue vbavailable(UniValue::VOBJ); + for (int j = 0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) { + Consensus::DeploymentPos pos = Consensus::DeploymentPos(j); + ThresholdState state = VersionBitsState(pindexPrev, consensusParams, pos, versionbitscache); + switch (state) { + case THRESHOLD_DEFINED: + case THRESHOLD_FAILED: + // Not exposed to GBT at all + break; + case THRESHOLD_LOCKED_IN: + // Ensure bit is set in block version + pblock->nVersion |= VersionBitsMask(consensusParams, pos); + // FALL THROUGH to get vbavailable set... + case THRESHOLD_STARTED: + { + const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos]; + vbavailable.push_back(Pair(gbt_vb_name(pos), consensusParams.vDeployments[pos].bit)); + break; + } + case THRESHOLD_ACTIVE: + { + // Add to rules only + const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos]; + aRules.push_back(gbt_vb_name(pos)); + break; + } + } + } + result.push_back(Pair("version", pblock->nVersion)); + result.push_back(Pair("rules", aRules)); + result.push_back(Pair("vbavailable", vbavailable)); + result.push_back(Pair("vbrequired", int(0))); + + result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); + result.push_back(Pair("transactions", transactions)); + result.push_back(Pair("coinbaseaux", aux)); + result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue)); + result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); + result.push_back(Pair("target", hashTarget.GetHex())); + result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); + result.push_back(Pair("mutable", aMutable)); + result.push_back(Pair("noncerange", "00000000ffffffff")); + int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST; + int64_t nSizeLimit = MAX_BLOCK_SERIALIZED_SIZE; + result.push_back(Pair("sigoplimit", nSigOpLimit)); + result.push_back(Pair("sizelimit", nSizeLimit)); + result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT)); + result.push_back(Pair("curtime", pblock->GetBlockTime())); + result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); + result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); + + if (!pblocktemplate->vchCoinbaseCommitment.empty() && fSupportsSegwit) { + result.push_back(Pair("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end()))); + } + + return result; +} class submitblock_StateCatcher : public CValidationInterface {