当前位置:首页 > 知识学习 > 详情

比特币源码(ma)学习笔记(二)

2025-06-24 18:01:02 阅读(21) 娱乐资讯网

本章介绍上一章交易(yi)创建后,比特币客户(hu)端进行数据序列化的(de)过程。

比特币(bi)客户端的所有序列化功(gong)能都在seriliaze.h中实现(xian),其中,CDataStream类是数据序列化的核心结(jie)构。

尚力财经小编2022比特币(bi)源码学习笔记(二)-娱乐资讯网

class CDATA stream { protected:typedef vector

vector _ type;vector _ type vch无符号int nReadPos短状态;短例外(wai)掩码;public:int nType;转换;//.}vch存储序列化数据(ju)。它是一个带有自定义内存分配器的(de)字符容器类型。当需要分配/释放内存时,容器的实现将调用内存(cun)分配器。内存分配(pei)器会在将内存释(shi)放给操作系统之前清除(chu)内存中的数据,防止机器(qi)的其他进程访问这些(xie)数据,从而保证数据存储的安(an)全性。这里不讨论这个内存分配(pei)器的实现,但是读者可(ke)以在serialize上找到,h NReadPos是vch读(du)取数据的起始位置。是状态错误标识符。此变(bian)量用于指示序列化/反序列(lie)化中可能出现的错误。Exceptmask是一个错误掩码。它被初始化为ios:badbit | ios:failbit。类似于state,它用于指示错误的种类。nType的值为SER_NETWORK、SER_DISK、SER_GETHASH、SER_SKIPSIG、SER_BLOCKHEADERONLY中的一个,其(qi)作用是通知CDataStream执行特定的序列化操作。这(zhe)五个符号在枚举(ju)类型中定义。每个符(fu)号都是int类型(4字节),其值是2的幂。enum {//primary actions SER _ NETWORK=(1 0),SER_DISK=(1 1),SER_GETHASH=(1 2),//modifiers SER_SKIPSIG=(1 16),SER_BLOCKHEADERONLY=(1 17),};n是转(zhuan)换数。

CDataStream:read()和CDataStream:write()成员函数CDataStream:read()和CDataStream:write()是用于序列化/反序列化CDataStream对象的低级函(han)数。CDataStream read(char* pch,int nSize) { //从缓冲区断言(yan)开始读取(nSize=0);unsigned int nReadPos next=nReadPos nSize;if(nReadPosNext=vch . size()){ if(nReadPosNext vch . size()){ setstate(IOs:fail bit,' CDATA stream:read():end of data ');memset(pch,0,nSize);nSize=vch . size()-nReadPos;} memcpy(pch,vch[nReadPos],nSize);nReadPos=0;vch . clear();返回(* this);} memcpy(pch,vch[nReadPos],nSize);nReadPos=nReadPosNext返回(hui)(* this);} CDATA stream Write(const char * PCH,int nSize) { //写(xie)到缓冲区断言的末(mo)尾(nSize=0);vch.insert(vch.end()、pch、PCH nSize);返回(hui)(* this);}计算要(yao)从vch中读取的数据(ju)的结束位置,unsigned int nReadPosNext?=nReadPos nSize .如果结束位置大于vch的大小(xiao),则当前没有足够的(de)数据来读取。在(zai)这种情况下,通(tong)过调用函数setState()将(jiang)状态设置为ios:failbit,并将所有零复制到pch。否(fou)则,调用memcpy(pch,vch[nReadPos],nSize)将(jiang)nSize个字符从(cong)vch的nReadPos位置开始复制到pch指向的预分配(pei)内存中。然后从nReadPos向前(qian)移动到下一个起(qi)始位置nReadPosNext(第22行(xing))。实现表明:1)从流中读取一(yi)段数据后,该段数据(ju)不能被再次读取;2)nReadPos是第一个有效数据的读取位(wei)置。CDataStream:write()非常(chang)简单。它将pch指向的nSize字符追加到vch的末尾(wei)。

宏READDATA()和WRITEDATA()

函数CDataStream:read()和CDataStream:write()用于序列化/反(fan)序列化原始类型(int、bool、unsigned long等。).为了序列(lie)化这些数据类型,指向这些类型的(de)指针将被转换为char*。因为(wei)这些类型的大小目前是已知的,所(suo)以它们可以从CDataStream中读取或写入(ru)字符缓冲区。用于引用这些函(han)数的两个宏被定义为(wei)帮助器。# DEFINE WRITE DATA (s,obj) S. WRITE ((char *) (obj),sizeof (obj)) # DEFINE READ DATA (s,obj) S. READ ((char *) (obj),sizeof (obj)) template inline void Serialize(Stream s,unsigned long a,int,int=0) { WRITEDATA(s,a);}

用自己的定义替(ti)换WRITEDATA(s,a)。接下来是扩(kuo)展的函数:

Template inline void serialize(streams s,unsigned long a,int,int=0) {s.write ((char *) (a),sizeof(a));}

这个(ge)函数接受一个无符号长整型(xing)参数a,获取它的内存地址,将(jiang)指针转换为char*并调用函数s.write()。

CDataStream中的运算(suan)符

CDataStream重载该运(yun)算符以进行序列化和反序列化(hua)。模板CDataStream运(yun)算符头文件serialize.h包含14个重载的全局函数,用于14种原始类型(char、short、int、long和long long以及char、float、double和bool的有符号和无符号版本)和6种复合类型(string、vector、pair、map、set和CScript)的6个重载版本。因此(ci),对于这些类型,可以简单地(di)使用接下来的代码来序列化/反序列化(hua)数据:CDATA stream ss(SER _ get hash);ss

obj 4;//deserialize

如果没有实现的类型匹(pi)配第二个参数obj,将调(diao)用接下来的泛型T全(quan)局函数。template inline void Serialize(Stream OS,const T a,long nType,int n VERSION=VERSION){ a . Serialize(OS,(int)nType,n VERSION);}

对(dui)于这个泛型版本,应该使用类型(xing)T来实现成员函数和签名T:Serialize(Stream,int,int)。它将通过. Serialize()调用。

如何实现一个类型的序列化

在前面的介绍中,泛型T需要实现以(yi)下三个成员函数进行序列(lie)化。unsigned int GetSerializeSize(int nType=0,int n VERSION=VERSION)const;void Serialize(Stream s,int nType=0,int n VERSION=VERSION)const;void Unserialize(Stream s,int nType=0,int n VERSION=VERSION);宏IMPLEMENT_SERIALIZE(statements)用于定(ding)义这三个函数的任(ren)何类型的实现。# define implements _ serialization(statements) signed int get serialize(int type=0,int n version=version)const { cs generationetserialize ser _ action; const bool fgetsize=true const bool fwrite=false const bool fread=false signed int insertsize=0; s。类型=类型: s。版本=版本: {语句} return nser size } template void serialization(stream s,int ntype=0,int n version=version)const { cseractivationsser _ action; const bool fgetsize=false const bool fwrite=true const bool fread=false signed int insertsize=0; {语句} } 模板无效重新(xin)初始化(Stream s,int ntype=0,int nversion=version) n重新初始化(hua)ser _ action const bool fgetsize=false const bool fwrite=false const bool fread=true signed int insertsize=0; {语(yu)句}}

以下例子示范怎(zen)样使用该宏。

#include #include "serialize.h"using namespace std;class AClass {public: AClass(int xin) : x(xin){}; int x; IMPLEMENT_SERIALIZE(READWRITE(this->x);)}int main() { CDataStream astream2; AClass aObj(200); //一个x为200的AClass类(lei)型对象 cout这段程序序列化/反序列化AClass对象。它将在屏幕上(shang)输出接下来的结果。

aObj=200a2=200

AClass的这三(san)个序列化/反序列化成员函数可以在一(yi)行代码中实现:

IMPLEMENT_SERIALIZE(READWRITE(this->x);)宏READWRITE()的定(ding)义如下#define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action))

该宏的展开被放在宏IMPLEMENT_SERIALIZE(statements)的全部三(san)个函数里。因此,它一次需要完成三件(jian)事情:1)返回(hui)序列化后数据的大小,2)序(xu)列化(写入)数据至(zhi)流;3)从流中反序列化(读(du)取)数据。参考宏IMPLEMENT_SERIALIZE(statements)中对这三个函数(shu)的定义。

