diff --git a/src/Makefile.am b/src/Makefile.am index e8d22313dc..b7976f5d66 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -127,6 +127,7 @@ BITCOIN_CORE_H = \ rpc/server.h \ rpc/register.h \ scheduler.h \ + script/generic.hpp \ script/sigcache.h \ script/sign.h \ script/standard.h \ diff --git a/src/chain.cpp b/src/chain.cpp index a5b369c4fc..f2dbb0b302 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -119,17 +119,7 @@ void CBlockIndex::BuildSkip() arith_uint256 GetBlockProof(const CBlockIndex& block) { - arith_uint256 bnTarget; - bool fNegative; - bool fOverflow; - bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - if (fNegative || fOverflow || bnTarget == 0) - return 0; - // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 - // as it's too large for a arith_uint256. However, as 2**256 is at least as large - // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, - // or ~bnTarget / (nTarget+1) + 1. - return (~bnTarget / (bnTarget + 1)) + 1; + return 1; } int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params) diff --git a/src/chain.h b/src/chain.h index acb29b667b..dea2936012 100644 --- a/src/chain.h +++ b/src/chain.h @@ -196,8 +196,7 @@ public: int nVersion; uint256 hashMerkleRoot; unsigned int nTime; - unsigned int nBits; - unsigned int nNonce; + CProof proof; //! (memory only) Sequential id assigned to distinguish order in which blocks are received. int32_t nSequenceId; @@ -224,8 +223,7 @@ public: nVersion = 0; hashMerkleRoot = uint256(); nTime = 0; - nBits = 0; - nNonce = 0; + proof.SetNull(); } CBlockIndex() @@ -240,8 +238,7 @@ public: nVersion = block.nVersion; hashMerkleRoot = block.hashMerkleRoot; nTime = block.nTime; - nBits = block.nBits; - nNonce = block.nNonce; + proof = block.proof; } CDiskBlockPos GetBlockPos() const { @@ -270,8 +267,7 @@ public: block.hashPrevBlock = pprev->GetBlockHash(); block.hashMerkleRoot = hashMerkleRoot; block.nTime = nTime; - block.nBits = nBits; - block.nNonce = nNonce; + block.proof = proof; return block; } @@ -386,8 +382,7 @@ public: READWRITE(hashPrev); READWRITE(hashMerkleRoot); READWRITE(nTime); - READWRITE(nBits); - READWRITE(nNonce); + READWRITE(proof); } uint256 GetBlockHash() const @@ -397,8 +392,7 @@ public: block.hashPrevBlock = hashPrev; block.hashMerkleRoot = hashMerkleRoot; block.nTime = nTime; - block.nBits = nBits; - block.nNonce = nNonce; + block.proof = proof; return block.GetHash(); } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index f1f7d2b992..28229fecb1 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -28,8 +28,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi CBlock genesis; genesis.nTime = nTime; - genesis.nBits = nBits; - genesis.nNonce = nNonce; + genesis.proof = CProof(nBits, nNonce); genesis.nVersion = nVersion; genesis.vtx.push_back(MakeTransactionRef(std::move(txNew))); genesis.hashPrevBlock.SetNull(); diff --git a/src/miner.cpp b/src/miner.cpp index a12dcec2ce..cc9c083a55 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -67,7 +67,7 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam // Updating time can change work required on testnet: if (consensusParams.fPowAllowMinDifficultyBlocks) - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams); + ResetChallenge(*pblock, *pindexPrev, consensusParams); return nNewTime - nOldTime; } @@ -198,8 +198,8 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); - pblock->nNonce = 0; + ResetChallenge(*pblock, *pindexPrev, chainparams.GetConsensus()); + ResetProof(*pblock); pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]); CValidationState state; diff --git a/src/pow.cpp b/src/pow.cpp index e57fd866f8..2300d06cb6 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -7,74 +7,37 @@ #include "arith_uint256.h" #include "chain.h" +#include "chainparams.h" +#include "core_io.h" +#include "hash.h" +#include "keystore.h" #include "primitives/block.h" +#include "script/generic.hpp" +#include "script/standard.h" #include "uint256.h" -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) +#ifdef ENABLE_WALLET +#include "wallet/wallet.h" +#endif + +CScript CombineBlockSignatures(const CBlockHeader& header, const CScript& scriptSig1, const CScript& scriptSig2) { - unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact(); - - // Genesis block - if (pindexLast == NULL) - return nProofOfWorkLimit; - - // Only change once per difficulty adjustment interval - if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0) - { - if (params.fPowAllowMinDifficultyBlocks) - { - // Special difficulty rule for testnet: - // If the new block's timestamp is more than 2* 10 minutes - // then allow mining of a min-difficulty block. - if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2) - return nProofOfWorkLimit; - else - { - // Return the last non-special-min-difficulty-rules-block - const CBlockIndex* pindex = pindexLast; - while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit) - pindex = pindex->pprev; - return pindex->nBits; - } - } - return pindexLast->nBits; - } - - // Go back by what we want to be 14 days worth of blocks - int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1); - assert(nHeightFirst >= 0); - const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst); - assert(pindexFirst); - - return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params); + SignatureData sig1(scriptSig1); + SignatureData sig2(scriptSig2); + return GenericCombineSignatures(header.proof.challenge, header, sig1, sig2).scriptSig; } -unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params) +bool CheckChallenge(const CBlockHeader& block, const CBlockIndex& indexLast, const Consensus::Params& params) { - if (params.fPowNoRetargeting) - return pindexLast->nBits; - - // Limit adjustment step - int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime; - if (nActualTimespan < params.nPowTargetTimespan/4) - nActualTimespan = params.nPowTargetTimespan/4; - if (nActualTimespan > params.nPowTargetTimespan*4) - nActualTimespan = params.nPowTargetTimespan*4; - - // Retarget - const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); - arith_uint256 bnNew; - bnNew.SetCompact(pindexLast->nBits); - bnNew *= nActualTimespan; - bnNew /= params.nPowTargetTimespan; - - if (bnNew > bnPowLimit) - bnNew = bnPowLimit; - - return bnNew.GetCompact(); + return block.proof.challenge == indexLast.proof.challenge; } -bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) +void ResetChallenge(CBlockHeader& block, const CBlockIndex& indexLast, const Consensus::Params& params) +{ + block.proof.challenge = indexLast.proof.challenge; +} + +bool CheckBitcoinProof(uint256 hash, unsigned int nBits, const Consensus::Params& params) { bool fNegative; bool fOverflow; @@ -92,3 +55,50 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& return true; } + +bool CheckProof(const CBlockHeader& block, const Consensus::Params& params) +{ + if (block.GetHash() == params.hashGenesisBlock) + return true; + return GenericVerifyScript(block.proof.solution, block.proof.challenge, SCRIPT_VERIFY_P2SH, block); +} + +bool MaybeGenerateProof(CBlockHeader *pblock, CWallet *pwallet) +{ +#ifdef ENABLE_WALLET + SignatureData solution(pblock->proof.solution); + bool res = GenericSignScript(*pwallet, *pblock, pblock->proof.challenge, solution); + pblock->proof.solution = solution.scriptSig; + return res; +#endif + return false; +} + +void ResetProof(CBlockHeader& block) +{ + block.proof.solution.clear(); +} + +double GetChallengeDifficulty(const CBlockIndex* blockindex) +{ + return 1; +} + +std::string GetChallengeStr(const CBlockIndex& block) +{ + return ScriptToAsmStr(block.proof.challenge); +} + +std::string GetChallengeStrHex(const CBlockIndex& block) +{ + return ScriptToAsmStr(block.proof.challenge); +} + +uint32_t GetNonce(const CBlockHeader& block) +{ + return 1; +} + +void SetNonce(CBlockHeader& block, uint32_t nNonce) +{ +} diff --git a/src/pow.h b/src/pow.h index e203f492a1..d8c1f484ec 100644 --- a/src/pow.h +++ b/src/pow.h @@ -9,15 +9,31 @@ #include "consensus/params.h" #include +#include class CBlockHeader; class CBlockIndex; +class CProof; +class CScript; +class CWallet; class uint256; -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&); -unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params&); /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ -bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); +bool CheckProof(const CBlockHeader& block, const Consensus::Params&); +/** Scans nonces looking for a hash with at least some zero bits */ +bool MaybeGenerateProof(CBlockHeader* pblock, CWallet* pwallet); +void ResetProof(CBlockHeader& block); +bool CheckChallenge(const CBlockHeader& block, const CBlockIndex& indexLast, const Consensus::Params&); +void ResetChallenge(CBlockHeader& block, const CBlockIndex& indexLast, const Consensus::Params&); + +CScript CombineBlockSignatures(const CBlockHeader& header, const CScript& scriptSig1, const CScript& scriptSig2); + +/** Avoid using these functions when possible */ +double GetChallengeDifficulty(const CBlockIndex* blockindex); +std::string GetChallengeStr(const CBlockIndex& block); +std::string GetChallengeStrHex(const CBlockIndex& block); +uint32_t GetNonce(const CBlockHeader& block); +void SetNonce(CBlockHeader& block, uint32_t nNonce); #endif // BITCOIN_POW_H diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 9a979094cc..8755a0bbea 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -9,6 +9,13 @@ #include "tinyformat.h" #include "utilstrencodings.h" #include "crypto/common.h" +#include "core_io.h" + +std::string CProof::ToString() const +{ + return strprintf("CProof(challenge=%s, solution=%s)", + ScriptToAsmStr(challenge), ScriptToAsmStr(solution)); +} uint256 CBlockHeader::GetHash() const { @@ -18,12 +25,13 @@ uint256 CBlockHeader::GetHash() const std::string CBlock::ToString() const { std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, proof=%u, vtx=%u)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), hashMerkleRoot.ToString(), - nTime, nBits, nNonce, + nTime, + proof.ToString(), vtx.size()); for (unsigned int i = 0; i < vtx.size(); i++) { diff --git a/src/primitives/block.h b/src/primitives/block.h index 4c6eb20ad5..abb22cbe56 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -7,9 +7,46 @@ #define BITCOIN_PRIMITIVES_BLOCK_H #include "primitives/transaction.h" +#include "script/script.h" #include "serialize.h" #include "uint256.h" +class CProof +{ +public: + CScript challenge; + CScript solution; + + CProof() + { + SetNull(); + } + CProof(CScript challengeIn, CScript solutionIn) : challenge(challengeIn), solution(solutionIn) {} + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) + { + READWRITE(*(CScriptBase*)(&challenge)); + if (!(s.GetType() & SER_GETHASH)) + READWRITE(*(CScriptBase*)(&solution)); + } + + void SetNull() + { + challenge.clear(); + solution.clear(); + } + + bool IsNull() const + { + return challenge.empty(); + } + + std::string ToString() const; +}; + /** Nodes collect new transactions into a block, hash them into a hash tree, * and scan through nonce values to make the block's hash satisfy proof-of-work * requirements. When they solve the proof-of-work, they broadcast the block @@ -25,8 +62,7 @@ public: uint256 hashPrevBlock; uint256 hashMerkleRoot; uint32_t nTime; - uint32_t nBits; - uint32_t nNonce; + CProof proof; CBlockHeader() { @@ -41,8 +77,7 @@ public: READWRITE(hashPrevBlock); READWRITE(hashMerkleRoot); READWRITE(nTime); - READWRITE(nBits); - READWRITE(nNonce); + READWRITE(proof); } void SetNull() @@ -51,13 +86,12 @@ public: hashPrevBlock.SetNull(); hashMerkleRoot.SetNull(); nTime = 0; - nBits = 0; - nNonce = 0; + proof.SetNull(); } bool IsNull() const { - return (nBits == 0); + return proof.IsNull(); } uint256 GetHash() const; @@ -111,8 +145,7 @@ public: block.hashPrevBlock = hashPrevBlock; block.hashMerkleRoot = hashMerkleRoot; block.nTime = nTime; - block.nBits = nBits; - block.nNonce = nNonce; + block.proof = proof; return block; } diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 7b69c81ff9..504fc4aceb 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -13,6 +13,7 @@ #include "policy/policy.h" #include "primitives/transaction.h" #include "rpc/server.h" +#include "pow.h" #include "streams.h" #include "sync.h" #include "txmempool.h" @@ -54,24 +55,7 @@ double GetDifficulty(const CBlockIndex* blockindex) else blockindex = chainActive.Tip(); } - - int nShift = (blockindex->nBits >> 24) & 0xff; - - double dDiff = - (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff); - - while (nShift < 29) - { - dDiff *= 256.0; - nShift++; - } - while (nShift > 29) - { - dDiff /= 256.0; - nShift--; - } - - return dDiff; + return GetChallengeDifficulty(blockindex); } UniValue blockheaderToJSON(const CBlockIndex* blockindex) @@ -89,8 +73,8 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex())); result.push_back(Pair("time", (int64_t)blockindex->nTime)); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); - result.push_back(Pair("nonce", (uint64_t)blockindex->nNonce)); - result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); + result.push_back(Pair("nonce", (uint64_t)GetNonce(blockindex->GetBlockHeader()))); + result.push_back(Pair("bits", GetChallengeStr(blockindex->GetBlockHeader()))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); @@ -133,8 +117,8 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); - result.push_back(Pair("nonce", (uint64_t)block.nNonce)); - result.push_back(Pair("bits", strprintf("%08x", block.nBits))); + result.push_back(Pair("nonce", (uint64_t)GetNonce(block))); + result.push_back(Pair("bits", GetChallengeStr(block))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 33e234a95e..9898bb0801 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -96,123 +96,9 @@ UniValue getnetworkhashps(const JSONRPCRequest& request) return GetNetworkHashPS(request.params.size() > 0 ? request.params[0].get_int() : 120, request.params.size() > 1 ? request.params[1].get_int() : -1); } -UniValue generateBlocks(boost::shared_ptr coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript) -{ - static const int nInnerLoopCount = 0x10000; - int nHeightStart = 0; - int nHeightEnd = 0; - int nHeight = 0; - - { // Don't keep cs_main locked - LOCK(cs_main); - nHeightStart = chainActive.Height(); - nHeight = nHeightStart; - nHeightEnd = nHeightStart+nGenerate; - } - unsigned int nExtraNonce = 0; - UniValue blockHashes(UniValue::VARR); - while (nHeight < nHeightEnd) - { - std::unique_ptr pblocktemplate(BlockAssembler(Params()).CreateNewBlock(coinbaseScript->reserveScript)); - if (!pblocktemplate.get()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); - CBlock *pblock = &pblocktemplate->block; - { - LOCK(cs_main); - IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); - } - while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount && !CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { - ++pblock->nNonce; - --nMaxTries; - } - if (nMaxTries == 0) { - break; - } - if (pblock->nNonce == nInnerLoopCount) { - continue; - } - std::shared_ptr shared_pblock = std::make_shared(*pblock); - if (!ProcessNewBlock(Params(), shared_pblock, true, NULL)) - throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); - ++nHeight; - blockHashes.push_back(pblock->GetHash().GetHex()); - - //mark script as important because it was used at least for one coinbase output if the script came from the wallet - if (keepScript) - { - coinbaseScript->KeepScript(); - } - } - return blockHashes; -} - UniValue generate(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( - "generate nblocks ( maxtries )\n" - "\nMine up to nblocks blocks immediately (before the RPC call returns)\n" - "\nArguments:\n" - "1. nblocks (numeric, required) How many blocks are generated immediately.\n" - "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n" - "\nResult:\n" - "[ blockhashes ] (array) hashes of blocks generated\n" - "\nExamples:\n" - "\nGenerate 11 blocks\n" - + HelpExampleCli("generate", "11") - ); - - int nGenerate = request.params[0].get_int(); - uint64_t nMaxTries = 1000000; - if (request.params.size() > 1) { - nMaxTries = request.params[1].get_int(); - } - - boost::shared_ptr coinbaseScript; - GetMainSignals().ScriptForMining(coinbaseScript); - - // If the keypool is exhausted, no script is returned at all. Catch this. - if (!coinbaseScript) - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - - //throw an error if no script was provided - if (coinbaseScript->reserveScript.empty()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); - - return generateBlocks(coinbaseScript, nGenerate, nMaxTries, true); -} - -UniValue generatetoaddress(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) - throw runtime_error( - "generatetoaddress nblocks address (maxtries)\n" - "\nMine blocks immediately to a specified address (before the RPC call returns)\n" - "\nArguments:\n" - "1. nblocks (numeric, required) How many blocks are generated immediately.\n" - "2. address (string, required) The address to send the newly generated bitcoin to.\n" - "3. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n" - "\nResult:\n" - "[ blockhashes ] (array) hashes of blocks generated\n" - "\nExamples:\n" - "\nGenerate 11 blocks to myaddress\n" - + HelpExampleCli("generatetoaddress", "11 \"myaddress\"") - ); - - int nGenerate = request.params[0].get_int(); - uint64_t nMaxTries = 1000000; - if (request.params.size() > 2) { - nMaxTries = request.params[2].get_int(); - } - - CBitcoinAddress address(request.params[1].get_str()); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address"); - - boost::shared_ptr coinbaseScript(new CReserveScript()); - coinbaseScript->reserveScript = GetScriptForDestination(address.Get()); - - return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false); + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method cannot be used in private chain mode"); } UniValue getmininginfo(const JSONRPCRequest& request) @@ -559,7 +445,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) // Update nTime UpdateTime(pblock, consensusParams, pindexPrev); - pblock->nNonce = 0; + ResetProof(*pblock); // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration const bool fPreSegWit = (THRESHOLD_ACTIVE != VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache)); @@ -607,8 +493,6 @@ UniValue getblocktemplate(const JSONRPCRequest& request) 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"); @@ -677,7 +561,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) 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("target", GetChallengeStrHex(*pblock))); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); result.push_back(Pair("mutable", aMutable)); result.push_back(Pair("noncerange", "00000000ffffffff")); @@ -694,7 +578,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) 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("bits", GetChallengeStr(*pblock))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); if (!pblocktemplate->vchCoinbaseCommitment.empty() && fSupportsSegwit) { @@ -935,7 +819,6 @@ static const CRPCCommand commands[] = { "mining", "submitblock", &submitblock, true, {"hexdata","parameters"} }, { "generating", "generate", &generate, true, {"nblocks","maxtries"} }, - { "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} }, { "util", "estimatefee", &estimatefee, true, {"nblocks"} }, { "util", "estimatepriority", &estimatepriority, true, {"nblocks"} }, diff --git a/src/script/generic.hpp b/src/script/generic.hpp new file mode 100644 index 0000000000..533b7b55ca --- /dev/null +++ b/src/script/generic.hpp @@ -0,0 +1,64 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef H_BITCOIN_SCRIPT_GENERIC +#define H_BITCOIN_SCRIPT_GENERIC + +#include "hash.h" +#include "script/interpreter.h" +#include "script/sign.h" + +class SimpleSignatureChecker : public BaseSignatureChecker +{ +public: + uint256 hash; + + SimpleSignatureChecker(const uint256& hashIn) : hash(hashIn) {}; + bool CheckSig(const std::vector& vchSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const + { + CPubKey pubkey(vchPubKey); + if (!pubkey.IsValid()) + return false; + if (vchSig.empty()) + return false; + return pubkey.Verify(hash, vchSig); + } +}; + +class SimpleSignatureCreator : public BaseSignatureCreator +{ + SimpleSignatureChecker checker; + +public: + SimpleSignatureCreator(const CKeyStore* keystoreIn, const uint256& hashIn) : BaseSignatureCreator(keystoreIn), checker(hashIn) {}; + const BaseSignatureChecker& Checker() const { return checker; } + bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const + { + CKey key; + if (!keystore->GetKey(keyid, key)) + return false; + return key.Sign(checker.hash, vchSig); + } +}; + +template +bool GenericVerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const T& data) +{ + return VerifyScript(scriptSig, scriptPubKey, NULL, flags, SimpleSignatureChecker(SerializeHash(data))); +} + +template +bool GenericSignScript(const CKeyStore& keystore, const T& data, const CScript& fromPubKey, SignatureData& scriptSig) +{ + return ProduceSignature(SimpleSignatureCreator(&keystore, SerializeHash(data)), fromPubKey, scriptSig); +} + +template +SignatureData GenericCombineSignatures(const CScript& scriptPubKey, const T& data, const SignatureData& scriptSig1, const SignatureData& scriptSig2) +{ + return CombineSignatures(scriptPubKey, SimpleSignatureChecker(SerializeHash(data)), scriptSig1, scriptSig2); +} + +#endif // H_BITCOIN_SCRIPT_GENERIC diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index 311ac024f3..52d907b6b2 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -10,6 +10,7 @@ #include "test/test_bitcoin.h" #include +/* TODO Re-add once Bitcoin blocks re-added std::vector> extra_txn; @@ -338,3 +339,5 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) { } BOOST_AUTO_TEST_SUITE_END() + +*/ diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 27bc92d670..faf156da57 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -22,7 +22,8 @@ #include BOOST_FIXTURE_TEST_SUITE(bloom_tests, BasicTestingSetup) - +// XXX: Re-enable after re-adding bitcoin +#if 0 BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize) { CBloomFilter filter(3, 0.01, 0, BLOOM_UPDATE_ALL); @@ -540,5 +541,5 @@ BOOST_AUTO_TEST_CASE(rolling_bloom) BOOST_CHECK(rb2.contains(data[i])); } } - +#endif BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index e1706b2f3c..23e6612063 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -226,12 +226,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) if (txFirst.size() < 4) txFirst.push_back(pblock->vtx[0]); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); - pblock->nNonce = blockinfo[i].nonce; - if (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, chainparams.GetConsensus())) - { - printf("WARNING: Skipping miner tests due to changed genesis block\n"); - return; - } std::shared_ptr shared_pblock = std::make_shared(*pblock); BOOST_CHECK(ProcessNewBlock(chainparams, shared_pblock, true, NULL)); pblock->hashPrevBlock = pblock->GetHash(); diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index 3b79f8000d..5d816a3084 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -13,6 +13,9 @@ BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) +#if 0 +// TODO: Re-enable when we re-add bitcoin stuff + /* Test calculation of next difficulty target with no constraints applying */ BOOST_AUTO_TEST_CASE(get_next_work) { @@ -21,7 +24,7 @@ BOOST_AUTO_TEST_CASE(get_next_work) CBlockIndex pindexLast; pindexLast.nHeight = 32255; pindexLast.nTime = 1262152739; // Block #32255 - pindexLast.nBits = 0x1d00ffff; + pindexLast.proof.nBits = 0x1d00ffff; BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1d00d86a); } @@ -33,7 +36,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit) CBlockIndex pindexLast; pindexLast.nHeight = 2015; pindexLast.nTime = 1233061996; // Block #2015 - pindexLast.nBits = 0x1d00ffff; + pindexLast.proof.nBits = 0x1d00ffff; BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1d00ffff); } @@ -45,7 +48,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual) CBlockIndex pindexLast; pindexLast.nHeight = 68543; pindexLast.nTime = 1279297671; // Block #68543 - pindexLast.nBits = 0x1c05a3f4; + pindexLast.proof.nBits = 0x1c05a3f4; BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1c0168fd); } @@ -57,7 +60,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) CBlockIndex pindexLast; pindexLast.nHeight = 46367; pindexLast.nTime = 1269211443; // Block #46367 - pindexLast.nBits = 0x1c387f6f; + pindexLast.proof.nBits = 0x1c387f6f; BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1d00e1fd); } @@ -69,7 +72,7 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) blocks[i].pprev = i ? &blocks[i - 1] : NULL; blocks[i].nHeight = i; blocks[i].nTime = 1269211443 + i * chainParams->GetConsensus().nPowTargetSpacing; - blocks[i].nBits = 0x207fffff; /* target 0x7fffff000... */ + blocks[i].proof.nBits = 0x207fffff; /* target 0x7fffff000... */ blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); } @@ -82,5 +85,6 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) BOOST_CHECK_EQUAL(tdiff, p1->GetBlockTime() - p2->GetBlockTime()); } } +#endif BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 399bdbc811..ee2bde756c 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -319,7 +319,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) adr = find_value(o1, "address"); BOOST_CHECK_EQUAL(adr.get_str(), "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128"); } - +/* BOOST_AUTO_TEST_CASE(rpc_convert_values_generatetoaddress) { UniValue result; @@ -342,5 +342,5 @@ BOOST_AUTO_TEST_CASE(rpc_convert_values_generatetoaddress) BOOST_CHECK_EQUAL(result[1].get_str(), "mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU"); BOOST_CHECK_EQUAL(result[2].get_int(), 9); } - +*/ BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 4785415e3c..379a9703d5 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -127,7 +127,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector& unsigned int extraNonce = 0; IncrementExtraNonce(&block, chainActive.Tip(), extraNonce); - while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; + assert(CheckProof(block, chainparams.GetConsensus())); std::shared_ptr shared_pblock = std::make_shared(block); ProcessNewBlock(chainparams, shared_pblock, true, NULL); diff --git a/src/txdb.cpp b/src/txdb.cpp index 4358f7e474..f74aa481b1 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -192,13 +192,12 @@ bool CBlockTreeDB::LoadBlockIndexGuts(boost::functionnVersion = diskindex.nVersion; pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->nTime = diskindex.nTime; - pindexNew->nBits = diskindex.nBits; - pindexNew->nNonce = diskindex.nNonce; + pindexNew->proof = diskindex.proof; pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; - if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus()) && pindexNew->GetBlockHash() != Params().GetConsensus().hashGenesisBlock) - return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); + if (!CheckProof(pindexNew->GetBlockHeader(), Params().GetConsensus())) + return error("LoadBlockIndex(): CheckProof failed: %s", pindexNew->ToString()); pcursor->Next(); } else { diff --git a/src/validation.cpp b/src/validation.cpp index 341ea7bc23..dfb57e1b1b 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1147,7 +1147,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus: } // Check the header - if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams) && + if (!CheckProof(block, consensusParams) && block.GetHash() != consensusParams.hashGenesisBlock) return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); @@ -2830,8 +2830,14 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW) { // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) - return state.DoS(50, false, REJECT_INVALID, "high-hash", false, "proof of work failed"); + if (fCheckPOW && !CheckProof(block, Params().GetConsensus())) + return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), + REJECT_INVALID, "high-hash"); + + // Check timestamp + if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) + return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"), + REJECT_INVALID, "time-too-new"); return true; } @@ -2979,7 +2985,7 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta { const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; // Check proof of work - if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) + if (!CheckChallenge(block, *pindexPrev, consensusParams)) return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work"); // Check timestamp against prev