diff --git a/src/Makefile.am b/src/Makefile.am index c5eddc6cf05..81700addf3d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -159,6 +159,7 @@ BITCOIN_CORE_H = \ rpc/util.h \ scheduler.h \ script/descriptor.h \ + script/generic.hpp \ script/ismine.h \ script/sigcache.h \ script/sign.h \ diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index b17ff3507d9..2f756f5467a 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -43,7 +43,13 @@ uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const uint256& txhash) const { return SipHashUint256(shorttxidk0, shorttxidk1, txhash) & 0xffffffffffffL; } - +std::vector PartiallyDownloadedBlock::GetAvailableTx() { + std::vector found_tx; + for (unsigned int i = 0; i < txn_available.size(); i++) { + if (txn_available[i]) found_tx.push_back(txn_available[i]); + } + return found_tx; +} ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector>& extra_txn) { if (cmpctblock.header.IsNull() || (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty())) @@ -173,7 +179,7 @@ bool PartiallyDownloadedBlock::IsTxAvailable(size_t index) const { return txn_available[index] != nullptr; } -ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector& vtx_missing) { +ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector& vtx_missing, bool check_pow) { assert(!header.IsNull()); uint256 hash = header.GetHash(); block = header; @@ -197,7 +203,7 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector< return READ_STATUS_INVALID; CValidationState state; - if (!CheckBlock(block, state, Params().GetConsensus())) { + if (!CheckBlock(block, state, Params().GetConsensus(), check_pow)) { // TODO: We really want to just check merkle tree manually here, // but that is expensive, and CheckBlock caches a block's // "checked-status" (in the CBlock?). CBlock should be able to diff --git a/src/blockencodings.h b/src/blockencodings.h index fad1f56f547..75c9c698bf5 100644 --- a/src/blockencodings.h +++ b/src/blockencodings.h @@ -200,10 +200,11 @@ class PartiallyDownloadedBlock { CBlockHeader header; explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {} + std::vector GetAvailableTx(); // extra_txn is a list of extra transactions to look at, in form ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector>& extra_txn); bool IsTxAvailable(size_t index) const; - ReadStatus FillBlock(CBlock& block, const std::vector& vtx_missing); + ReadStatus FillBlock(CBlock& block, const std::vector& vtx_missing, bool check_pow = true); }; #endif // BITCOIN_BLOCKENCODINGS_H diff --git a/src/chain.cpp b/src/chain.cpp index d462f94ab5e..8e60397eff3 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -120,6 +120,11 @@ void CBlockIndex::BuildSkip() arith_uint256 GetBlockProof(const CBlockIndex& block) { + // All valid signed blocks have "weight" 1 + if (g_signed_blocks) { + return 1; + } + arith_uint256 bnTarget; bool fNegative; bool fOverflow; diff --git a/src/chain.h b/src/chain.h index 01011d54f19..e02ebf7d148 100644 --- a/src/chain.h +++ b/src/chain.h @@ -212,6 +212,7 @@ class CBlockIndex uint32_t nTime; uint32_t nBits; uint32_t nNonce; + CProof proof; //! (memory only) Sequential id assigned to distinguish order in which blocks are received. int32_t nSequenceId; @@ -240,6 +241,7 @@ class CBlockIndex nTime = 0; nBits = 0; nNonce = 0; + proof.SetNull(); } CBlockIndex() @@ -256,6 +258,7 @@ class CBlockIndex nTime = block.nTime; nBits = block.nBits; nNonce = block.nNonce; + proof = block.proof; } CDiskBlockPos GetBlockPos() const { @@ -286,6 +289,7 @@ class CBlockIndex block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; + block.proof = proof; return block; } @@ -405,6 +409,7 @@ class CDiskBlockIndex : public CBlockIndex READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); + READWRITE(proof); } uint256 GetBlockHash() const @@ -416,6 +421,7 @@ class CDiskBlockIndex : public CBlockIndex 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 b8604e155cb..9a3367a5aaa 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -17,7 +17,7 @@ #include #include -static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) +static CBlock CreateGenesisBlock(const Consensus::Params& params, const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) { CMutableTransaction txNew; txNew.nVersion = 1; @@ -35,6 +35,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi genesis.vtx.push_back(MakeTransactionRef(std::move(txNew))); genesis.hashPrevBlock.SetNull(); genesis.hashMerkleRoot = BlockMerkleRoot(genesis); + genesis.proof = CProof(params.signblockscript, CScript()); return genesis; } @@ -49,11 +50,11 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi * CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B) * vMerkleTree: 4a5e1e */ -static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) +static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward, const Consensus::Params& params) { const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; - return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward); + return CreateGenesisBlock(params, pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward); } /** @@ -106,6 +107,7 @@ class CMainParams : public CChainParams { consensus.genesis_subsidy = 50*COIN; consensus.connect_genesis_outputs = false; + anyonecanspend_aremine = false; /** * The message start string is designed to be unlikely to occur in normal data. @@ -119,7 +121,7 @@ class CMainParams : public CChainParams { nDefaultPort = 8333; nPruneAfterHeight = 100000; - genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN); + genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN, consensus); consensus.hashGenesisBlock = genesis.GetHash(); assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")); assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); @@ -223,6 +225,7 @@ class CTestNetParams : public CChainParams { consensus.genesis_subsidy = 50*COIN; consensus.connect_genesis_outputs = false; + anyonecanspend_aremine = false; pchMessageStart[0] = 0x0b; pchMessageStart[1] = 0x11; @@ -231,7 +234,7 @@ class CTestNetParams : public CChainParams { nDefaultPort = 18333; nPruneAfterHeight = 1000; - genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN); + genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN, consensus); consensus.hashGenesisBlock = genesis.GetHash(); assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")); assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); @@ -315,6 +318,7 @@ class CRegTestParams : public CChainParams { consensus.genesis_subsidy = 50*COIN; consensus.connect_genesis_outputs = false; + anyonecanspend_aremine = false; pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xbf; @@ -325,7 +329,7 @@ class CRegTestParams : public CChainParams { UpdateVersionBitsParametersFromArgs(args); - genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN); + genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN, consensus); consensus.hashGenesisBlock = genesis.GetHash(); assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); @@ -436,9 +440,18 @@ class CCustomParams : public CRegTestParams { std::vector man_bytes = ParseHex(gArgs.GetArg("-con_mandatorycoinbase", "")); consensus.mandatory_coinbase_destination = CScript(man_bytes.begin(), man_bytes.end()); // Blank script allows any coinbase destination + // Block signing encumberance script, default of 51 aka OP_TRUE + std::vector sign_bytes = ParseHex(gArgs.GetArg("-signblockscript", "51")); + consensus.signblockscript = CScript(sign_bytes.begin(), sign_bytes.end()); + // Default signature size is the size of dummy push, and single 72 byte DER signature + consensus.max_block_signature_size = gArgs.GetArg("-con_max_block_sig_size", 74); + g_signed_blocks = gArgs.GetBoolArg("-con_signed_blocks", true); + // Custom chains connect coinbase outputs to db by default consensus.connect_genesis_outputs = gArgs.GetArg("-con_connect_coinbase", true); + anyonecanspend_aremine = gArgs.GetBoolArg("-anyonecanspendaremine", true); + nPruneAfterHeight = (uint64_t)args.GetArg("-npruneafterheight", nPruneAfterHeight); fDefaultConsistencyChecks = args.GetBoolArg("-fdefaultconsistencychecks", fDefaultConsistencyChecks); fMineBlocksOnDemand = args.GetBoolArg("-fmineblocksondemand", fMineBlocksOnDemand); @@ -476,7 +489,7 @@ class CCustomParams : public CRegTestParams { { strNetworkID = chain; UpdateFromArgs(args); - genesis = CreateGenesisBlock(strNetworkID.c_str(), CScript(OP_TRUE), 1296688602, 2, 0x207fffff, 1, 50 * COIN); + genesis = CreateGenesisBlock(consensus, strNetworkID.c_str(), CScript(OP_TRUE), 1296688602, 2, 0x207fffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); } }; diff --git a/src/chainparams.h b/src/chainparams.h index 19818b40aff..6692e07050e 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -80,6 +80,7 @@ class CChainParams const std::vector& FixedSeeds() const { return vFixedSeeds; } const CCheckpointData& Checkpoints() const { return checkpointData; } const ChainTxData& TxData() const { return chainTxData; } + bool anyonecanspend_aremine; protected: CChainParams() {} diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 8db4690b415..5114c760f67 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -26,6 +26,9 @@ void SetupChainParamsBaseOptions() gArgs.AddArg("-seednode=", "Use specified node as seed node. This option can be specified multiple times to connect to multiple nodes. (custom only)", true, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-con_blocksubsidy", "Defines the amount of block subsidy to start with, at genesis block.", false, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-con_connect_coinbase", "Connect outputs in genesis block to utxo database.", false, OptionsCategory::CHAINPARAMS); + gArgs.AddArg("-con_signed_blocks", "Signed blockchain. Uses input of `-signblockscript` to define what signatures are necessary to solve it.", false, OptionsCategory::CHAINPARAMS); + gArgs.AddArg("-signblockscript", "Signed blockchain enumberance. Only active when `-con_signed_blcoks` set to true.", false, OptionsCategory::CHAINPARAMS); + gArgs.AddArg("-con_max_block_sig_size", "Max allowed witness data for the signed block header.", false, OptionsCategory::CHAINPARAMS); } static std::unique_ptr globalChainBaseParams; diff --git a/src/consensus/params.h b/src/consensus/params.h index 7a217e755d8..69273c0d3fc 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -83,6 +83,9 @@ struct Params { CScript mandatory_coinbase_destination; CAmount genesis_subsidy; bool connect_genesis_outputs; + CScript signblockscript; + uint32_t max_block_signature_size; + // g_signed_blocks - Whether blocks are signed or not, get around circular dep }; } // namespace Consensus diff --git a/src/init.cpp b/src/init.cpp index 6a260108820..40c373eb599 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -495,6 +495,7 @@ void SetupServerArgs() CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), false, OptionsCategory::NODE_RELAY); gArgs.AddArg("-whitelistforcerelay", strprintf("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)", DEFAULT_WHITELISTFORCERELAY), false, OptionsCategory::NODE_RELAY); gArgs.AddArg("-whitelistrelay", strprintf("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), false, OptionsCategory::NODE_RELAY); + gArgs.AddArg("-anyonecanspendaremine", strprintf("Treat OP_TRUE outputs as funds for the wallet. Default true for custom chains."), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-blockmaxweight=", strprintf("Set maximum BIP141 block weight (default: %d)", DEFAULT_BLOCK_MAX_WEIGHT), false, OptionsCategory::BLOCK_CREATION); diff --git a/src/miner.cpp b/src/miner.cpp index 6d35f9ac37d..03353692a42 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -96,8 +96,9 @@ void BlockAssembler::resetBlock() nFees = 0; } -std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx) +std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx, int required_age_in_secs) { + assert(required_age_in_secs >= 0); int64_t nTimeStart = GetTimeMicros(); resetBlock(); @@ -142,9 +143,18 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc // transaction (which in most cases can be a no-op). fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()) && fMineWitnessTx; + if (g_signed_blocks) { + // Pad block weight by block proof fields (including upper-bound of signature) + nBlockWeight += chainparams.GetConsensus().signblockscript.size() * WITNESS_SCALE_FACTOR; + nBlockWeight += chainparams.GetConsensus().max_block_signature_size * WITNESS_SCALE_FACTOR; + // Reset block proof + ResetProof(*pblock); + ResetChallenge(*pblock, *pindexPrev, chainparams.GetConsensus()); + } + int nPackagesSelected = 0; int nDescendantsUpdated = 0; - addPackageTxs(nPackagesSelected, nDescendantsUpdated); + addPackageTxs(nPackagesSelected, nDescendantsUpdated, required_age_in_secs); int64_t nTime1 = GetTimeMicros(); @@ -168,7 +178,7 @@ 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->nBits = g_signed_blocks ? 0 : GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]); @@ -303,7 +313,7 @@ void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, std::ve // Each time through the loop, we compare the best transaction in // mapModifiedTxs with the next transaction in the mempool to decide what // transaction package to work on next. -void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated) +void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, int required_age_in_secs) { // mapModifiedTx will store sorted packages after they are modified // because some of their txs are already in the block @@ -359,6 +369,12 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda } } + // Skip transactions that are under X seconds in mempool + // required_age_in_secs value of 0 is considered "inactive", in case of mocktime + if (required_age_in_secs > 0 && iter->GetTime() > GetTime() - required_age_in_secs) { + continue; + } + // We skip mapTx entries that are inBlock, and mapModifiedTx shouldn't // contain anything that is inBlock. assert(!inBlock.count(iter)); diff --git a/src/miner.h b/src/miner.h index 8cdcf7133ba..814875f6a84 100644 --- a/src/miner.h +++ b/src/miner.h @@ -157,7 +157,7 @@ class BlockAssembler BlockAssembler(const CChainParams& params, const Options& options); /** Construct a new block template with coinbase to scriptPubKeyIn */ - std::unique_ptr CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx=true); + std::unique_ptr CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx=true, int required_wait=0); private: // utility functions @@ -170,7 +170,7 @@ class BlockAssembler /** Add transactions based on feerate including unconfirmed ancestors * Increments nPackagesSelected / nDescendantsUpdated with corresponding * statistics from the package selection (for logging statistics). */ - void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs); + void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, int required_wait=0) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs); // helper functions for addPackageTxs() /** Remove confirmed (inBlock) entries from given set */ diff --git a/src/pow.cpp b/src/pow.cpp index 1414d375649..5844a57bb5c 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -9,6 +9,22 @@ #include #include #include +#include