Bitcoin 시리얼화된 라이브러리 사용

14761 단어 비트코인
비트코인 서열화 기능은 주로 serialize.h 파일에 실현되고 전체 코드는 stream와 서열화에 참여하는 반서열화 유형 T를 중심으로 전개된다. 
stream 이 템플릿은 read(char**, size_t) write(char**, size_t) 방법을 가진 대상을 나타냅니다. Golang의 io와 유사합니다.reader ,io.writer.
간단한 사용 예:
#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< {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()

사용자 정의 유형 내부에 ADD 추가 필요SERIALIZE_METHODS 호출, 확대 후:
template                                         \
    void Serialize(Stream& s) const {                                 \
        NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize());  \
    }                                                                 \
    template                                         \
    void Unserialize(Stream& s) {                                     \
        SerializationOp(s, CSerActionUnserialize());                  \
    }

이 매크로는 사용자 정의 형식에 두 개의 구성원 함수를 추가했습니다:serialize와 Unserialize입니다. 사용자 정의 템플릿 구성원 함수인 SerializationOp을 내부에서 호출합니다. SerializationOp 함수 내부에서는 주로 READWRITE와 READWRITEMANY 매크로를 사용하여 사용자 정의 형식의 모든 데이터 구성원에 대한 서열화와 반서열화를 완성합니다.
#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; }
};

template
inline 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...);
}

사용자 정의 유형 내부에 ADD 추가 필요SERIALIZE_METHODS 호출, 확대 후:

template  \

 void Serialize(Stream& s) const {  \

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

 }  \

 template  \

 void Unserialize(Stream& s) {  \

 SerializationOp(s, CSerActionUnserialize()); \

 }

이 매크로는 사용자 정의 형식에 두 개의 구성원 함수를 추가했다. SerializeUnserialize 매크로는 사용자 정의 템플릿 구성원 함수SerializationOp를 내부 호출하고 SerializationOp 함수 내부에서 주로 READWRITEREADWRITEMANY 매크로를 사용하며 사용자 정의 형식의 모든 데이터 구성원에 대한 서열화와 반서열화를 완성했다.
#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; }
};

template
inline 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는 각각 두 개의 오버로드가 이루어졌는데 그 차이는 마지막에 각각 다른 유형CSerActionSerializeCSerActionUnserialize이 전해졌고 형삼seraction은 내부에서 사용하지 않고 관련 자료를 찾아봤습니다. 여기는 c++ 일반 프로그래밍에서 자주 사용하는 모델을 사용했습니다.
tag dispatch 기술] (https://akrzemi1.wordpress.co...다른 설명: [https://arne-mertz.de/2016/10...://arne-mertz.de/2016/10/tag-dispatch/),
서로 다른 유형을 가지고 번역할 때 서로 다른 오버로드를 선택하여 실현하고 CserActionserialize는 서열화에 대응하며 CserActionUnserialize는 반서열화에 대응한다.SerializeManySerializeMany는 길어진 템플릿 파라메터 패키지 전개 기술을 통해 이루어진 것으로 SerializeMany를 예로 들 수 있다.

template
void 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 세 개의 오버로드가 실현되고 위에서 쓰러진다고 가정하면 각각 1, 2, 3이다.두 개 이상의 실참이 들어오면 컴파일러가 버전 3을 선택하고 버전 3 내부에서parameter 패키지에서 파라미터를 팝업해서 버전 2에 호출하고 나머지 파라미터 목록은 버전 3에 전송하며, 다시 호출하고parameter 패키지가 비어 있을 때까지 버전 1을 선택합니다.
이렇게 길게 우회하면 최종 서열화는 전역 명칭 공간Serialize을 사용하여 이루어지고 반서열화는 호출Unserialize을 통해 이루어진다.SerializeUnserialize 또 한 무더기의 오버로드가 실현되었다. 비트코인 작가는 흔히 볼 수 있는 유형의 템플릿 특화를 실현했다. 예를 들어 std:::string, 주로 스크립트를 디자인하는 prevector,std:vector,std::pair,std:::map,std:::set,std:::uniqueptr, std::share_ptr . c++의 템플릿 매칭은 매개 변수 목록의 매칭 정도에 따라 다른 실현을 선택하고 정확하고 정확하게 우선하며 마지막으로 유형 T의 구성원 함수를 선택하여 실현한다.
template
inline 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 등 여러 요소를 포함할 수 있는 집합 형식을 서열화할 때 내부적으로 ReadCompactSizeWriteCompactSize를 호출하여 인코딩된 요소의 개수를 읽습니다.
template
void 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;
}

비트폭 1,2,4,8의 기초 유형에 대한 SerializeUnserialize 최종 호출serwritedata, ser_readdata8 완성 실현.
template inline 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 대상은 주로 여러 개의 실현 서명에 다음과 같은 형식이 있다.
template  
T::T(deserialize_type, Stream& s)

Ctransaction, CMutable Transaction 유형:
template 
    CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {}
    
    template 
    CMutableTransaction(deserialize_type, Stream& s) {
        Unserialize(s);
    }

원본 주소:https://mp.weixin.qq.com/s/_fhGCfkI0sT3fasSKWqdPA
본문은 Copernicus 에 작성되었고 전재는 권한을 부여할 필요가 없다.

좋은 웹페이지 즐겨찾기