比特币源码学习0.13-数据结构-区块

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37847176/article/details/81874834

在了解挖矿前先来看下区块的结构。
在比特币的p2p网络中,每个节点都保存有一个区块链副本。所谓的区块链由相互连接的区块()所构成,每个区块中包含多笔交易,为了便于存储、搜索、读取在内存和磁盘中的区块和交易信息,比特币引入一些访问类,包括索引区块的CBlockIndex、CDiskBlockIndex 和索引交易。


CBlockHeader

CBlock的父类,所以先介绍CBlockHeader,这个类是区块头的数据结构

uint256: 256-bit opaque blob.
blob:binary large objects.

字段尺寸 描述 数据类型 说明
4 nVersion int32_t block的版本信息,基于创建该区块的软件版本
32 hashPrevBlock uint256 该区块前一区块的hash值
32 hashMerkleRoot uint256 与该区块相关的全部交易的hash(Merkle树),Merkle树是hash的二叉树,在比特币中使用两次SHA-256算法来生成Merkle树
4 nTime uint32_t 记录block创建时间的时间戳
4 nBits uint32_t 创建block的计算难度
4 nNonce uint32_t 用于生成这一block的Nonce值

主要看下这段代码的数据结构,函数比较简单

//block.h
/*网络中的节点将新的交易收集到块中,把他们散列到哈希树(Merkle树)中,然后遍历随机数以使得块的hash值满足工作量证明要求
*当节点找到满足要求的一个随机数,就把块广播给其节点,并添加到区块链上,每个区块的第一个交易都是coinbase交易。*/
class CBlockHeader
{
public:
    // header
    int32_t nVersion;
    uint256 hashPrevBlock;
    uint256 hashMerkleRoot;
    uint32_t nTime;
    uint32_t nBits;
    uint32_t nNonce;

    CBlockHeader()
    {
        SetNull();
    }

    ADD_SERIALIZE_METHODS;

    template <typename Stream, typename Operation>
    inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
        READWRITE(this->nVersion);
        READWRITE(hashPrevBlock);
        READWRITE(hashMerkleRoot);
        READWRITE(nTime);
        READWRITE(nBits);
        READWRITE(nNonce);
    }

    void SetNull()
    {
        nVersion = 0;
        hashPrevBlock.SetNull();
        hashMerkleRoot.SetNull();
        nTime = 0;
        nBits = 0;
        nNonce = 0;
    }

    bool IsNull() const
    {
        return (nBits == 0);
    }

    uint256 GetHash() const;

    int64_t GetBlockTime() const
    {
        return (int64_t)nTime;
    }
};

GetHash()

//1. blocp.cpp
uint256 CBlockHeader::GetHash() const
{
    return SerializeHash(*this);
}
//2. hash.h
/** Compute the 256-bit hash of an object's serialization. */
template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
{
    CHashWriter ss(nType, nVersion);
    ss << obj;
    return ss.GetHash();
}
//3. class CHashWriter 
 // invalidates the object
    uint256 GetHash() {
        uint256 result;
        ctx.Finalize((unsigned char*)&result);//ctx是v
        return result;
    }

可以看到对区块获取hash值是使用区块头的数据计算所得,不包括交易容器vtx,当然区块的hash与交易是有关的 ,hashMerkleRoot是区块头的一部分,该成员变量由函数BlockMerkleRoot计算所得,用到的参数是block.vtx,也就是交易部分

//merkle.h
/*
 * Compute the Merkle root of the transactions in a block.
 * *mutated is set to true if a duplicated subtree was found.
 */
uint256 BlockMerkleRoot(const CBlock& block, bool* mutated = NULL);

关于merkle树,可以参考src/consensus/目录下的merkle.cpp的注释


CBlock

CBlock公有继承类CBlockHeader

字段尺寸 描述 数据类型 说明
80 CBlockHeader 区块头
vtx vector<CTransaction> 所有的交易
fChecked mutable bool 交易是否验证过并构成Merkle树
//block.h
class CBlock : public CBlockHeader
{
public:
    // network and disk
    std::vector<CTransaction> vtx;

    // memory only
    mutable bool fChecked;

    CBlock()
    {
        SetNull();
    }

    CBlock(const CBlockHeader &header)
    {
        SetNull();
        *((CBlockHeader*)this) = header;
    }

    ADD_SERIALIZE_METHODS;

    template <typename Stream, typename Operation>
    inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
        READWRITE(*(CBlockHeader*)this);
        READWRITE(vtx);
    }

    void SetNull()
    {
        CBlockHeader::SetNull();
        vtx.clear();
        fChecked = 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;
};

CBlockIndex

