Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (blockindex->IsInMainChain()) confirmations = nBestHeight - blockindex->nHeight + 1; result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint))); result.push_back(Pair("time", (int64_t)block.GetBlockTime())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("blocktrust", leftTrim(blockindex->GetBlockTrust().GetHex(), '0'))); result.push_back(Pair("chaintrust", leftTrim(blockindex->nChainTrust.GetHex(), '0'))); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); if (blockindex->pnext) result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex())); result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": ""))); result.push_back(Pair("proofhash", blockindex->hashProof.GetHex())); result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit())); result.push_back(Pair("modifier", strprintf("%016x", blockindex->nStakeModifier))); result.push_back(Pair("modifierv2", blockindex->bnStakeModifierV2.GetHex())); Array txinfo; BOOST_FOREACH (const CTransaction& tx, block.vtx) { if (fPrintTransactionDetail) { Object entry; entry.push_back(Pair("txid", tx.GetHash().GetHex())); TxToJSON(tx, 0, entry); txinfo.push_back(entry); } else txinfo.push_back(tx.GetHash().GetHex()); } result.push_back(Pair("tx", txinfo)); if (block.IsProofOfStake()) result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end()))); return result; }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); CMerkleTx txGen(block.vtx[0]); txGen.SetMerkleBranch(&block); result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); if(blockindex->nHeight==1){ result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint-6999900*COIN))); } else{ result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint))); } result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime())); result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce)); result.push_back(Pair("bits", HexBits(block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); if (blockindex->pnext) result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex())); result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": ""))); result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex())); result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit())); result.push_back(Pair("modifier", strprintf("%016"PRI64x, blockindex->nStakeModifier))); result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum))); Array txinfo; BOOST_FOREACH (const CTransaction& tx, block.vtx) { if (fPrintTransactionDetail) { Object entry; entry.push_back(Pair("txid", tx.GetHash().GetHex())); TxToJSON(tx, 0, entry); txinfo.push_back(entry); } else txinfo.push_back(tx.GetHash().GetHex()); } result.push_back(Pair("tx", txinfo)); result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end()))); return result; }
void MineGenesis(CBlock genesis){ // This will figure out a valid hash and Nonce if you're creating a different genesis block: uint256 hashTarget = CBigNum().SetCompact(Params().ProofOfWorkLimit().GetCompact()).getuint256(); printf("Target: %s\n", hashTarget.GetHex().c_str()); uint256 newhash = genesis.GetHash(); uint256 besthash; memset(&besthash,0xFF,32); while (newhash > hashTarget) { ++genesis.nNonce; if (genesis.nNonce == 0){ printf("NONCE WRAPPED, incrementing time"); ++genesis.nTime; } newhash = genesis.GetHash(); if(newhash < besthash){ besthash=newhash; printf("New best: %s\n", newhash.GetHex().c_str()); } } printf("Found Genesis, Nonce: %ld, Hash: %s\n", genesis.nNonce, genesis.GetHash().GetHex().c_str()); exit(0); }
static CBlock FindDevNetGenesisBlock(const Consensus::Params& params, const CBlock &prevBlock, const CAmount& reward) { std::string devNetName = GetDevNetName(); assert(!devNetName.empty()); CBlock block = CreateDevNetGenesisBlock(prevBlock.GetHash(), devNetName.c_str(), prevBlock.nTime + 1, 0, prevBlock.nBits, reward); arith_uint256 bnTarget; bnTarget.SetCompact(block.nBits); for (uint32_t nNonce = 0; nNonce < UINT32_MAX; nNonce++) { block.nNonce = nNonce; uint256 hash = block.GetHash(); if (UintToArith256(hash) <= bnTarget) return block; } // This is very unlikely to happen as we start the devnet with a very low difficulty. In many cases even the first // iteration of the above loop will give a result already error("FindDevNetGenesisBlock: could not find devnet genesis block for %s", devNetName); assert(false); }
UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript) { static const int nInnerLoopCount = 0x10000; int nHeightEnd = 0; int nHeight = 0; unsigned int profile = 0x3; { // Don't keep cs_main locked LOCK(cs_main); nHeight = chainActive.Height(); nHeightEnd = nHeight+nGenerate; } unsigned int nExtraNonce = 0; UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd && !ShutdownRequested()) { std::unique_ptr<CBlockTemplate> 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); } if (pblock->GetBlockTime() >= Params().GetConsensus().nNeoScryptFork) profile = 0x0; while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount && !CheckProofOfWork(pblock->GetPoWHash(profile), pblock->nBits, Params().GetConsensus())) { ++pblock->nNonce; --nMaxTries; } if (nMaxTries == 0) { break; } if (pblock->nNonce == nInnerLoopCount) { continue; } std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock); if (!ProcessNewBlock(Params(), shared_pblock, true, nullptr)) 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 generateBlocks(boost::shared_ptr<CReserveScript> 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<CBlockTemplate> pblocktemplate(CreateNewBlock(Params(), 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; } CValidationState state; if (!ProcessNewBlock(state, Params(), NULL, 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; }
int CTxIndex::GetDepthInMainChain() const { // Read block header CBlock block; if (!block.ReadFromDisk(pos.nFile, pos.nBlockPos, false)) return 0; // Find the block in the index map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.GetHash()); if (mi == mapBlockIndex.end()) return 0; CBlockIndex* pindex = (*mi).second; if (!pindex || !pindex->IsInMainChain()) return 0; return 1 + nBestHeight - pindex->nHeight; }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) confirmations = chainActive.Height() - blockindex->nHeight + 1; result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion.GetFullVersion())); int algo = block.GetAlgo(); result.push_back(Pair("pow_algo_id", algo)); result.push_back(Pair("pow_algo", GetAlgoName(algo))); result.push_back(Pair("pow_hash", block.GetPoWHash(algo).GetHex())); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); Array txs; BOOST_FOREACH(const CTransaction&tx, block.vtx) { if(txDetails) { Object objTx; TxToJSON(tx, uint256(), objTx); txs.push_back(objTx); } else txs.push_back(tx.GetHash().GetHex()); } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex, miningAlgo))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); if (block.auxpow) result.push_back(Pair("auxpow", auxpowToJSON(*block.auxpow))); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; }
double SumOfSubsidiesForRTM() { //Iterate throught the entire chain... if (nBestHeight < 10) 0; int nMaxDepth = nBestHeight; int nMinDepth = 1; double total = 0; CBlock block; for (int ii = nMaxDepth; ii > nMinDepth; ii--) { CBlockIndex* pblockindex = FindBlockByHeight(ii); block.ReadFromDisk(pblockindex); double subsidy = GetBlockValueByHash(block.GetHash()); total += subsidy; } return total/COIN; }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) confirmations = chainActive.Height() - blockindex->nHeight + 1; result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); if (block.nVersion & BLOCK_VERSION_AUXPOW) { // this block includes auxpow Object auxpow; auxpow.push_back(Pair("size", (int)::GetSerializeSize(*block.auxpow, SER_NETWORK, PROTOCOL_VERSION))); Object coinbasetx; TxToJSON(*block.auxpow, 0, coinbasetx); auxpow.push_back(Pair("coinbasetx", Value(coinbasetx))); Array coinbaseMerkle; BOOST_FOREACH(const uint256 &hash, block.auxpow->vMerkleBranch) coinbaseMerkle.push_back(hash.GetHex()); auxpow.push_back(Pair("coinbaseMerkleBranch", coinbaseMerkle)); auxpow.push_back(Pair("coinbaseIndex", block.auxpow->nIndex)); Array chainMerkle; BOOST_FOREACH(const uint256 &hash, block.auxpow->vChainMerkleBranch) chainMerkle.push_back(hash.GetHex()); auxpow.push_back(Pair("chainMerkleBranch", chainMerkle)); auxpow.push_back(Pair("chainIndex", (boost::uint64_t)block.auxpow->nChainIndex)); Object parent_block; parent_block.push_back(Pair("hash", block.auxpow->parentBlockHeader.GetHash().GetHex())); parent_block.push_back(Pair("version", (boost::uint64_t)block.auxpow->parentBlockHeader.nVersion)); parent_block.push_back(Pair("previousblockhash", block.auxpow->parentBlockHeader.hashPrevBlock.GetHex())); parent_block.push_back(Pair("merkleroot", block.auxpow->parentBlockHeader.hashMerkleRoot.GetHex())); parent_block.push_back(Pair("time", (boost::int64_t)block.auxpow->parentBlockHeader.nTime)); parent_block.push_back(Pair("bits", strprintf("%08x", block.auxpow->parentBlockHeader.nBits))); parent_block.push_back(Pair("nonce", (boost::uint64_t)block.auxpow->parentBlockHeader.nNonce)); auxpow.push_back(Pair("parent_block", Value(parent_block))); result.push_back(Pair("auxpow", Value(auxpow))); }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); CMerkleTx txGen(block.vtx[0]); txGen.SetMerkleBranch(&block); result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint))); result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime())); result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce)); result.push_back(Pair("bits", HexBits(block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("blocktrust", leftTrim(blockindex->GetBlockTrust().GetHex(), '0'))); result.push_back(Pair("chaintrust", leftTrim(blockindex->nChainTrust.GetHex(), '0'))); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); if (blockindex->pnext) result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex())); result.push_back(Pair("flags", strprintf("%s","proof-of-work"))); result.push_back(Pair("proofhash", blockindex->GetBlockHash().GetHex())); Array txinfo; BOOST_FOREACH (const CTransaction& tx, block.vtx) { if (fPrintTransactionDetail) { Object entry; entry.push_back(Pair("txid", tx.GetHash().GetHex())); TxToJSON(tx, 0, entry); txinfo.push_back(entry); } else txinfo.push_back(tx.GetHash().GetHex()); } result.push_back(Pair("tx", txinfo)); return result; }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); CMerkleTx txGen(block.vtx[0]); txGen.SetMerkleBranch(&block); result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); if (block.nVersion & BLOCK_VERSION_AUXPOW) { // this block includes auxpow Object auxpow; auxpow.push_back(Pair("size", (int)::GetSerializeSize(*block.auxpow, SER_NETWORK, PROTOCOL_VERSION))); Object coinbasetx; TxToJSON(*block.auxpow, 0, coinbasetx); auxpow.push_back(Pair("coinbasetx", Value(coinbasetx))); Array coinbaseMerkle; BOOST_FOREACH(const uint256 &hash, block.auxpow->vMerkleBranch) coinbaseMerkle.push_back(hash.GetHex()); auxpow.push_back(Pair("coinbaseMerkleBranch", coinbaseMerkle)); auxpow.push_back(Pair("coinbaseIndex", block.auxpow->nIndex)); Array chainMerkle; BOOST_FOREACH(const uint256 &hash, block.auxpow->vChainMerkleBranch) chainMerkle.push_back(hash.GetHex()); auxpow.push_back(Pair("chainMerkleBranch", chainMerkle)); auxpow.push_back(Pair("chainIndex", (boost::uint64_t)block.auxpow->nChainIndex)); Object parent_block; parent_block.push_back(Pair("hash", block.auxpow->parentBlockHeader.GetHash().GetHex())); parent_block.push_back(Pair("version", (boost::uint64_t)block.auxpow->parentBlockHeader.nVersion)); parent_block.push_back(Pair("previousblockhash", block.auxpow->parentBlockHeader.hashPrevBlock.GetHex())); parent_block.push_back(Pair("merkleroot", block.auxpow->parentBlockHeader.hashMerkleRoot.GetHex())); parent_block.push_back(Pair("time", (boost::int64_t)block.auxpow->parentBlockHeader.nTime)); parent_block.push_back(Pair("bits", HexBits(block.auxpow->parentBlockHeader.nBits))); parent_block.push_back(Pair("nonce", (boost::uint64_t)block.auxpow->parentBlockHeader.nNonce)); auxpow.push_back(Pair("parent_block", Value(parent_block))); result.push_back(Pair("auxpow", Value(auxpow))); }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); CMerkleTx txGen(block.vtx[0]); txGen.SetMerkleBranch(&block); result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); Array txs; Array txuserhashes; Array usernames; std::string spamMessage; std::string spamUser; BOOST_FOREACH(const CTransaction&tx, block.vtx) { txs.push_back(tx.GetHash().GetHex()); if( tx.IsSpamMessage() ) { spamMessage = tx.message.ExtractPushDataString(0); spamUser = tx.userName.ExtractPushDataString(0); } else { txuserhashes.push_back(tx.GetUsernameHash().GetHex()); usernames.push_back(tx.userName.ExtractSmallString()); } } result.push_back(Pair("tx", txs)); result.push_back(Pair("spamMessage", spamMessage)); result.push_back(Pair("spamUser", spamUser)); result.push_back(Pair("userhashes", txuserhashes)); result.push_back(Pair("usernames", usernames)); result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime())); result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce)); result.push_back(Pair("bits", HexBits(block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = blockindex->GetNextInMainChain(); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) confirmations = chainActive.Height() - blockindex->nHeight + 1; result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion.GetFullVersion())); result.push_back(Pair("proof_type", block.IsProofOfStake() ? "PoS" : "PoW")); if (block.IsProofOfStake()) result.push_back(Pair("stake_source", COutPoint(block.stakePointer.txid, block.stakePointer.nPos).ToString())); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); Array txs; BOOST_FOREACH(const CTransaction&tx, block.vtx) { if(txDetails) { Object objTx; TxToJSON(tx, uint256(), objTx); txs.push_back(objTx); } else txs.push_back(tx.GetHash().GetHex()); } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); result.push_back(Pair("block_witnesses", (int64_t)g_proofTracker->GetWitnessCount(block.GetHash()))); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; }
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { UniValue result(UniValue::VOBJ); result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) confirmations = chainActive.Height() - blockindex->nHeight + 1; result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); UniValue txs(UniValue::VARR); BOOST_FOREACH(const CTransaction&tx, block.vtx) { if(txDetails) { UniValue objTx(UniValue::VOBJ); TxToJSON(tx, uint256(), objTx); txs.push_back(objTx); } else txs.push_back(tx.GetHash().GetHex()); } 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("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; }
TEST(wallet_tests, nullifier_is_spent) { CWallet wallet; auto sk = libzcash::SpendingKey::random(); wallet.AddSpendingKey(sk); auto wtx = GetValidReceive(sk, 10, true); auto note = GetNote(sk, wtx, 0, 1); auto nullifier = note.nullifier(sk); EXPECT_FALSE(wallet.IsSpent(nullifier)); wallet.AddToWallet(wtx, true, NULL); EXPECT_FALSE(wallet.IsSpent(nullifier)); auto wtx2 = GetValidSpend(sk, note, 5); wallet.AddToWallet(wtx2, true, NULL); EXPECT_FALSE(wallet.IsSpent(nullifier)); // Fake-mine the transaction EXPECT_EQ(-1, chainActive.Height()); CBlock block; block.vtx.push_back(wtx2); block.hashMerkleRoot = block.BuildMerkleTree(); auto blockHash = block.GetHash(); CBlockIndex fakeIndex {block}; mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex)); chainActive.SetTip(&fakeIndex); EXPECT_TRUE(chainActive.Contains(&fakeIndex)); EXPECT_EQ(0, chainActive.Height()); wtx2.SetMerkleBranch(block); wallet.AddToWallet(wtx2, true, NULL); EXPECT_TRUE(wallet.IsSpent(nullifier)); // Tear down chainActive.SetTip(NULL); mapBlockIndex.erase(blockHash); }
bool SignStakeBlock(CBlock &block, CKey &key, vector<const CWalletTx*> &StakeInputs, CWallet *pwallet, MiningCPID& BoincData) { //Append beacon signature to coinbase std::string PublicKey = GlobalCPUMiningCPID.BoincPublicKey; if (!PublicKey.empty()) { std::string sBoincSignature; std::string sError; bool bResult = SignBlockWithCPID(GlobalCPUMiningCPID.cpid, GlobalCPUMiningCPID.lastblockhash, sBoincSignature, sError); if (!bResult) { return error("SignStakeBlock: Failed to sign boinchash -> %s\n", sError); } BoincData.BoincSignature = sBoincSignature; if(fDebug2) LogPrintf("Signing BoincBlock for cpid %s and blockhash %s with sig %s\n", GlobalCPUMiningCPID.cpid, GlobalCPUMiningCPID.lastblockhash, BoincData.BoincSignature); } block.vtx[0].hashBoinc = SerializeBoincBlock(BoincData,block.nVersion); //if (fDebug2) LogPrintf("SignStakeBlock: %s\n",SerializedBoincData.c_str()); //Sign the coinstake transaction unsigned nIn = 0; for (auto const& pcoin : StakeInputs) { if (!SignSignature(*pwallet, *pcoin, block.vtx[1], nIn++)) { return error("SignStakeBlock: failed to sign coinstake"); } } //Sign the whole block block.hashMerkleRoot = block.BuildMerkleTree(); if( !key.Sign(block.GetHash(), block.vchBlockSig) ) { return error("SignStakeBlock: failed to sign block"); } return true; }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); CMerkleTx txGen(block.vtx[0]); txGen.SetMerkleBranch(&block); result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); result.push_back(Pair("size", (int)blockindex->nSize)); result.push_back(Pair("chainsize", blockindex->nChainSize)); if (chainActive.Contains(blockindex)) result.push_back(Pair("maxsize", (int)chainActive.MaxBlockSize(blockindex->nHeight))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", (uint64_t)block.GetVersion())); result.push_back(Pair("ispok", block.IsPoKBlock())); if (block.IsPoKBlock()) result.push_back(Pair("pok", (uint64_t)block.GetPoK())); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("bits", HexBits(block.nBits))); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); Array txs; BOOST_FOREACH(const CTransaction&tx, block.vtx) txs.push_back(tx.GetHash().GetHex()); result.push_back(Pair("tx", txs)); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); result.push_back(Pair("ntx", (int64_t)blockindex->nTx)); result.push_back(Pair("nchaintx", (int64_t)blockindex->nChainTx)); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; }
bool CDeterministicMNManager::UndoBlock(const CBlock& block, const CBlockIndex* pindex) { int nHeight = pindex->nHeight; uint256 blockHash = block.GetHash(); CDeterministicMNList curList; CDeterministicMNList prevList; CDeterministicMNListDiff diff; { LOCK(cs); evoDb.Read(std::make_pair(DB_LIST_DIFF, blockHash), diff); if (diff.HasChanges()) { // need to call this before erasing curList = GetListForBlock(blockHash); prevList = GetListForBlock(pindex->pprev->GetBlockHash()); } evoDb.Erase(std::make_pair(DB_LIST_DIFF, blockHash)); evoDb.Erase(std::make_pair(DB_LIST_SNAPSHOT, blockHash)); mnListsCache.erase(blockHash); } if (diff.HasChanges()) { auto inversedDiff = curList.BuildDiff(prevList); GetMainSignals().NotifyMasternodeListChanged(true, curList, inversedDiff); uiInterface.NotifyMasternodeListChanged(); } const auto& consensusParams = Params().GetConsensus(); if (nHeight == consensusParams.DIP0003EnforcementHeight) { LogPrintf("CDeterministicMNManager::%s -- DIP3 is not enforced anymore. nHeight=%d\n", __func__, nHeight); } return true; }
Object diskBlockThinIndexToJSON(CDiskBlockThinIndex& diskBlock) { CBlock block = diskBlock.GetBlock(); Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); //CMerkleTx txGen(block.vtx[0]); //txGen.SetMerkleBranch(&block); //result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); //result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", diskBlock.nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); //result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint))); result.push_back(Pair("time", (int64_t)block.GetBlockTime())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("bits", HexBits(block.nBits))); result.push_back(Pair("difficulty", BitsToDouble(diskBlock.nBits))); result.push_back(Pair("blocktrust", leftTrim(diskBlock.GetBlockTrust().GetHex(), '0'))); result.push_back(Pair("chaintrust", leftTrim(diskBlock.nChainTrust.GetHex(), '0'))); result.push_back(Pair("previousblockhash", diskBlock.hashPrev.GetHex())); result.push_back(Pair("nextblockhash", diskBlock.hashNext.GetHex())); result.push_back(Pair("flags", strprintf("%s%s", diskBlock.IsProofOfStake()? "proof-of-stake" : "proof-of-work", diskBlock.GeneratedStakeModifier()? " stake-modifier": ""))); result.push_back(Pair("proofhash", diskBlock.hashProof.GetHex())); result.push_back(Pair("entropybit", (int)diskBlock.GetStakeEntropyBit())); result.push_back(Pair("modifier", strprintf("%016x", diskBlock.nStakeModifier))); //result.push_back(Pair("modifierchecksum", strprintf("%08x", diskBlock.nStakeModifierChecksum))); //if (block.IsProofOfStake()) // result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end()))); return result; }
void SignBlock(CBlock& block){ block_signature sig = MakeBlockSignature((const unsigned char*) block.GetHash().GetHex().c_str()); block.sig = sig.sig; block.slen = sig.slen; }
int PrimeWorker::HandleRequest(zmq_pollitem_t *item) { proto::Request& req = mRequest; zmsg_t* msg = ReceiveRequest(req, item->socket); if(!msg) return 0; //req.PrintDebugString(); proto::Request::Type rtype = req.type(); proto::Reply::ErrType etype = proto::Reply::NONE; proto::Reply& rep = mReply; rep.Clear(); rep.set_type(rtype); rep.set_reqid(req.reqid()); if(!proto::Request::Type_IsValid(rtype)){ printf("ERROR: !proto::Request::Type_IsValid.\n"); rtype = proto::Request::NONE; etype = proto::Reply::INVALID; } while(etype == proto::Reply::NONE) { int vstatus = CheckVersion(req.version()); if(vstatus <= 0){ rep.set_errstr("Your miner version is no longer supported. Please upgrade."); etype = proto::Reply::VERSION; break; } if(rtype == proto::Request::CONNECT){ rep.mutable_sinfo()->CopyFrom(mServerInfo); if(vstatus == 1){ etype = proto::Reply::VERSION; rep.set_errstr("Your miner version will no longer be supported in the near future. Please upgrade."); } }else if(rtype == proto::Request::GETWORK){ if(!mCurrBlock.has_height()){ etype = proto::Reply::HEIGHT; break; } if(req.height() != mCurrHeight){ etype = proto::Reply::HEIGHT; break; } CBlock *pblock = &mBlockTemplate->block; IncrementExtraNonce(pblock, mIndexPrev, mExtraNonce); pblock->nTime = std::max(pblock->nTime, (unsigned int)GetAdjustedTime()); mNonceMap[pblock->hashMerkleRoot] = mExtraNonce; proto::Work* work = rep.mutable_work(); work->set_height(mCurrHeight); work->set_merkle(pblock->hashMerkleRoot.GetHex()); work->set_time(pblock->nTime); work->set_bits(pblock->nBits); }else if(rtype == proto::Request::SHARE){ if(!mCurrBlock.has_height()){ etype = proto::Reply::STALE; break; } if(!req.has_share()){ printf("ERROR: !req.has_share().\n"); etype = proto::Reply::INVALID; break; } const proto::Share& share = req.share(); if(share.height() != mCurrHeight){ etype = proto::Reply::STALE; break; } if(share.length() < mCurrBlock.minshare()){ printf("ERROR: share.length too short.\n"); etype = proto::Reply::INVALID; break; } uint256 merkleRoot; merkleRoot.SetHex(share.merkle()); unsigned extraNonce = mNonceMap[merkleRoot]; if(!extraNonce){ etype = proto::Reply::STALE; break; } unsigned nCandidateType = share.chaintype(); if(nCandidateType > 2){ printf("ERROR: share.chaintype invalid.\n"); etype = proto::Reply::INVALID; break; } CBlock *pblock = &mBlockTemplate->block; extraNonce--; IncrementExtraNonce(pblock, mIndexPrev, extraNonce); pblock->nTime = share.time(); pblock->nBits = share.bits(); pblock->nNonce = share.nonce(); uint256 headerHash = pblock->GetHeaderHash(); { uint256 headerHashClient; headerHashClient.SetHex(share.hash()); if(headerHashClient != headerHash){ printf("ERROR: headerHashClient != headerHash.\n"); etype = proto::Reply::INVALID; break; } } pblock->bnPrimeChainMultiplier.SetHex(share.multi()); uint256 blockhash = pblock->GetHash(); if(!mShares.insert(blockhash).second){ etype = proto::Reply::DUPLICATE; break; } CBigNum bnChainOrigin = CBigNum(headerHash) * pblock->bnPrimeChainMultiplier; unsigned int nChainLength = 0; bool isblock = ProbablePrimeChainTestForMiner(bnChainOrigin, pblock->nBits, nCandidateType+1, nChainLength); nChainLength = TargetGetLength(nChainLength); if(nChainLength >= mCurrBlock.minshare()){ if(isblock) isblock = CheckWork(pblock, *mWallet, mReserveKey); if(share.length() != nChainLength){ printf("ERROR: share.length() != nChainLength.\n"); etype = proto::Reply::INVALID; } mData.Clear(); proto::Share* mshare = mData.mutable_share(); mshare->CopyFrom(share); mshare->set_blockhash(blockhash.GetHex()); mshare->set_length(nChainLength); mshare->set_isblock(isblock); if(isblock){ mshare->set_genvalue(pblock->vtx[0].vout[0].nValue); } SendData(mData, mBackend); CBitcoinAddress address(share.addr()); if(!address.IsValid()){ printf("ERROR: invalid address for share: %s\n", share.addr().c_str()); etype = proto::Reply::INVALID; std::string errstr = "Your payment address '"; errstr.append(share.addr()); errstr.append("' is INVALID!!!"); rep.set_errstr(errstr); break; } }else{ printf("ERROR: share.length too short after test: %d/%d\n", nChainLength, share.length()); etype = proto::Reply::INVALID; break; } }else if(rtype == proto::Request::STATS){ if(!req.has_stats()){ printf("ERROR: !req.has_stats().\n"); etype = proto::Reply::INVALID; break; } const proto::ClientStats& stats = req.stats(); std::pair<std::string,uint64> key = std::make_pair(stats.addr(), stats.clientid() * stats.instanceid()); std::map<std::pair<std::string,uint64>, proto::Data>::iterator iter = mStats.find(key); if(iter != mStats.end()){ proto::ClientStats* s = mStats[key].mutable_clientstats(); s->set_version(std::min(s->version(), stats.version())); s->set_cpd(s->cpd() + stats.cpd()); s->set_errors(s->errors() + stats.errors()); s->set_temp(std::max(s->temp(), stats.temp())); s->set_latency(std::max(s->latency(), stats.latency())); s->set_ngpus(s->ngpus() + stats.ngpus()); /*if(s->name() != stats.name()){ s->mutable_name()->append("+"); s->mutable_name()->append(stats.name()); }*/ }else if(mStats.size() < 100000){ mStats[key].mutable_clientstats()->CopyFrom(stats); } } break; } if(req.height() < mCurrHeight){ rep.mutable_block()->CopyFrom(mCurrBlock); } mReqStats[std::make_pair(rtype,etype)]++; rep.set_error(etype); SendReply(rep, &msg, item->socket); zmsg_destroy(&msg); return 0; }
UniValue getauxblock(const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 0 && params.size() != 2)) throw std::runtime_error( "getauxblock (hash auxpow)\n" "\nCreate or submit a merge-mined block.\n" "\nWithout arguments, create a new block and return information\n" "required to merge-mine it. With arguments, submit a solved\n" "auxpow for a previously returned block.\n" "\nArguments:\n" "1. \"hash\" (string, optional) hash of the block to submit\n" "2. \"auxpow\" (string, optional) serialised auxpow found\n" "\nResult (without arguments):\n" "{\n" " \"hash\" (string) hash of the created block\n" " \"chainid\" (numeric) chain ID for this block\n" " \"previousblockhash\" (string) hash of the previous block\n" " \"coinbasevalue\" (numeric) value of the block's coinbase\n" " \"bits\" (string) compressed target of the block\n" " \"height\" (numeric) height of the block\n" " \"_target\" (string) target in reversed byte order, deprecated\n" "}\n" "\nResult (with arguments):\n" "xxxxx (boolean) whether the submitted block was correct\n" "\nExamples:\n" + HelpExampleCli("getauxblock", "") + HelpExampleCli("getauxblock", "\"hash\" \"serialised auxpow\"") + HelpExampleRpc("getauxblock", "") ); boost::shared_ptr<CReserveScript> coinbaseScript; GetMainSignals().ScriptForMining(coinbaseScript); //throw an error if no script was provided if (!coinbaseScript->reserveScript.size()) throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); if (vNodes.empty() && !Params().MineBlocksOnDemand()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Namecoin is not connected!"); if (IsInitialBlockDownload() && !Params().MineBlocksOnDemand()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Namecoin is downloading blocks..."); /* This should never fail, since the chain is already past the point of merge-mining start. Check nevertheless. */ { LOCK(cs_main); if (chainActive.Height() + 1 < Params().GetConsensus().nAuxpowStartHeight) throw std::runtime_error("getauxblock method is not yet available"); } /* The variables below are used to keep track of created and not yet submitted auxpow blocks. Lock them to be sure even for multiple RPC threads running in parallel. */ static CCriticalSection cs_auxblockCache; LOCK(cs_auxblockCache); static std::map<uint256, CBlock*> mapNewBlock; static std::vector<CBlockTemplate*> vNewBlockTemplate; /* Create a new block? */ if (params.size() == 0) { static unsigned nTransactionsUpdatedLast; static const CBlockIndex* pindexPrev = NULL; static uint64_t nStart; static CBlockTemplate* pblocktemplate; static unsigned nExtraNonce = 0; // Update block { LOCK(cs_main); if (pindexPrev != chainActive.Tip() || (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)) { if (pindexPrev != chainActive.Tip()) { // Deallocate old blocks since they're obsolete now mapNewBlock.clear(); BOOST_FOREACH(CBlockTemplate* pbt, vNewBlockTemplate) delete pbt; vNewBlockTemplate.clear(); } // Create new block with nonce = 0 and extraNonce = 1 pblocktemplate = CreateNewBlock(coinbaseScript->reserveScript); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "out of memory"); // Update state only when CreateNewBlock succeeded nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); pindexPrev = chainActive.Tip(); nStart = GetTime(); // Finalise it by setting the version and building the merkle root CBlock* pblock = &pblocktemplate->block; IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); pblock->nVersion.SetAuxpow(true); pblock->hashMerkleRoot = pblock->BuildMerkleTree(); // Save mapNewBlock[pblock->GetHash()] = pblock; vNewBlockTemplate.push_back(pblocktemplate); } } const CBlock& block = pblocktemplate->block; arith_uint256 target; bool fNegative, fOverflow; target.SetCompact(block.nBits, &fNegative, &fOverflow); if (fNegative || fOverflow || target == 0) throw std::runtime_error("invalid difficulty bits in block"); UniValue result(UniValue::VOBJ); result.push_back(Pair("hash", block.GetHash().GetHex())); result.push_back(Pair("chainid", block.nVersion.GetChainId())); result.push_back(Pair("previousblockhash", block.hashPrevBlock.GetHex())); result.push_back(Pair("coinbasevalue", (int64_t)block.vtx[0].vout[0].nValue)); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("height", static_cast<int64_t> (pindexPrev->nHeight + 1))); result.push_back(Pair("_target", HexStr(BEGIN(target), END(target)))); return result; } /* Submit a block instead. Note that this need not lock cs_main, since ProcessBlockFound below locks it instead. */ assert(params.size() == 2); uint256 hash; hash.SetHex(params[0].get_str()); const std::map<uint256, CBlock*>::iterator mit = mapNewBlock.find(hash); if (mit == mapNewBlock.end()) throw JSONRPCError(RPC_INVALID_PARAMETER, "block hash unknown"); CBlock& block = *mit->second; const std::vector<unsigned char> vchAuxPow = ParseHex(params[1].get_str()); CDataStream ss(vchAuxPow, SER_GETHASH, PROTOCOL_VERSION); CAuxPow pow; ss >> pow; block.SetAuxpow(new CAuxPow(pow)); assert(block.GetHash() == hash); const bool ok = ProcessBlockFound(&block, Params()); if (ok) coinbaseScript->KeepScript(); return ok; }
BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) { // Test that passing CheckInputs with one set of script flags doesn't imply // that we would pass again with a different set of flags. { LOCK(cs_main); InitScriptExecutionCache(); } CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; CScript p2sh_scriptPubKey = GetScriptForDestination(CScriptID(p2pk_scriptPubKey)); CScript p2pkh_scriptPubKey = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); CScript p2wpkh_scriptPubKey = GetScriptForWitness(p2pkh_scriptPubKey); CBasicKeyStore keystore; keystore.AddKey(coinbaseKey); keystore.AddCScript(p2pk_scriptPubKey); // flags to test: SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, SCRIPT_VERIFY_CHECKSEQUENCE_VERIFY, SCRIPT_VERIFY_NULLDUMMY, uncompressed pubkey thing // Create 2 outputs that match the three scripts above, spending the first // coinbase tx. CMutableTransaction spend_tx; spend_tx.nVersion = 1; spend_tx.vin.resize(1); spend_tx.vin[0].prevout.hash = m_coinbase_txns[0]->GetHash(); spend_tx.vin[0].prevout.n = 0; spend_tx.vout.resize(4); spend_tx.vout[0].nValue = 11*CENT; spend_tx.vout[0].scriptPubKey = p2sh_scriptPubKey; spend_tx.vout[1].nValue = 11*CENT; spend_tx.vout[1].scriptPubKey = p2wpkh_scriptPubKey; spend_tx.vout[2].nValue = 11*CENT; spend_tx.vout[2].scriptPubKey = CScript() << OP_CHECKLOCKTIMEVERIFY << OP_DROP << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; spend_tx.vout[3].nValue = 11*CENT; spend_tx.vout[3].scriptPubKey = CScript() << OP_CHECKSEQUENCEVERIFY << OP_DROP << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; // Sign, with a non-DER signature { std::vector<unsigned char> vchSig; uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char) 0); // padding byte makes this non-DER vchSig.push_back((unsigned char)SIGHASH_ALL); spend_tx.vin[0].scriptSig << vchSig; } // Test that invalidity under a set of flags doesn't preclude validity // under other (eg consensus) flags. // spend_tx is invalid according to DERSIG { LOCK(cs_main); CValidationState state; PrecomputedTransactionData ptd_spend_tx(spend_tx); BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr)); // If we call again asking for scriptchecks (as happens in // ConnectBlock), we should add a script check object for this -- we're // not caching invalidity (if that changes, delete this test case). std::vector<CScriptCheck> scriptchecks; BOOST_CHECK(CheckInputs(spend_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks)); BOOST_CHECK_EQUAL(scriptchecks.size(), 1U); // Test that CheckInputs returns true iff DERSIG-enforcing flags are // not present. Don't add these checks to the cache, so that we can // test later that block validation works fine in the absence of cached // successes. ValidateCheckInputsForAllFlags(spend_tx, SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false); } // And if we produce a block with this tx, it should be valid (DERSIG not // enabled yet), even though there's no cache entry. CBlock block; block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey); BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash()); LOCK(cs_main); // Test P2SH: construct a transaction that is valid without P2SH, and // then test validity with P2SH. { CMutableTransaction invalid_under_p2sh_tx; invalid_under_p2sh_tx.nVersion = 1; invalid_under_p2sh_tx.vin.resize(1); invalid_under_p2sh_tx.vin[0].prevout.hash = spend_tx.GetHash(); invalid_under_p2sh_tx.vin[0].prevout.n = 0; invalid_under_p2sh_tx.vout.resize(1); invalid_under_p2sh_tx.vout[0].nValue = 11*CENT; invalid_under_p2sh_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; std::vector<unsigned char> vchSig2(p2pk_scriptPubKey.begin(), p2pk_scriptPubKey.end()); invalid_under_p2sh_tx.vin[0].scriptSig << vchSig2; ValidateCheckInputsForAllFlags(invalid_under_p2sh_tx, SCRIPT_VERIFY_P2SH, true); } // Test CHECKLOCKTIMEVERIFY { CMutableTransaction invalid_with_cltv_tx; invalid_with_cltv_tx.nVersion = 1; invalid_with_cltv_tx.nLockTime = 100; invalid_with_cltv_tx.vin.resize(1); invalid_with_cltv_tx.vin[0].prevout.hash = spend_tx.GetHash(); invalid_with_cltv_tx.vin[0].prevout.n = 2; invalid_with_cltv_tx.vin[0].nSequence = 0; invalid_with_cltv_tx.vout.resize(1); invalid_with_cltv_tx.vout[0].nValue = 11*CENT; invalid_with_cltv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; // Sign std::vector<unsigned char> vchSig; uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101; ValidateCheckInputsForAllFlags(invalid_with_cltv_tx, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true); // Make it valid, and check again invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100; CValidationState state; PrecomputedTransactionData txdata(invalid_with_cltv_tx); BOOST_CHECK(CheckInputs(invalid_with_cltv_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr)); } // TEST CHECKSEQUENCEVERIFY { CMutableTransaction invalid_with_csv_tx; invalid_with_csv_tx.nVersion = 2; invalid_with_csv_tx.vin.resize(1); invalid_with_csv_tx.vin[0].prevout.hash = spend_tx.GetHash(); invalid_with_csv_tx.vin[0].prevout.n = 3; invalid_with_csv_tx.vin[0].nSequence = 100; invalid_with_csv_tx.vout.resize(1); invalid_with_csv_tx.vout[0].nValue = 11*CENT; invalid_with_csv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; // Sign std::vector<unsigned char> vchSig; uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101; ValidateCheckInputsForAllFlags(invalid_with_csv_tx, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true); // Make it valid, and check again invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100; CValidationState state; PrecomputedTransactionData txdata(invalid_with_csv_tx); BOOST_CHECK(CheckInputs(invalid_with_csv_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr)); } // TODO: add tests for remaining script flags // Test that passing CheckInputs with a valid witness doesn't imply success // for the same tx with a different witness. { CMutableTransaction valid_with_witness_tx; valid_with_witness_tx.nVersion = 1; valid_with_witness_tx.vin.resize(1); valid_with_witness_tx.vin[0].prevout.hash = spend_tx.GetHash(); valid_with_witness_tx.vin[0].prevout.n = 1; valid_with_witness_tx.vout.resize(1); valid_with_witness_tx.vout[0].nValue = 11*CENT; valid_with_witness_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; // Sign SignatureData sigdata; ProduceSignature(keystore, MutableTransactionSignatureCreator(&valid_with_witness_tx, 0, 11*CENT, SIGHASH_ALL), spend_tx.vout[1].scriptPubKey, sigdata); UpdateTransaction(valid_with_witness_tx, 0, sigdata); // This should be valid under all script flags. ValidateCheckInputsForAllFlags(valid_with_witness_tx, 0, true); // Remove the witness, and check that it is now invalid. valid_with_witness_tx.vin[0].scriptWitness.SetNull(); ValidateCheckInputsForAllFlags(valid_with_witness_tx, SCRIPT_VERIFY_WITNESS, true); } { // Test a transaction with multiple inputs. CMutableTransaction tx; tx.nVersion = 1; tx.vin.resize(2); tx.vin[0].prevout.hash = spend_tx.GetHash(); tx.vin[0].prevout.n = 0; tx.vin[1].prevout.hash = spend_tx.GetHash(); tx.vin[1].prevout.n = 1; tx.vout.resize(1); tx.vout[0].nValue = 22*CENT; tx.vout[0].scriptPubKey = p2pk_scriptPubKey; // Sign for (int i=0; i<2; ++i) { SignatureData sigdata; ProduceSignature(keystore, MutableTransactionSignatureCreator(&tx, i, 11*CENT, SIGHASH_ALL), spend_tx.vout[i].scriptPubKey, sigdata); UpdateTransaction(tx, i, sigdata); } // This should be valid under all script flags ValidateCheckInputsForAllFlags(tx, 0, true); // Check that if the second input is invalid, but the first input is // valid, the transaction is not cached. // Invalidate vin[1] tx.vin[1].scriptWitness.SetNull(); CValidationState state; PrecomputedTransactionData txdata(tx); // This transaction is now invalid under segwit, because of the second input. BOOST_CHECK(!CheckInputs(tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr)); std::vector<CScriptCheck> scriptchecks; // Make sure this transaction was not cached (ie because the first // input was valid) BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks)); // Should get 2 script checks back -- caching is on a whole-transaction basis. BOOST_CHECK_EQUAL(scriptchecks.size(), 2U); } }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); CMerkleTx txGen(block.vtx[0]); txGen.SetMerkleBranch(&block); result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); Array txs; BOOST_FOREACH(const CTransaction&tx, block.vtx) txs.push_back(tx.GetHash().GetHex()); result.push_back(Pair("tx", txs)); result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime())); result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce)); result.push_back(Pair("bits", HexBits(block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); //result.push_back(Pair("boinchash", block.hashBoinc)); MiningCPID bb = DeserializeBoincBlock(block.hashBoinc); uint256 blockhash = block.GetPoWHash(); std::string sblockhash = blockhash.GetHex(); result.push_back(Pair("BlockType", block.BlockType)); result.push_back(Pair("CPID", bb.cpid)); result.push_back(Pair("ProjectName", bb.projectname)); result.push_back(Pair("BlockDiffBytes", (double)bb.diffbytes)); result.push_back(Pair("RAC", bb.rac)); result.push_back(Pair("NetworkRAC", bb.NetworkRAC)); //if (block.hashBoinc.length() > 10) //{ //result.push_back(Pair("BoincHash",block.hashBoinc.substr(0,100))); //} result.push_back(Pair("PoBDifficulty", bb.pobdifficulty)); result.push_back(Pair("AES512SkeinHash", bb.aesskein)); std::string skein2 = aes_complex_hash(blockhash); result.push_back(Pair("AESCalcHash",skein2)); uint256 boincpowhash = block.hashMerkleRoot + bb.nonce; int iav = TestAESHash(bb.rac, (unsigned int)bb.diffbytes, boincpowhash, bb.aesskein); result.push_back(Pair("AES512Valid",iav)); result.push_back(Pair("ClientVersion",bb.clientversion)); std::string hbd = AdvancedDecrypt(bb.enccpid); bool IsCpidValid = IsCPIDValid(bb.cpid, bb.enccpid); result.push_back(Pair("CPIDValid",IsCpidValid)); result.push_back(Pair("PoWHash",blockhash.GetHex())); //Subsidy 6-29-2014 result.push_back(Pair("Subsidy", ValueFromAmount(GetBlockValueByHash(block.GetHash())))); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); if (blockindex->pnext) result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex())); return result; }
Value rewindchain(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "rewindchain <number>\n" "Remove <number> blocks from the chain."); int nNumber = params[0].get_int(); if (nNumber < 0 || nNumber > nBestHeight) throw runtime_error("Block number out of range."); Object result; int nRemoved = 0; { LOCK2(cs_main, pwalletMain->cs_wallet); uint32_t nFileRet = 0; uint8_t buffer[512]; LogPrintf("rewindchain %d\n", nNumber); void* nFind; for (int i = 0; i < nNumber; ++i) { memset(buffer, 0, sizeof(buffer)); FILE* fp = AppendBlockFile(false, nFileRet, "r+b"); if (!fp) { LogPrintf("AppendBlockFile failed.\n"); break; }; errno = 0; if (fseek(fp, 0, SEEK_END) != 0) { LogPrintf("fseek failed: %s\n", strerror(errno)); break; }; long int fpos = ftell(fp); if (fpos == -1) { LogPrintf("ftell failed: %s\n", strerror(errno)); break; }; long int foundPos = -1; long int readSize = sizeof(buffer) / 2; while (fpos > 0) { if (fpos < (long int)sizeof(buffer) / 2) readSize = fpos; memcpy(buffer+readSize, buffer, readSize); // move last read data (incase token crosses a boundary) fpos -= readSize; if (fseek(fp, fpos, SEEK_SET) != 0) { LogPrintf("fseek failed: %s\n", strerror(errno)); break; }; errno = 0; if (fread(buffer, sizeof(uint8_t), readSize, fp) != (size_t)readSize) { if (errno != 0) LogPrintf("fread failed: %s\n", strerror(errno)); else LogPrintf("End of file.\n"); break; }; uint32_t findPos = sizeof(buffer); while (findPos > MESSAGE_START_SIZE) { if ((nFind = shellk::memrchr(buffer, Params().MessageStart()[0], findPos-MESSAGE_START_SIZE))) { if (memcmp(nFind, Params().MessageStart(), MESSAGE_START_SIZE) == 0) { foundPos = ((uint8_t*)nFind - buffer) + MESSAGE_START_SIZE; break; } else { findPos = ((uint8_t*)nFind - buffer); // -- step over matched char that wasn't pchMessageStart if (findPos > 0) // prevent findPos < 0 (unsigned) findPos--; }; } else { break; // pchMessageStart[0] not found in buffer }; }; if (foundPos > -1) break; }; LogPrintf("fpos %d, foundPos %d.\n", fpos, foundPos); if (foundPos < 0) { LogPrintf("block start not found.\n"); fclose(fp); break; }; CAutoFile blkdat(fp, SER_DISK, CLIENT_VERSION); if (fseek(blkdat, fpos+foundPos, SEEK_SET) != 0) { LogPrintf("fseek blkdat failed: %s\n", strerror(errno)); break; }; unsigned int nSize; blkdat >> nSize; LogPrintf("nSize %u .\n", nSize); if (nSize < 1 || nSize > MAX_BLOCK_SIZE) { LogPrintf("block size error %u\n", nSize); }; CBlock block; blkdat >> block; uint256 hashblock = block.GetHash(); LogPrintf("hashblock %s .\n", hashblock.ToString().c_str()); std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashblock); if (mi != mapBlockIndex.end() && (*mi).second) { LogPrintf("block is in main chain.\n"); if (!mi->second->pprev) { LogPrintf("! mi->second.pprev\n"); } else { { CBlock blockPrev; // strange way SetBestChain works, TODO: does it need the full block? if (!blockPrev.ReadFromDisk(mi->second->pprev)) { LogPrintf("blockPrev.ReadFromDisk failed %s.\n", mi->second->pprev->GetBlockHash().ToString().c_str()); break; }; CTxDB txdb; if (!blockPrev.SetBestChain(txdb, mi->second->pprev)) { LogPrintf("SetBestChain failed.\n"); }; } mi->second->pprev->pnext = NULL; }; delete mi->second; mapBlockIndex.erase(mi); }; std::map<uint256, COrphanBlock*>::iterator miOph = mapOrphanBlocks.find(hashblock); if (miOph != mapOrphanBlocks.end()) { LogPrintf("block is an orphan.\n"); mapOrphanBlocks.erase(miOph); }; CTxDB txdb; for (vector<CTransaction>::iterator it = block.vtx.begin(); it != block.vtx.end(); ++it) { LogPrintf("EraseTxIndex().\n"); txdb.EraseTxIndex(*it); }; LogPrintf("EraseBlockIndex().\n"); txdb.EraseBlockIndex(hashblock); errno = 0; if (ftruncate(fileno(fp), fpos+foundPos-MESSAGE_START_SIZE) != 0) { LogPrintf("ftruncate failed: %s\n", strerror(errno)); }; LogPrintf("hashBestChain %s, nBestHeight %d\n", hashBestChain.ToString().c_str(), nBestHeight); //fclose(fp); // ~CAutoFile() will close the file nRemoved++; }; } result.push_back(Pair("no. blocks removed", itostr(nRemoved))); result.push_back(Pair("hashBestChain", hashBestChain.ToString())); result.push_back(Pair("nBestHeight", itostr(nBestHeight))); // -- need restart, setStakeSeen etc if (nRemoved > 0) result.push_back(Pair("Please restart Taurus", "")); if (nRemoved == nNumber) result.push_back(Pair("result", "success")); else result.push_back(Pair("result", "failure")); return result; }
void BlockChecked(const CBlock& block, const CValidationState& stateIn) override { if (block.GetHash() != hash) return; found = true; state = stateIn; }
static 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" " }\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", "{\"rules\": [\"segwit\"]}") + HelpExampleRpc("getblocktemplate", "{\"rules\": [\"segwit\"]}") ); LOCK(cs_main); std::string strMode = "template"; UniValue lpval = NullUniValue; std::set<std::string> setClientRules; int64_t nMaxVersionPreVB = -1; if (!request.params[0].isNull()) { const UniValue& oparam = request.params[0].get_obj(); const UniValue& modeval = find_value(oparam, "mode"); if (modeval.isStr()) strMode = modeval.get_str(); else if (modeval.isNull()) { /* Do nothing */ } else throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); lpval = find_value(oparam, "longpollid"); if (strMode == "proposal") { const UniValue& dataval = find_value(oparam, "data"); if (!dataval.isStr()) throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal"); CBlock block; if (!DecodeHexBlk(block, dataval.get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); uint256 hash = block.GetHash(); const CBlockIndex* pindex = LookupBlockIndex(hash); if (pindex) { if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) return "duplicate"; if (pindex->nStatus & BLOCK_FAILED_MASK) return "duplicate-invalid"; return "duplicate-inconclusive"; } CBlockIndex* const pindexPrev = chainActive.Tip(); // TestBlockValidity only supports blocks built on the current Tip if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; CValidationState state; TestBlockValidity(state, Params(), block, pindexPrev, false, true); return BIP22ValidationResult(state); } const UniValue& aClientRules = find_value(oparam, "rules"); if (aClientRules.isArray()) { for (unsigned int i = 0; i < aClientRules.size(); ++i) { const UniValue& v = aClientRules[i]; setClientRules.insert(v.get_str()); } } else { // NOTE: It is important that this NOT be read if versionbits is supported const UniValue& uvMaxVersion = find_value(oparam, "maxversion"); if (uvMaxVersion.isNum()) { nMaxVersionPreVB = uvMaxVersion.get_int64(); } } } if (strMode != "template") throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!"); if (IsInitialBlockDownload()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Bitcoin is downloading blocks..."); static unsigned int nTransactionsUpdatedLast; if (!lpval.isNull()) { // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions uint256 hashWatchedChain; std::chrono::steady_clock::time_point checktxtime; unsigned int nTransactionsUpdatedLastLP; if (lpval.isStr()) { // Format: <hashBestChain><nTransactionsUpdatedLast> std::string lpstr = lpval.get_str(); hashWatchedChain = ParseHashV(lpstr.substr(0, 64), "longpollid"); nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64)); } else { // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier hashWatchedChain = chainActive.Tip()->GetBlockHash(); nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; } // Release the wallet and main lock while waiting LEAVE_CRITICAL_SECTION(cs_main); { checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1); WAIT_LOCK(g_best_block_mutex, lock); while (g_best_block == hashWatchedChain && IsRPCRunning()) { if (g_best_block_cv.wait_until(lock, checktxtime) == std::cv_status::timeout) { // Timeout: Check transactions for update if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) break; checktxtime += std::chrono::seconds(10); } } } ENTER_CRITICAL_SECTION(cs_main); if (!IsRPCRunning()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners? } const struct VBDeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT]; // If the caller is indicating segwit support, then allow CreateNewBlock() // to select witness transactions, after segwit activates (otherwise // don't). bool fSupportsSegwit = setClientRules.find(segwit_info.name) != setClientRules.end(); // Update block static CBlockIndex* pindexPrev; static int64_t nStart; static std::unique_ptr<CBlockTemplate> pblocktemplate; // Cache whether the last invocation was with segwit support, to avoid returning // a segwit-block to a non-segwit caller. static bool fLastTemplateSupportsSegwit = true; if (pindexPrev != chainActive.Tip() || (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5) || fLastTemplateSupportsSegwit != fSupportsSegwit) { // 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(); fLastTemplateSupportsSegwit = fSupportsSegwit; // 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; } assert(pindexPrev); CBlock* pblock = &pblocktemplate->block; // pointer for convenience const Consensus::Params& consensusParams = Params().GetConsensus(); // Update nTime UpdateTime(pblock, consensusParams, pindexPrev); pblock->nNonce = 0; // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration const bool fPreSegWit = (ThresholdState::ACTIVE != VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache)); UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); UniValue transactions(UniValue::VARR); std::map<uint256, int64_t> 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.pushKV("data", EncodeHexTx(tx)); entry.pushKV("txid", txHash.GetHex()); entry.pushKV("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.pushKV("depends", deps); int index_in_template = i - 1; entry.pushKV("fee", pblocktemplate->vTxFees[index_in_template]); int64_t nTxSigOps = pblocktemplate->vTxSigOpsCost[index_in_template]; if (fPreSegWit) { assert(nTxSigOps % WITNESS_SCALE_FACTOR == 0); nTxSigOps /= WITNESS_SCALE_FACTOR; } entry.pushKV("sigops", nTxSigOps); entry.pushKV("weight", GetTransactionWeight(tx)); transactions.push_back(entry); } UniValue aux(UniValue::VOBJ); aux.pushKV("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); result.pushKV("capabilities", aCaps); 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 ThresholdState::DEFINED: case ThresholdState::FAILED: // Not exposed to GBT at all break; case ThresholdState::LOCKED_IN: // Ensure bit is set in block version pblock->nVersion |= VersionBitsMask(consensusParams, pos); // FALL THROUGH to get vbavailable set... case ThresholdState::STARTED: { const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos]; vbavailable.pushKV(gbt_vb_name(pos), consensusParams.vDeployments[pos].bit); if (setClientRules.find(vbinfo.name) == setClientRules.end()) { if (!vbinfo.gbt_force) { // If the client doesn't support this, don't indicate it in the [default] version pblock->nVersion &= ~VersionBitsMask(consensusParams, pos); } } break; } case ThresholdState::ACTIVE: { // Add to rules only const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos]; aRules.push_back(gbt_vb_name(pos)); if (setClientRules.find(vbinfo.name) == setClientRules.end()) { // Not supported by the client; make sure it's safe to proceed if (!vbinfo.gbt_force) { // If we do anything other than throw an exception here, be sure version/force isn't sent to old clients throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Support for '%s' rule requires explicit client support", vbinfo.name)); } } break; } } } result.pushKV("version", pblock->nVersion); result.pushKV("rules", aRules); result.pushKV("vbavailable", vbavailable); result.pushKV("vbrequired", int(0)); if (nMaxVersionPreVB >= 2) { // If VB is supported by the client, nMaxVersionPreVB is -1, so we won't get here // Because BIP 34 changed how the generation transaction is serialized, we can only use version/force back to v2 blocks // This is safe to do [otherwise-]unconditionally only because we are throwing an exception above if a non-force deployment gets activated // Note that this can probably also be removed entirely after the first BIP9 non-force deployment (ie, probably segwit) gets activated aMutable.push_back("version/force"); } result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex()); result.pushKV("transactions", transactions); result.pushKV("coinbaseaux", aux); result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue); result.pushKV("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)); result.pushKV("target", hashTarget.GetHex()); result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1); result.pushKV("mutable", aMutable); result.pushKV("noncerange", "00000000ffffffff"); int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST; int64_t nSizeLimit = MAX_BLOCK_SERIALIZED_SIZE; if (fPreSegWit) { assert(nSigOpLimit % WITNESS_SCALE_FACTOR == 0); nSigOpLimit /= WITNESS_SCALE_FACTOR; assert(nSizeLimit % WITNESS_SCALE_FACTOR == 0); nSizeLimit /= WITNESS_SCALE_FACTOR; } result.pushKV("sigoplimit", nSigOpLimit); result.pushKV("sizelimit", nSizeLimit); if (!fPreSegWit) { result.pushKV("weightlimit", (int64_t)MAX_BLOCK_WEIGHT); } result.pushKV("curtime", pblock->GetBlockTime()); result.pushKV("bits", strprintf("%08x", pblock->nBits)); result.pushKV("height", (int64_t)(pindexPrev->nHeight+1)); if (!pblocktemplate->vchCoinbaseCommitment.empty() && fSupportsSegwit) { result.pushKV("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end())); } return result; }
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) { // Make sure skipping validation of transactions that were // validated going into the memory pool does not allow // double-spends in blocks to pass validation when they should not. CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; // Create a double-spend of mature coinbase txn: std::vector<CMutableTransaction> spends; spends.resize(2); for (int i = 0; i < 2; i++) { spends[i].nVersion = 1; spends[i].vin.resize(1); spends[i].vin[0].prevout.hash = m_coinbase_txns[0]->GetHash(); spends[i].vin[0].prevout.n = 0; spends[i].vout.resize(1); spends[i].vout[0].nValue = 11*CENT; spends[i].vout[0].scriptPubKey = scriptPubKey; // Sign: std::vector<unsigned char> vchSig; uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, 0, SigVersion::BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); spends[i].vin[0].scriptSig << vchSig; } CBlock block; // Test 1: block with both of those transactions should be rejected. block = CreateAndProcessBlock(spends, scriptPubKey); { LOCK(cs_main); BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); } // Test 2: ... and should be rejected if spend1 is in the memory pool BOOST_CHECK(ToMemPool(spends[0])); block = CreateAndProcessBlock(spends, scriptPubKey); { LOCK(cs_main); BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); } mempool.clear(); // Test 3: ... and should be rejected if spend2 is in the memory pool BOOST_CHECK(ToMemPool(spends[1])); block = CreateAndProcessBlock(spends, scriptPubKey); { LOCK(cs_main); BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); } mempool.clear(); // Final sanity test: first spend in mempool, second in block, that's OK: std::vector<CMutableTransaction> oneSpend; oneSpend.push_back(spends[0]); BOOST_CHECK(ToMemPool(spends[1])); block = CreateAndProcessBlock(oneSpend, scriptPubKey); { LOCK(cs_main); BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash()); } // spends[1] should have been removed from the mempool when the // block with spends[0] is accepted: BOOST_CHECK_EQUAL(mempool.size(), 0U); }
// pindex must belong to the main branch, i.e. corresponding blocks must be connected // Returns a copy of the game state bool GetGameState (DatabaseSet& dbset, CBlockIndex *pindex, GameState &outState) { if (!pindex) { outState = GameState(); return true; } /* See if we have the block in the state cache. */ if (stateCache.query (*pindex->phashBlock, outState)) return true; // Get the latest saved state CGameDB gameDb("r", dbset.tx ()); if (gameDb.Read(pindex->nHeight, outState)) { if (outState.nHeight != pindex->nHeight) return error("GetGameState: wrong height"); if (outState.hashBlock != *pindex->phashBlock) return error("GetGameState: wrong hash"); return true; } if (!pindex->IsInMainChain()) return error("GetGameState called for non-main chain"); printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); printf("GetGameState: need to integrate state for height %d (current %d)\n", pindex->nHeight, nBestHeight); CBlockIndex *plast = pindex; GameState lastState; for (; plast->pprev; plast = plast->pprev) { if (stateCache.query (*plast->pprev->phashBlock, lastState)) break; if (gameDb.Read(plast->pprev->nHeight, lastState)) break; } printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); printf("GetGameState: last saved block has height %d\n", lastState.nHeight); // Integrate steps starting from the last saved state // FIXME: Might want to store intermediate steps in stateCache, too. loop { std::vector<CTransaction> vgametx; CBlock block; block.ReadFromDisk(plast); int64 nTax; if (!PerformStep (dbset.name (), lastState, &block, nTax, outState, vgametx)) return false; if (block.vgametx != vgametx) { printf("Error: GetGameState: computed vgametx is different from the stored one\n"); printf(" block %s (height = %d) vgametx:\n", block.GetHash().ToString().c_str(), plast->nHeight); BOOST_FOREACH (const CTransaction &tx, block.vgametx) { printf(" "); tx.print(); } printf(" computed vgametx (height = %d):\n", outState.nHeight); BOOST_FOREACH (const CTransaction &tx, vgametx) { printf(" "); tx.print(); } return false; }