想要(yao)了解宏READWRITE(obj)怎样工作,你首先需要明白(bai)它的完整形式当中的nSerSize,s,nType,nVersion和ser_action是怎(zen)么来的。它们全部来自宏(hong)IMPLEMENT_SERIALIZE(statements)的三个函数主体部分:nSerSize是一个unsigned int,在三个函数(shu)当中初始化为0;ser_action是一个对象在三个(ge)函数当中均有声明,但为三种(zhong)不同类型。它在三个函数当中分别为(wei)CSerActionGetSerializeSize、CSerActionSerialize和CSerActionUnserialize;s在第一个函数中(zhong)定义为ser_streamplaceholder类型。它是第一个传(chuan)入至另外两个函数的(de)参数,拥有参数类型Stream;nType和nVersion在三个函数中均为传入参(can)数。因此,一旦宏(hong)READWRITE()扩展至宏IMPLEMENT_SERIALIZE(),所有(you)它的符号都将被计算,因为它们已经(jing)存在于宏IMPLEMENT_SERIALIZE()的(de)主体中。READWRITE(obj)的扩展调用一个全局函数(shu)::SerReadWrite(s, (obj), nType, nVersion, ser_action)。这里是这个函数的全部(bu)三种版本。templateinline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action){ return ::GetSerializeSize(obj, nType, nVersion);}templateinline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action){ ::Serialize(s, obj, nType, nVersion); return 0;}templateinline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action){ ::Unserialize(s, obj,尚力财经小编2022 nType, nVersion); return 0;}

