Bitcoin中如何使用序列化庫(kù),針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。
創(chuàng)新互聯(lián)公司于2013年成立,先為麥積等服務(wù)建站,麥積等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為麥積企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。
Bitcoin序列化功能主要實(shí)現(xiàn)在serialize.h
文件,整個(gè)代碼主要是圍繞stream
和參與序列化反序列化的類型T展開。
stream這個(gè)模板形參表達(dá)具有read(char**, size_t)
和write(char**, size_t)
方法的對(duì)象, 類似Golang 的io.reader ,io.writer。
簡(jiǎn)單的使用例子:
#include#include #include #include #include #include #include BOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup) struct student { std::string name; double midterm, final; std::vector homework; ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(name); READWRITE(midterm); READWRITE(final); READWRITE(homework); } }; bool operator==(student const& lhs, student const& rhs){ return lhs.name == rhs.name && \ lhs.midterm == rhs.midterm && \ lhs.final == rhs.final && \ lhs.homework == rhs.homework; } std::ostream& operator<<(std::ostream& os, student const& st){ os << "name: " << st.name << '\n' << "midterm: " << st.midterm << '\n' << "final: " << st.final << '\n' << "homework: " ; for (auto e : st.homework) { os << e << ' '; } return os; } BOOST_AUTO_TEST_CASE(normal) { student s, t; s.name = "john"; s.midterm = 77; s.final = 82; auto v = std::vector {83, 50, 10, 88, 65}; s.homework = v; CDataStream ss(SER_DISK, 0); ss << s; ss >> t; BOOST_CHECK(t.name == "john"); BOOST_CHECK(t.midterm == 77); BOOST_CHECK(t.final == 82); BOOST_TEST(t.homework == v, boost::test_tools::per_element()); CDataStream sd(SER_DISK, 0); CDataStream sn(SER_NETWORK, PROTOCOL_VERSION); sd << s; sn << s; BOOST_CHECK(Hash(sd.begin(), sd.end()) == Hash(sn.begin(), sn.end())); } BOOST_AUTO_TEST_CASE(vector) { auto vs = std::vector (3); vs[0].name = "bob"; vs[0].midterm = 90; vs[0].final = 76; vs[0].homework = std::vector {85, 53, 12, 75, 55}; vs[1].name = "jim"; vs[1].midterm = 96; vs[1].final = 72; vs[1].homework = std::vector {91, 46, 19, 70, 59}; vs[2].name = "tom"; vs[2].midterm = 85; vs[2].final = 57; vs[2].homework = std::vector {91, 77, 45, 50, 35}; CDataStream ss(SER_DISK, 0); auto vt = std::vector (3); ss << vs; ss >> vt; BOOST_TEST(vs == vt, boost::test_tools::per_element()); } BOOST_AUTO_TEST_CASE(unique_ptr){ auto hex = "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000"; CDataStream stream(ParseHex(hex), SER_NETWORK, PROTOCOL_VERSION); //CTransaction tx(deserialize, stream); auto utx = std::unique_ptr (nullptr); ::Unserialize(stream, utx); BOOST_TEST(utx->vin.size() == std::size_t(1)); BOOST_TEST(utx->vout[0].nValue == 1000000); } BOOST_AUTO_TEST_SUITE_END()
需要在用戶的自定義類型內(nèi)部 添加 ADD_SERIALIZE_METHODS調(diào)用, 宏展開后:
template\ void Serialize(Stream& s) const { \ NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize()); \ } \ template \ void Unserialize(Stream& s) { \ SerializationOp(s, CSerActionUnserialize()); \ }
這個(gè)宏為用戶自定義類型添加了兩個(gè)成員函數(shù): Serialize和 Unserialize, 它們內(nèi)部調(diào)用需要用戶自定義的模板成員函數(shù)SerializationOp, 在 SerializationOp函數(shù)內(nèi)部, 主要使用 READWRITE和 READWRITEMANY宏,完成對(duì)自定義類型每個(gè)數(shù)據(jù)成員的序列化與反序列化。
#define READWRITE(obj) (::SerReadWrite(s, (obj), ser_action)) #define READWRITEMANY(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__)) struct CSerActionSerialize { constexpr bool ForRead() const { return false; } }; struct CSerActionUnserialize { constexpr bool ForRead() const { return true; } }; templateinline void SerReadWrite(Stream& s, const T& obj, CSerActionSerialize ser_action) { ::Serialize(s, obj); } template inline void SerReadWrite(Stream& s, T& obj, CSerActionUnserialize ser_action) { ::Unserialize(s, obj); } template inline void SerReadWriteMany(Stream& s, CSerActionSerialize ser_action, Args&&... args) { ::SerializeMany(s, std::forward (args)...); } template inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&... args) { ::UnserializeMany(s, args...); }
需要在用戶的自定義類型內(nèi)部 添加 ADD_SERIALIZE_METHODS調(diào)用, 宏展開后:
template\ void Serialize(Stream& s) const { \ NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize()); \ } \ template \ void Unserialize(Stream& s) { \ SerializationOp(s, CSerActionUnserialize()); \ }
這個(gè)宏為用戶自定義類型添加了兩個(gè)成員函數(shù): Serialize
和 Unserialize
, 它們內(nèi)部調(diào)用需要用戶自定義的模板成員函數(shù)SerializationOp
, 在 SerializationOp
函數(shù)內(nèi)部, 主要使用 READWRITE
和 READWRITEMANY
宏,完成對(duì)自定義類型每個(gè)數(shù)據(jù)成員的序列化與反序列化。
#define READWRITE(obj) (::SerReadWrite(s, (obj), ser_action)) #define READWRITEMANY(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__)) struct CSerActionSerialize { constexpr bool ForRead() const { return false; } }; struct CSerActionUnserialize { constexpr bool ForRead() const { return true; } }; templateinline void SerReadWrite(Stream& s, const T& obj, CSerActionSerialize ser_action) { ::Serialize(s, obj); } template inline void SerReadWrite(Stream& s, T& obj, CSerActionUnserialize ser_action) { ::Unserialize(s, obj); } template inline void SerReadWriteMany(Stream& s, CSerActionSerialize ser_action, Args&&... args) { ::SerializeMany(s, std::forward (args)...); } template inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&... args) { ::UnserializeMany(s, args...); }
這里SerReadWrite 和 SerReadWriteMany 各自有兩個(gè)overload 實(shí)現(xiàn), 區(qū)別是末尾分別傳入了不同的類型CSerActionSerialize
和 CSerActionUnserialize
, 而且 形參 ser_action 根本沒(méi)有在內(nèi)部使用, 查閱了相關(guān)資料, 這里使用了c++ 泛型編程常用的一種模式:
tag dispatch 技術(shù)](https://akrzemi1.wordpress.com/examples/overloading-tag-dispatch/), 另一個(gè)解釋:[https://arne-mertz.de/2016/10/tag-dispatch/)(https://arne-mertz.de/2016/10/tag-dispatch/),
通過(guò)攜帶不同的類型,在編譯時(shí)選擇不同的overload 實(shí)現(xiàn), CSerActionSerialize 對(duì)應(yīng)序列化的實(shí)現(xiàn), CSerActionUnserialize 對(duì)應(yīng)反序列化的實(shí)現(xiàn)。
SerializeMany
和 SerializeMany
是通過(guò)變長(zhǎng)模板parameter pack 展開技術(shù)來(lái)實(shí)現(xiàn), 以 SerializeMany
為例子:
templatevoid SerializeMany(Stream& s) { } template void SerializeMany(Stream& s, Arg&& arg) { ::Serialize(s, std::forward (arg)); } template void SerializeMany(Stream& s, Arg&& arg, Args&&... args) { ::Serialize(s, std::forward (arg)); ::SerializeMany(s, std::forward (args)...); }
SerializeMany
有三個(gè)overload 實(shí)現(xiàn),假設(shè)從上倒下,分別編號(hào)為1, 2, 3; 當(dāng)我們傳入兩個(gè)以上的實(shí)參是,編譯器選擇版本3,版本3內(nèi)部從parameter pack 彈出一個(gè)參數(shù),然后傳給版本2調(diào)用,剩下的參數(shù)列表,傳給版本3,遞歸調(diào)用,直到parameter pack 為空時(shí),選擇版本1。
迂回這么長(zhǎng), 最終序列化真正使用全局名稱空間的 Serialize
來(lái)完成, 反序列化通過(guò)調(diào)用Unserialize
實(shí)現(xiàn)。
而 Serialize
和Unserialize
又有一堆的overload 實(shí)現(xiàn), Bitcoin 作者實(shí)現(xiàn)一些常見(jiàn)類型的模板特化,比如,std::string, 主要設(shè)計(jì)表達(dá)腳本的prevector , std::vector, std::pair, std::map, std::set, std::unique_ptr, std::share_ptr 。 c++ 的模板匹配根據(jù)參數(shù)列表的匹配程度選擇不同的實(shí)現(xiàn), 優(yōu)先精準(zhǔn)匹配,最后選擇類型T的成員函數(shù)實(shí)現(xiàn):
templateinline void Serialize(Stream& os, const T& a) { a.Serialize(os); } template inline void Unserialize(Stream& is, T& a) { a.Unserialize(is); }
在序列化string, map, set, vector, prevector 等可能包含多元素的集合類型時(shí), 內(nèi)部會(huì)調(diào)用 ReadCompactSize
和 WriteCompactSize
讀取寫入緊湊編碼的元素個(gè)數(shù):
templatevoid WriteCompactSize(Stream& os, uint64_t nSize) { if (nSize < 253) { ser_writedata8(os, nSize); } else if (nSize <= std::numeric_limits ::max()) { ser_writedata8(os, 253); ser_writedata16(os, nSize); } else if (nSize <= std::numeric_limits ::max()) { ser_writedata8(os, 254); ser_writedata32(os, nSize); } else { ser_writedata8(os, 255); ser_writedata64(os, nSize); } return; } template uint64_t ReadCompactSize(Stream& is) { uint8_t chSize = ser_readdata8(is); uint64_t nSizeRet = 0; if (chSize < 253) { nSizeRet = chSize; } else if (chSize == 253) { nSizeRet = ser_readdata16(is); if (nSizeRet < 253) throw std::ios_base::failure("non-canonical ReadCompactSize()"); } else if (chSize == 254) { nSizeRet = ser_readdata32(is); if (nSizeRet < 0x10000u) throw std::ios_base::failure("non-canonical ReadCompactSize()"); } else { nSizeRet = ser_readdata64(is); if (nSizeRet < 0x100000000ULL) throw std::ios_base::failure("non-canonical ReadCompactSize()"); } if (nSizeRet > (uint64_t)MAX_SIZE) throw std::ios_base::failure("ReadCompactSize(): size too large"); return nSizeRet; }
針對(duì)位寬1,2,4,8的基礎(chǔ)類型,Serialize
和 Unserialize
最終調(diào)用ser_writedata*, ser_readdata8* 完成實(shí)現(xiàn)。
templateinline void Serialize(Stream& s, char a ) { ser_writedata8(s, a); } // TODO Get rid of bare char template inline void Serialize(Stream& s, int8_t a ) { ser_writedata8(s, a); } template inline void Serialize(Stream& s, uint8_t a ) { ser_writedata8(s, a); } template inline void Serialize(Stream& s, int16_t a ) { ser_writedata16(s, a); } template inline void Serialize(Stream& s, uint16_t a) { ser_writedata16(s, a); } template inline void Serialize(Stream& s, int32_t a ) { ser_writedata32(s, a); } template inline void Serialize(Stream& s, uint32_t a) { ser_writedata32(s, a); } template inline void Serialize(Stream& s, int64_t a ) { ser_writedata64(s, a); } template inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); } template inline void Serialize(Stream& s, float a ) { ser_writedata32(s, ser_float_to_uint32(a)); } template inline void Serialize(Stream& s, double a ) { ser_writedata64(s, ser_double_to_uint64(a)); } template inline void Unserialize(Stream& s, char& a ) { a = ser_readdata8(s); } // TODO Get rid of bare char template inline void Unserialize(Stream& s, int8_t& a ) { a = ser_readdata8(s); } template inline void Unserialize(Stream& s, uint8_t& a ) { a = ser_readdata8(s); } template inline void Unserialize(Stream& s, int16_t& a ) { a = ser_readdata16(s); } template inline void Unserialize(Stream& s, uint16_t& a) { a = ser_readdata16(s); } template inline void Unserialize(Stream& s, int32_t& a ) { a = ser_readdata32(s); } template inline void Unserialize(Stream& s, uint32_t& a) { a = ser_readdata32(s); } template inline void Unserialize(Stream& s, int64_t& a ) { a = ser_readdata64(s); } template inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); } template inline void Unserialize(Stream& s, float& a ) { a = ser_uint32_to_float(ser_readdata32(s)); } template inline void Unserialize(Stream& s, double& a ) { a = ser_uint64_to_double(ser_readdata64(s)); } template inline void Serialize(Stream& s, bool a) { char f=a; ser_writedata8(s, f); } template inline void Unserialize(Stream& s, bool& a) { char f=ser_readdata8(s); a=f; }
另外代碼開始處的
struct deserialize_type {}; constexpr deserialize_type deserialize {};
作為tag 類型, tag 對(duì)象, 主要為多個(gè)實(shí)現(xiàn)簽名有以下形式:
templateT::T(deserialize_type, Stream& s)
的反序列化構(gòu)造器做分發(fā), 目前主要是CTransaction, CMutableTransaction 類型:
templateCTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {} template CMutableTransaction(deserialize_type, Stream& s) { Unserialize(s); }
關(guān)于Bitcoin中如何使用序列化庫(kù)問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。