2 14198
本章繼上一章交易建立之後介紹位元幣客戶端序列化資料的過程。
位元幣客戶端所有的序列化函式均在seriliaze.h中實現。其中,cdatastream類是資料序列化的核心結構。
cdatastream擁有乙個字元類容器用來存放序列化之後的資料。它結合乙個容器型別和乙個流(stream)介面以處理資料。它使用6個成員函式實現這一功能:
class cdatastream
enum成員函式cdatastream::read()和cdatastream::write()是用於執行序列化/反序列化cdatastream物件的低階函式。;
cdatastream& read(char* pch, int nsize)cdatastream::read()從cdatastream複製nsize個字元到乙個由char* pch所指向的記憶體空間。以下是它的實現過程:memcpy(pch, &vch[nreadpos], nsize);
nreadpos = 0;
vch.clear();
return (*this);
}memcpy(pch, &vch[nreadpos], nsize);
nreadpos = nreadposnext;
return (*this);
}cdatastream& write(const char* pch, int nsize)
該實現表明1)當一段資料被從流中讀取之後,該段資料無法被再次讀取;2)nreadpos是第乙個有效資料的讀取位置。
cdatastream::write()非常簡單。它將由pch指向的nsize個字元附加到vch的結尾。
函式cdatastream::read()與cdatastream::write()的作用是序列化/反序列化原始型別(int,bool,unsigned long等)。為了序列化這些資料型別,這些型別的指標將被轉換為char*。由於這些型別的大小目前已知,它們可以從cdatastream中讀取或者寫入至字元緩衝。兩個用於引用這些函式的巨集被定義為助手。
#define writedata(s, obj) s.write((char*)&(obj), sizeof(obj))這裡是如何使用這些巨集的例子。下面的函式將序列化乙個unsigned long型別。#define readdata(s, obj) s.read((char*)&(obj), sizeof(obj))
templateinline void serialize(stream& s, unsigned long a, int, int=0)把writedata(s, a)用自身的定義取代,以下是展開以後的函式:
templateinline void serialize(stream& s, unsigned long a, int, int=0)該函式接受乙個unsigned long引數a,獲取它的記憶體位址,轉換指標為char*並呼叫函式s.write()。
cdatastream過載了操作符<< 和 >>用於序列化和反序列化。
templatecdatastream& operator<<(const t& obj)標頭檔案serialize.h包含了14個過載後的這兩個全域性函式給14個原始型別(signed和unsigned版本char,short,int,long和long long,以及char,float,double和bool)以及6個過載版本的6個復合型別(string,vector,pair,map,set和cscript)。因此,對於這些型別,你可以簡單地使用以下**來序列化/反序列化資料:templatecdatastream& operator>>(t& obj)
cdatastream ss(ser_gethash);如果沒有任何實現的型別符合第二個引數obj,則以下泛型t全域性函式將會被呼叫。ss<>obj3>>obj4; //反序列化
templateinline void serialize(stream& os, const t& a, long ntype, int nversion=version)對於該泛型版本,型別t應該用於實現乙個成員函式和簽名t::serialize(stream, int, int)。它將通過a.serialize()被呼叫。
在之前的介紹當中,泛型t需要實現以下三個成員函式進行序列化。
unsigned int getserializesize(int ntype=0, int nversion=version) const;這三個函式將由它們相對應的帶泛型t的全域性函式呼叫。這些全域性函式則由cdatastream中過載的操作符《和》呼叫。void serialize(stream& s, int ntype=0, int nversion=version) const;
void unserialize(stream& s, int ntype=0, int nversion=version);
乙個巨集implement_serialize(statements)用於定義任意型別的這三個函式的實現。
#define implement_serialize(statements) \以下例子示範怎樣使用該巨集。unsigned int getserializesize(int ntype=0, int nversion=version) const \
\return nsersize; \
} \
template\
void serialize(stream& s, int ntype=0, int nversion=version) const \
\} \
template\
void unserialize(stream& s, int ntype=0, int nversion=version) \
\}
#include #include "serialize.h"如你所見,函式::serreadwrite()被過載為三種版本。取決於最後乙個引數,它將會調分別用全域性函式::getserialize(),::serialize()和::unserialize();這三個函式在前面章節已經介紹。using namespace std;
class aclass ;
int x;
implement_serialize(readwrite(this->x);)
}int main()
templateinline unsigned int serreadwrite(stream& s, const t& obj, int ntype, int nversion, cseractionserialize ser_action)
templateinline unsigned int serreadwrite(stream& s, t& obj, int ntype, int nversion, cseractionunserialize ser_action)
如果你檢查三種不同版本的::serreadwrite()的最後乙個引數,你會發現它們全部為空型別。這三種型別的唯一用途是區別::serreadwrite()的三個版本,繼而被巨集implement_serialize()定義的所有函式使用。
位元幣原始碼研讀二(交易指令碼)
今天接著寫五個全域性靜態常量,用於定義交易執行序列的規則.1 static const uint32 t sequence final oxffffffff 如果交易中的所有輸入都將nsequence賦值為該全域性變數值,nlocktime將無效 無需考慮交易的鎖定時間,最近的交易達到區塊後,交易立...
位元幣原始碼解讀一
上次在ubuntu系統中將位元處原始碼編譯環境設定好了後,還沒有具體分析裡面的 今天我們就解讀一下。原始碼版本是bitcoin 0.9.5rc2。我們說驗證位元幣客戶端安裝成功就是從 which bitcoind 這個命令進行驗證的,因為位元幣客戶端有兩個。乙個是圖形介面的版本,通常被稱為 bitc...
位元幣原始碼編譯過程
編譯位元幣原始碼 系統環境 ubuntu 16.04 lts 2g記憶體的虛擬機器 1 更新系統的安裝庫,否則很多依賴庫無法從伺服器獲取 apt get update 2 先安裝一些必要的依賴庫 sudo apt get install build essential libtool autotoo...