如(ru)你所见,函数::SerReadWrite()被重载为(wei)三种版本。取决于最后一个(ge)参数,它将会调分别用全局函(han)数::GetSerialize(),::Serialize()和::Unserialize();这三(san)个函数在前面章节已经介绍。

如果你检查三种(zhong)不同版本的::SerReadWrite()的最后一个(ge)参数,你会发现(xian)它们全部为空类型(xing)。这三种类型的唯一用途(tu)是区别::SerReadWrite()的三个版本(ben),继而被宏IMPLEMENT_SERIALIZE()定义的所有函数使用。

上一篇:either是什么意思(si)的简单介绍

下一篇:大盘蓝筹股(大盘蓝(lan)筹股推荐)

推荐阅读:

  • cpu后面的(de)k和f什么意思(cpu后边的k和f)

    cpu后面的(de)k和f什么意思(cpu后边的k和f)

    CPU一(yi)些人都只知道几代i3/几代i5/几代i7,对于其他信息知之(zhi)甚少,相信不少人身边都有一些“硬(ying)件白痴”,玩起软件的东西信手拈来(lai),可是一问他CPU型(xing)号是啥,总是只会说i5。那这CPU型号后面…
    2023-06-13 阅读(25)
  • 怎么判断仓鼠(shu)受了内伤(仓鼠受了内伤的表现)

    怎么判断仓鼠(shu)受了内伤(仓鼠受了内伤的表现)

    奋斗君一直以(yi)为自己是个坚定的猫痴,直到(dao)我无意中发现了推主mocomo2co2晒萌宠的一组图......飞翔的毛(mao)绒团子!没有一丝丝防备,就这样(yang)被萌了一脸血!这是什么?毛绒(rong)团子?完全没有抵抗力啊…
    2023-06-13 阅读(19)
  • 最担心(xin)的食品安全问题有哪些(请问最担心的食品安全问题是什么)

    最担心(xin)的食品安全问题有哪些(请问最担心的食品安全问题是什么)

    目前消费者最担心的食品安(an)全问题有哪些根据新华社的报道“四大食品(pin)安全问题最受消费(fei)者关心”,全文如下:中毒事件屡屡发生令人(ren)防不胜防,新技术影(ying)响食品品质和口感,环境恶化导致农牧(mu)…
    2023-06-13 阅读(22)
  • 雪中悍刀行舒(shu)羞(雪中悍刀行舒羞是好是坏)

    雪中悍刀行舒(shu)羞(雪中悍刀行舒羞是好是坏)

    《雪中悍刀行》舒羞(xiu)的扮演者是谁?《雪中悍刀行》舒羞的扮(ban)演者是张艺上。张艺上,1996年3月4日出(chu)生于重庆,中国内(nei)地女演员,就读于中央(yang)戏剧学院。2015年,参演个(ge)人首部电影《铁道飞虎…
    2023-06-13 阅读(31)
  • 欧义交易(yi)平台app最新版 欧义ok最新安卓v6.1.3

    欧义交易(yi)平台app最新版 欧义ok最新安卓v6.1.3

    欧意是一款绝对正规安全的(de)区块链app用户可以在平(ping)台上了解到超多关于币圈的信息,手(shou)机轻松注册,收益每天不断进入账户,轻松,是各位赚钱的神器。欧意交易所安卓版:点(dian)击进入欧意交易所ios版:…
    2023-06-13 阅读(21)