编程语言
首页 > 编程语言> > 比特币源码分析之序列化

比特币源码分析之序列化

作者:互联网

比特币源码分析之序列化

 

https://blog.csdn.net/guoguangwu/article/details/88874251

比特币的数据存储(文件或者内存数据库)都会使用到序列化、反序列化。

如果自定义一些结构的话,涉及到持久化就需要在这个类中实现序列化反序列化的实现。

比特币对基本类型都有序列化,比如int、std::string、uint256、vector都有实现,几乎不需要自己去添加基础类型序列化函数。

比特币的序列化、反序列接口都是函数模板,第一个参数是具体的进行序列化的对象, 第二个参数是序列化到哪里磁盘文件、网络、哈希等。

序列化反序列化的时候可以使用 操作符 <<  >>进行。

下面以区块头的结构进行举例分析,底层实现涉及到宏定义。


 
  1. class CBlockHeader

  2. {

  3. public:

  4. // header

  5. int32_t nVersion;

  6. uint256 hashPrevBlock;

  7. uint256 hashMerkleRoot;

  8. uint32_t nTime;

  9. uint32_t nBits;

  10. uint32_t nNonce;

  11.  
  12. CBlockHeader()

  13. {

  14. SetNull();

  15. }

  16.  
  17. /* 这个宏定义了两个函数模板:序列化与反序列化, 下面会给出定义的代码 */

  18. ADD_SERIALIZE_METHODS;

  19.  
  20. /*

  21. * 在序列化与反序列化的函数中,会通过this指针调用这个函数进行实际的序列化与反序列化

  22. * 通过第二个参数 ser_action进行区分是序列化还是反序列化

  23. */

  24. template <typename Stream, typename Operation>

  25. inline void SerializationOp(Stream& s, Operation ser_action) {

  26. READWRITE(this->nVersion);

  27. READWRITE(hashPrevBlock);

  28. READWRITE(hashMerkleRoot);

  29. READWRITE(nTime);

  30. READWRITE(nBits);

  31. READWRITE(nNonce);

  32. }

  33. ....

  34. };

  35.  
  36. /* 定义的序列化反序列化函数 */

  37. #define ADD_SERIALIZE_METHODS \

  38. template<typename Stream> \

  39. void Serialize(Stream& s) const { \

  40. NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize()); \

  41. } \

  42. template<typename Stream> \

  43. void Unserialize(Stream& s) { \

  44. SerializationOp(s, CSerActionUnserialize()); \

  45. }

  46.  
  47.  
  48. /*实际序列化反序列化的调用*/

  49. #define READWRITE(obj) (::SerReadWrite(s, (obj), ser_action))

  50.  
  51.  
  52. /* 序列化 反序列化的实现 */

  53. template<typename Stream, typename T>

  54. inline void SerReadWrite(Stream& s, const T& obj, CSerActionSerialize ser_action)

  55. {

  56. /* 根据obj的是积类型调用对应的序列化函数模板uint8_t、uint16_t、std::basic_string等*/

  57. ::Serialize(s, obj);

  58. }

  59.  
  60. template<typename Stream, typename T>

  61. inline void SerReadWrite(Stream& s, T& obj, CSerActionUnserialize ser_action)

  62. {

  63. ::Unserialize(s, obj);

  64. }

  65.  
  66.  
  67.  

使用序列化与反序列化的时候需要注意一点,如果子类进行序列化的时候,父类中也有序列化与反序列化的需求,需要对this指针进行强制类型转换,然后调用父类的相关函数,否则子类不会自动调用父类的相应函数,出现异常。

 

