]>
Commit | Line | Data |
---|---|---|
9294a4bb | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
f914f1a7 | 2 | // Copyright (c) 2009-2014 The Bitcoin Core developers |
2d79bba3 | 3 | // Distributed under the MIT software license, see the accompanying |
9294a4bb | 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | ||
84738627 PJ |
6 | #ifndef BITCOIN_COMPRESSOR_H |
7 | #define BITCOIN_COMPRESSOR_H | |
9294a4bb | 8 | |
d2270111 | 9 | #include "primitives/transaction.h" |
9294a4bb | 10 | #include "script/script.h" |
85c579e3 | 11 | #include "serialize.h" |
9294a4bb | 12 | |
85c579e3 CF |
13 | class CKeyID; |
14 | class CPubKey; | |
066e2a14 CF |
15 | class CScriptID; |
16 | ||
9294a4bb | 17 | /** Compact serializer for scripts. |
18 | * | |
19 | * It detects common cases and encodes them much more efficiently. | |
20 | * 3 special cases are defined: | |
21 | * * Pay to pubkey hash (encoded as 21 bytes) | |
22 | * * Pay to script hash (encoded as 21 bytes) | |
23 | * * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes) | |
24 | * | |
25 | * Other scripts up to 121 bytes require 1 byte + script length. Above | |
26 | * that, scripts up to 16505 bytes require 2 bytes + script length. | |
27 | */ | |
28 | class CScriptCompressor | |
29 | { | |
30 | private: | |
fa94b9d5 MF |
31 | /** |
32 | * make this static for now (there are only 6 special scripts defined) | |
33 | * this can potentially be extended together with a new nVersion for | |
34 | * transactions, in which case this value becomes dependent on nVersion | |
35 | * and nHeight of the enclosing transaction. | |
36 | */ | |
9294a4bb | 37 | static const unsigned int nSpecialScripts = 6; |
38 | ||
39 | CScript &script; | |
40 | protected: | |
fa94b9d5 MF |
41 | /** |
42 | * These check for scripts for which a special case with a shorter encoding is defined. | |
43 | * They are implemented separately from the CScript test, as these test for exact byte | |
44 | * sequence correspondences, and are more strict. For example, IsToPubKey also verifies | |
45 | * whether the public key is valid (as invalid ones cannot be represented in compressed | |
46 | * form). | |
47 | */ | |
9294a4bb | 48 | bool IsToKeyID(CKeyID &hash) const; |
49 | bool IsToScriptID(CScriptID &hash) const; | |
50 | bool IsToPubKey(CPubKey &pubkey) const; | |
51 | ||
52 | bool Compress(std::vector<unsigned char> &out) const; | |
53 | unsigned int GetSpecialSize(unsigned int nSize) const; | |
54 | bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out); | |
55 | public: | |
56 | CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } | |
57 | ||
58 | unsigned int GetSerializeSize(int nType, int nVersion) const { | |
59 | std::vector<unsigned char> compr; | |
60 | if (Compress(compr)) | |
61 | return compr.size(); | |
62 | unsigned int nSize = script.size() + nSpecialScripts; | |
63 | return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion); | |
64 | } | |
65 | ||
66 | template<typename Stream> | |
67 | void Serialize(Stream &s, int nType, int nVersion) const { | |
68 | std::vector<unsigned char> compr; | |
69 | if (Compress(compr)) { | |
70 | s << CFlatData(compr); | |
71 | return; | |
72 | } | |
73 | unsigned int nSize = script.size() + nSpecialScripts; | |
74 | s << VARINT(nSize); | |
75 | s << CFlatData(script); | |
76 | } | |
77 | ||
78 | template<typename Stream> | |
79 | void Unserialize(Stream &s, int nType, int nVersion) { | |
80 | unsigned int nSize = 0; | |
81 | s >> VARINT(nSize); | |
82 | if (nSize < nSpecialScripts) { | |
83 | std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00); | |
84 | s >> REF(CFlatData(vch)); | |
85 | Decompress(nSize, vch); | |
86 | return; | |
87 | } | |
88 | nSize -= nSpecialScripts; | |
89 | script.resize(nSize); | |
90 | s >> REF(CFlatData(script)); | |
91 | } | |
92 | }; | |
93 | ||
561e9e9d | 94 | /** wrapper for CTxOut that provides a more compact serialization */ |
95 | class CTxOutCompressor | |
96 | { | |
97 | private: | |
98 | CTxOut &txout; | |
99 | ||
100 | public: | |
101 | static uint64_t CompressAmount(uint64_t nAmount); | |
102 | static uint64_t DecompressAmount(uint64_t nAmount); | |
103 | ||
104 | CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { } | |
105 | ||
106 | ADD_SERIALIZE_METHODS; | |
107 | ||
108 | template <typename Stream, typename Operation> | |
109 | inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { | |
110 | if (!ser_action.ForRead()) { | |
111 | uint64_t nVal = CompressAmount(txout.nValue); | |
112 | READWRITE(VARINT(nVal)); | |
113 | } else { | |
114 | uint64_t nVal = 0; | |
115 | READWRITE(VARINT(nVal)); | |
116 | txout.nValue = DecompressAmount(nVal); | |
117 | } | |
118 | CScriptCompressor cscript(REF(txout.scriptPubKey)); | |
119 | READWRITE(cscript); | |
120 | } | |
121 | }; | |
122 | ||
84738627 | 123 | #endif // BITCOIN_COMPRESSOR_H |