比特幣源碼(v0.01)區塊序列化過程
比特幣中,區塊序列化存儲到區塊文件(格式:blkxxxxx.dat)中,序列化過程【1】-【13】如下:
class CBlock
{
public:
// header
int nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
unsigned int nTime;
unsigned int nBits;
unsigned int nNonce;
// network and disk
vector<CTransaction> vtx;
// memory only
mutable vector<uint256> vMerkleTree;
//[7]
//序列化宏調用:用宏定義部分替換
IMPLEMENT_SERIALIZE
(
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
// ConnectBlock depends on vtx being last so it can calculate offset
if (!(nType & (SER_GETHASH | SER_BLOCKHEADERONLY)))
READWRITE(vtx);
else if (fRead)
const_cast<CBlock*>(this)->vtx.clear();
)
//[2]
//序列化存儲到硬盤中
bool WriteToDisk(bool fWriteTransactions, unsigned int& nFileRet, unsigned int& nBlockPosRet)
{
// Open history file to append
CAutoFile fileout = AppendBlockFile(nFileRet);
if (!fileout)
return error("CBlock::WriteToDisk() : AppendBlockFile failed");
if (!fWriteTransactions)
fileout.nType |= SER_BLOCKHEADERONLY;
// Write index header
unsigned int nSize = fileout.GetSerializeSize(*this);
fileout << FLATDATA(pchMessageStart) << nSize;
// Write block
nBlockPosRet = ftell(fileout);
if (nBlockPosRet == -1)
return error("CBlock::WriteToDisk() : ftell failed");
//[3]
//實例序列化
fileout << *this;
return true;
}
}
//序列化宏定義開始,替換CBlock類中的IMPLEMENT_SERIALIZE宏
//#define IMPLEMENT_SERIALIZE(statements) start
unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const
{
CSerActionGetSerializeSize ser_action;
const bool fGetSize = true;
const bool fWrite = false;
const bool fRead = false;
unsigned int nSerSize = 0;
ser_streamplaceholder s;
s.nType = nType;
s.nVersion = nVersion;
//READWRITE(obj);調用宏READWRITE,結果如下:
nSerSize += ::SerReadWrite(s, this->nVersion, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, hashPrevBlock, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, hashMerkleRoot, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, nTime, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, nBits, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, nNonce, nType, nVersion, ser_action);
if (!(nType & (SER_GETHASH | SER_BLOCKHEADERONLY)))
nSerSize += ::SerReadWrite(s, vtx, nType, nVersion, ser_action);
else if (fRead)
const_cast<CBlock*>(this)->vtx.clear();
return nSerSize;
}
//[8]
template<typename Stream>
void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const
{
CSerActionSerialize ser_action;
const bool fGetSize = false;
const bool fWrite = true;
const bool fRead = false;
unsigned int nSerSize = 0;
//[9]
//READWRITE(obj);調用宏READWRITE,結果如下:
nSerSize += ::SerReadWrite(s, this->nVersion, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, hashPrevBlock, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, hashMerkleRoot, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, nTime, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, nBits, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, nNonce, nType, nVersion, ser_action);
if (!(nType & (SER_GETHASH | SER_BLOCKHEADERONLY)))
nSerSize += ::SerReadWrite(s, vtx, nType, nVersion, ser_action);
else if (fRead)
const_cast<CBlock*>(this)->vtx.clear();
}
template<typename Stream>
void Unserialize(Stream& s, int nType=0, int nVersion=VERSION)
{
CSerActionUnserialize ser_action;
const bool fGetSize = false;
const bool fWrite = false;
const bool fRead = true;
unsigned int nSerSize = 0;
//READWRITE(obj);調用宏READWRITE,結果如下:
nSerSize += ::SerReadWrite(s, this->nVersion, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, hashPrevBlock, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, hashMerkleRoot, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, nTime, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, nBits, nType, nVersion, ser_action);
nSerSize += ::SerReadWrite(s, nNonce, nType, nVersion, ser_action);
if (!(nType & (SER_GETHASH | SER_BLOCKHEADERONLY)))
nSerSize += ::SerReadWrite(s, vtx, nType, nVersion, ser_action);
else if (fRead)
const_cast<CBlock*>(this)->vtx.clear();
}
//#define IMPLEMENT_SERIALIZE(statements) end
//序列化宏定義結束
//宏READWRITE開始
//#define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action))
//多態(ser_action)
template<typename Stream, typename T>
inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action)
{
return ::GetSerializeSize(obj, nType, nVersion);
}
//[10]
template<typename Stream, typename T>
inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action)
{
::Serialize(s, obj, nType, nVersion);
return 0;
}
template<typename Stream, typename T>
inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action)
{
::Unserialize(s, obj, nType, nVersion);
return 0;
}
//宏READWRITE結束
//[12]
#define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj))
#define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj))
//多態
inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); }
//[11]
template<typename Stream> inline void Serialize(Stream& s, signed int a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, unsigned int a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, signed int& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned int& a, int, int=0) { READDATA(s, a); }
//類型爲類
template<typename T>
inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion=VERSION)
{
return a.GetSerializeSize((int)nType, nVersion);
}
template<typename Stream, typename T>
inline void Serialize(Stream& os, const T& a, long nType, int nVersion=VERSION)
{
a.Serialize(os, (int)nType, nVersion);
}
template<typename Stream, typename T>
inline void Unserialize(Stream& is, T& a, long nType, int nVersion=VERSION)
{
a.Unserialize(is, (int)nType, nVersion);
}
//[1]
//構造block,然後序列化
//......
//block.WriteToDisk(!fClient, nFile, nBlockPos)
//調用block.Serialize方法
//[4]
//序列化,重載操作符<<
//序列化區塊時,此時,T爲CBlock類
template<typename T>
CAutoFile& operator<<(const T& obj)
{
// Serialize to this stream
if (!file)
throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL");
//[5]
//調用多態方法
::Serialize(*this, obj, nType, nVersion);
return (*this);
}
//[6]
//此時,T爲CBlock類
template<typename Stream, typename T>
inline void Serialize(Stream& os, const T& a, long nType, int nVersion=VERSION)
{
//調用CBlock類中的Serialize方法:
//調用block.Serialize方法
a.Serialize(os, (int)nType, nVersion);
}
//[13]
CAutoFile& write(const char* pch, int nSize)
{
if (!file)
throw std::ios_base::failure("CAutoFile::write : file handle is NULL");
if (fwrite(pch, 1, nSize, file) != nSize)
setstate(ios::failbit, "CAutoFile::write : write failed");
return (*this);
}
//[12]
//CDataStream類
template<typename Stream>
void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const
{
// Special case: stream << stream concatenates like stream += stream
if (!vch.empty())
s.write((char*)&vch[0], vch.size() * sizeof(vch[0]));
}
//[13]
CDataStream& write(const char* pch, int nSize)
{
// Write to the end of the buffer
assert(nSize >= 0);
vch.insert(vch.end(), pch, pch + nSize);
return (*this);
}