// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2013 The Bitcoin Core developers // Copyright (c) 2019-2020 The Hush developers // Distributed under the GPLv3 software license, see the accompanying // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ #ifndef BITCOIN_PRIMITIVES_BLOCK_H #define BITCOIN_PRIMITIVES_BLOCK_H #include "primitives/transaction.h" //#include "primitives/nonce.h" #include "serialize.h" #include "uint256.h" #include "arith_uint256.h" /** 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 static const size_t HEADER_SIZE=4+32+32+32+4+4+32; // excluding Equihash solution static const int32_t CURRENT_VERSION=4; static uint256 (CBlockHeader::*hashFunction)() const; static void SetHashAlgo(); int32_t nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; uint256 hashFinalSaplingRoot; uint32_t nTime; uint32_t nBits; uint256 nNonce; std::vector nSolution; CBlockHeader() { SetNull(); } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); READWRITE(hashPrevBlock); READWRITE(hashMerkleRoot); READWRITE(hashFinalSaplingRoot); READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); READWRITE(nSolution); } void SetNull() { nVersion = CBlockHeader::CURRENT_VERSION; hashPrevBlock.SetNull(); hashMerkleRoot.SetNull(); hashFinalSaplingRoot.SetNull(); nTime = 0; nBits = 0; nNonce = uint256(); nSolution.clear(); } bool IsNull() const { return (nBits == 0); } uint256 GetHash() const { return (this->*hashFunction)(); } uint256 GetSHA256DHash() const; static void SetSHA256DHash(); int64_t GetBlockTime() const { return (int64_t)nTime; } }; // this class is used to address the type mismatch that existed between nodes, where block headers // were being serialized by senders as CBlock and deserialized as CBlockHeader + an assumed extra // compact value. although it was working, I made this because it did break, and makes the connection // between CBlock and CBlockHeader more brittle. // by using this intentionally specified class instead, we remove an instability in the code that could break // due to unrelated changes, but stay compatible with the old method. class CNetworkBlockHeader : public CBlockHeader { public: std::vector compatVec; CNetworkBlockHeader() : CBlockHeader() { SetNull(); } CNetworkBlockHeader(const CBlockHeader &header) { SetNull(); *((CBlockHeader*)this) = header; } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(*(CBlockHeader*)this); READWRITE(compatVec); } void SetNull() { CBlockHeader::SetNull(); compatVec.clear(); } }; class CBlock : public CBlockHeader { public: // network and disk std::vector vtx; // memory only mutable std::vector vMerkleTree; CBlock() { SetNull(); } CBlock(const CBlockHeader &header) { SetNull(); *((CBlockHeader*)this) = header; } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(*(CBlockHeader*)this); READWRITE(vtx); } void SetNull() { CBlockHeader::SetNull(); vtx.clear(); vMerkleTree.clear(); } CBlockHeader GetBlockHeader() const { CBlockHeader block; block.nVersion = nVersion; block.hashPrevBlock = hashPrevBlock; block.hashMerkleRoot = hashMerkleRoot; block.hashFinalSaplingRoot = hashFinalSaplingRoot; block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; block.nSolution = nSolution; return block; } // Build the in-memory merkle tree for this block and return the merkle root. // If non-NULL, *mutated is set to whether mutation was detected in the merkle // tree (a duplication of transactions in the block leading to an identical // merkle root). uint256 BuildMerkleTree(bool* mutated = NULL) const; std::vector GetMerkleBranch(int nIndex) const; static uint256 CheckMerkleBranch(uint256 hash, const std::vector& vMerkleBranch, int nIndex); std::string ToString() const; }; uint256 BuildMerkleTree(bool* fMutated, const std::vector leaves, std::vector &vMerkleTree); std::vector GetMerkleBranch(int nIndex, int nLeaves, const std::vector &vMerkleTree); /** * Custom serializer for CBlockHeader that omits the nonce and solution, for use * as input to Equihash. */ class CEquihashInput : private CBlockHeader { public: CEquihashInput(const CBlockHeader &header) { CBlockHeader::SetNull(); *((CBlockHeader*)this) = header; } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); READWRITE(hashPrevBlock); READWRITE(hashMerkleRoot); READWRITE(hashFinalSaplingRoot); READWRITE(nTime); READWRITE(nBits); } }; /** 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 { std::vector vHave; CBlockLocator() {} CBlockLocator(const std::vector& vHaveIn) { vHave = vHaveIn; } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { int nVersion = s.GetVersion(); if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); READWRITE(vHave); } void SetNull() { vHave.clear(); } bool IsNull() const { return vHave.empty(); } friend bool operator==(const CBlockLocator& a, const CBlockLocator& b) { return (a.vHave == b.vHave); } }; #endif // BITCOIN_PRIMITIVES_BLOCK_H