比如下面的区块序列化实现


 
  1. class CBlock : public CBlockHeader

  2. {

  3. public:

  4. // network and disk

  5. std::vector<CTransactionRef> vtx;

  6.  
  7. // memory only

  8. mutable bool fChecked;

  9.  
  10. CBlock()

  11. {

  12. SetNull();

  13. }

  14.  
  15. CBlock(const CBlockHeader &header)

  16. {

  17. SetNull();

  18. *((CBlockHeader*)this) = header;

  19. }

  20.  
  21. ADD_SERIALIZE_METHODS;

  22.  
  23. template <typename Stream, typename Operation>

  24. inline void SerializationOp(Stream& s, Operation ser_action) {

  25. /* 先序列化反序列化父类的信息,然后再处理自己的信息*/

  26. READWRITE(*(CBlockHeader*)this);

  27. READWRITE(vtx);

  28. }

  29.  
  30. void SetNull()

  31. {

  32. CBlockHeader::SetNull();

  33. vtx.clear();

  34. fChecked = false;

  35. }

  36.  
  37. CBlockHeader GetBlockHeader() const

  38. {

  39. CBlockHeader block;

  40. block.nVersion = nVersion;

  41. block.hashPrevBlock = hashPrevBlock;

  42. block.hashMerkleRoot = hashMerkleRoot;

  43. block.nTime = nTime;

  44. block.nBits = nBits;

  45. block.nNonce = nNonce;

  46. return block;

  47. }

  48.  
  49. std::string ToString() const;

  50. };

上面是一种实现方式。

接下来分析讲一下另一种实现方式(比特币的交易的序列化与反序列化)。比特币的交易有两种类型struct CMutableTransaction、class CTransaction,第一种是可以变化的,会用来创建交易使用。


 
  1. /*

  2. * 内部直接定义两个函数Serialize, Unserialize,其实和前面的一致,只不过交易的序列化逻辑比较复杂

  3. * 单独写比较方便,内部有很多逻辑处理、条件判断,直接通过READWRITE很难处理,单独写了两个函数模板

  4. */

  5. struct CMutableTransaction

  6. {

  7. int32_t nVersion;

  8. std::vector<CTxIn> vin;

  9. std::vector<CTxOut> vout;

  10. uint32_t nLockTime;

  11.  
  12. CMutableTransaction();

  13. CMutableTransaction(const CTransaction& tx);

  14.  
  15. template <typename Stream>

  16. inline void Serialize(Stream& s) const {

  17. SerializeTransaction(*this, s);

  18. }

  19.  
  20.  
  21. template <typename Stream>

  22. inline void Unserialize(Stream& s) {

  23. UnserializeTransaction(*this, s);

  24. }

  25.  
  26. template <typename Stream>

  27. CMutableTransaction(deserialize_type, Stream& s) {

  28. Unserialize(s);

  29. }

  30.  
  31. ...

  32. };

  33.  
  34. /*这是交易的序列化的实现, 有判定是否是隔离见证,所以需要单独拿出来自己写*/

  35. template<typename Stream, typename TxType>

  36. inline void SerializeTransaction(const TxType& tx, Stream& s) {

  37. const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);

  38.  
  39. s << tx.nVersion;

  40. unsigned char flags = 0;

  41. // Consistency check

  42. if (fAllowWitness) {

  43. /* Check whether witnesses need to be serialized. */

  44. if (tx.HasWitness()) {

  45. flags |= 1;

  46. }

  47. }

  48. if (flags) {

  49. /* Use extended format in case witnesses are to be serialized. */

  50. std::vector<CTxIn> vinDummy;

  51. s << vinDummy;

  52. s << flags;

  53. }

  54. s << tx.vin;

  55. s << tx.vout;

  56. if (flags & 1) {

  57. for (size_t i = 0; i < tx.vin.size(); i++) {

  58. s << tx.vin[i].scriptWitness.stack;

  59. }

  60. }

  61. s << tx.nLockTime;

  62. }

如果需要在比特币的代码里面实现自己的业务逻辑,也涉及到序列化反序列化,里面的逻辑比较复杂,建议参考交易的处理方式。自己单独写个函数来实现相关操作

标签:const,Stream,比特,READWRITE,void,源码,template,序列化
来源: https://blog.csdn.net/TuxedoLinux/article/details/89639136