// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2022 The Limenka developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef LIMENKA_PRIMITIVES_BLOCK_H #define LIMENKA_PRIMITIVES_BLOCK_H #include #include #include #include #include /** Nodes collect new transactions into a block, hash them into a hash tree, * and scan through nonce values to make the block's hash satisfy proof-of-work * requirements. When they solve the proof-of-work, they broadcast the block * to everyone and the block is added to the block chain. The first transaction * in the block is a special one that creates a new coin owned by the creator * of the block. */ class CBlockHeader { public: // header int32_t nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; uint32_t nTime; uint32_t nBits; uint32_t nNonce; CBlockHeader() { SetNull(); } SERIALIZE_METHODS(CBlockHeader, obj) { READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, obj.nTime, obj.nBits, obj.nNonce); } void SetNull() { nVersion = 0; hashPrevBlock.SetNull(); hashMerkleRoot.SetNull(); nTime = 0; nBits = 0; nNonce = 0; } bool IsNull() const { return (nBits == 0); } uint256 GetHash() const; NodeSeconds Time() const { return NodeSeconds{std::chrono::seconds{nTime}}; } int64_t GetBlockTime() const { return (int64_t)nTime; } }; /** Fork block subsidy: time-proportional, uncapped. * R(e) = R_full * e / 600 where R_full is the halved base subsidy * (halving counted in aggregate fork seconds). At e = 600 the block * pays exactly the parent-chain subsidy; early blocks pay * proportionally less, late blocks proportionally more (catch-up). * The telescoping sum of e over all blocks equals elapsed time, so * total issuance is exactly parity regardless of cadence. * e: measured interval (nTime - prev nTime, seconds) * nAggregateSeconds: total fork seconds emitted so far * nSubsidyHalvingInterval: blocks-per-halving (210000) */ inline CAmount GetForkBlockSubsidy(int64_t e, int64_t nAggregateSeconds, int nSubsidyHalvingInterval) { int64_t halvings = nAggregateSeconds / (600 * nSubsidyHalvingInterval); CAmount nSubsidy = 50 * COIN; if (halvings >= 63) return 0; // shift past the word width would be UB nSubsidy >>= halvings; if (nSubsidy == 0) return 0; return (nSubsidy * e) / 600; } /** Fork block payload weight limit: time-proportional, uncapped. * payload = S_max * e / 600 (header+coinbase subtracted by the * caller). A late block can clear the backlog accumulated during a * stall. */ inline int64_t GetForkPayloadWeightLimit(int64_t e, int64_t nMaxPayloadWeight) { return (nMaxPayloadWeight * e) / 600; } class CBlock : public CBlockHeader { public: // network and disk std::vector vtx; // Memory-only flags for caching expensive checks mutable bool fChecked; // CheckBlock() mutable bool m_checked_witness_commitment{false}; // CheckWitnessCommitment() mutable bool m_checked_merkle_root{false}; // CheckMerkleRoot() CBlock() { SetNull(); } CBlock(const CBlockHeader &header) { SetNull(); *(static_cast(this)) = header; } SERIALIZE_METHODS(CBlock, obj) { READWRITE(AsBase(obj), obj.vtx); } void SetNull() { CBlockHeader::SetNull(); vtx.clear(); fChecked = false; m_checked_witness_commitment = false; m_checked_merkle_root = false; } CBlockHeader GetBlockHeader() const { CBlockHeader block; block.nVersion = nVersion; block.hashPrevBlock = hashPrevBlock; block.hashMerkleRoot = hashMerkleRoot; block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; return block; } std::string ToString() const; }; /** Describes a place in the block chain to another node such that if the * other node doesn't have the same branch, it can find a recent common trunk. * The further back it is, the further before the fork it may be. */ struct CBlockLocator { /** Historically CBlockLocator's version field has been written to network * streams as the negotiated protocol version and to disk streams as the * client version, but the value has never been used. * * Hard-code to the highest protocol version ever written to a network stream. * SerParams can be used if the field requires any meaning in the future, **/ static constexpr int DUMMY_VERSION = 70016; std::vector vHave; CBlockLocator() = default; explicit CBlockLocator(std::vector&& have) : vHave(std::move(have)) {} SERIALIZE_METHODS(CBlockLocator, obj) { int nVersion = DUMMY_VERSION; READWRITE(nVersion); READWRITE(obj.vHave); } void SetNull() { vHave.clear(); } bool IsNull() const { return vHave.empty(); } }; #endif // LIMENKA_PRIMITIVES_BLOCK_H