区块链是树状结构,从根部的起源块开始,每个块可能具有多个候选者作为下一个块。 块索引可能有多个pprev指向它,但最多其中一个可以是当前活动分支的一部分。

class CBlockIndex
{
public:
    //! pointer to the hash of the block, if any. Memory is owned by this CBlockIndex
    const uint256* phashBlock;//指向区块hash的指针

    //! pointer to the index of the predecessor of this block
    CBlockIndex* pprev;//指向当前区块前一区块索引的指针

    //! pointer to the index of some further predecessor of this block
    CBlockIndex* pskip;//指向前几区块

    //! height of the entry in the chain. The genesis block has height 0
    int nHeight;

    //! Which # file this block is stored in (blk?????.dat)
    int nFile;//这个区块保存在哪个文件

    //! Byte offset within blk?????.dat where this block's data is stored
    unsigned int nDataPos;

    //! Byte offset within rev?????.dat where this block's undo data is stored
    unsigned int nUndoPos;

    //! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block
    arith_uint256 nChainWork;

    //! Number of transactions in this block.
    //! Note: in a potential headers-first mode, this number cannot be relied upon
    unsigned int nTx;//交易数

    //! (memory only) Number of transactions in the chain up to and including this block.
    //! This value will be non-zero only if and only if transactions for this block and all its parents are available.
    //! Change to 64-bit type when necessary; won't happen before 2030
    unsigned int nChainTx;

    //! Verification status of this block. See enum BlockStatus
    unsigned int nStatus;

    //! block header 区块头结构类似
    int nVersion;
    uint256 hashMerkleRoot;
    unsigned int nTime;
    unsigned int nBits;
    unsigned int nNonce;

    //! (memory only) Sequential id assigned to distinguish order in which blocks are received.
  uint32_t nSequenceId;
    ···

下面来看继承自类CTransaction的两个类

CMerkleTx

一个交易带有一个能把它连接到区块链上的 merkle 分支

/** A transaction with a merkle branch linking it to the block chain. */
class CMerkleTx : public CTransaction
{
private:
  /** Constant used in hashBlock to indicate tx has been abandoned */
    static const uint256 ABANDON_HASH;

public:
    uint256 hashBlock;

    /* An nIndex == -1 means that hashBlock (in nonzero) refers to the earliest
     * block in the chain we know this or any in-wallet dependency conflicts
     * with. Older clients interpret nIndex == -1 as unconfirmed for backward
     * compatibility.
     */
    int nIndex;

    CMerkleTx()
    {
        Init();
    }

    CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
    {
        Init();
    }

    void Init()
    {
        hashBlock = uint256();
        nIndex = -1;
    }

    ADD_SERIALIZE_METHODS;

    template <typename Stream, typename Operation>
    inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
        std::vector<uint256> vMerkleBranch; // For compatibility with older versions.
        READWRITE(*(CTransaction*)this);
        nVersion = this->nVersion;
        READWRITE(hashBlock);
        READWRITE(vMerkleBranch);
        READWRITE(nIndex);
    }

    int SetMerkleBranch(const CBlock& block);

    /**
     * Return depth of transaction in blockchain:
     * <0  : conflicts with a transaction this deep in the blockchain
     *  0  : in memory pool, waiting to be included in a block
     * >=1 : this many blocks deep in the main chain
     */
    int GetDepthInMainChain(const CBlockIndex* &pindexRet) const;
    int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
    bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; }
    int GetBlocksToMaturity() const;
    /** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
    bool AcceptToMemoryPool(bool fLimitFree, const CAmount nAbsurdFee, CValidationState& state);
    bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
    bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
    void setAbandoned() { hashBlock = ABANDON_HASH; }
};

这个类可以方便的验证一个交易是否属于一个区块。


CWalletTx

包含大量附加信息的交易,只有(这笔交易)所有者关心。 它包括将其链接回块链所需的任何未记录的事务。

//wallet.h
/** 
 * A transaction with a bunch of additional info that only the owner cares about.
 * It includes any unrecorded transactions needed to link it back to the block chain.
 */
class CWalletTx : public CMerkleTx
{
private:
    const CWallet* pwallet;

public:
    mapValue_t mapValue;
    std::vector<std::pair<std::string, std::string> > vOrderForm;
    unsigned int fTimeReceivedIsTxTime;
    unsigned int nTimeReceived; //!< time received by this node
    unsigned int nTimeSmart;
    char fFromMe;
    std::string strFromAccount;
    int64_t nOrderPos; //!< position in ordered transaction list
···

猜你喜欢

转载自blog.csdn.net/m0_37847176/article/details/81874834