/root/bitcoin/src/compressor.h
Line | Count | Source |
1 | | // Copyright (c) 2009-2010 Satoshi Nakamoto |
2 | | // Copyright (c) 2009-present The Bitcoin Core developers |
3 | | // Distributed under the MIT software license, see the accompanying |
4 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | | |
6 | | #ifndef BITCOIN_COMPRESSOR_H |
7 | | #define BITCOIN_COMPRESSOR_H |
8 | | |
9 | | #include <prevector.h> |
10 | | #include <primitives/transaction.h> |
11 | | #include <script/script.h> |
12 | | #include <serialize.h> |
13 | | #include <span.h> |
14 | | |
15 | | /** |
16 | | * This saves us from making many heap allocations when serializing |
17 | | * and deserializing compressed scripts. |
18 | | * |
19 | | * This prevector size is determined by the largest .resize() in the |
20 | | * CompressScript function. The largest compressed script format is a |
21 | | * compressed public key, which is 33 bytes. |
22 | | */ |
23 | | using CompressedScript = prevector<33, unsigned char>; |
24 | | |
25 | | |
26 | | bool CompressScript(const CScript& script, CompressedScript& out); |
27 | | unsigned int GetSpecialScriptSize(unsigned int nSize); |
28 | | bool DecompressScript(CScript& script, unsigned int nSize, const CompressedScript& in); |
29 | | |
30 | | /** |
31 | | * Compress amount. |
32 | | * |
33 | | * nAmount is of type uint64_t and thus cannot be negative. If you're passing in |
34 | | * a CAmount (int64_t), make sure to properly handle the case where the amount |
35 | | * is negative before calling CompressAmount(...). |
36 | | * |
37 | | * @pre Function defined only for 0 <= nAmount <= MAX_MONEY. |
38 | | */ |
39 | | uint64_t CompressAmount(uint64_t nAmount); |
40 | | |
41 | | uint64_t DecompressAmount(uint64_t nAmount); |
42 | | |
43 | | /** Compact serializer for scripts. |
44 | | * |
45 | | * It detects common cases and encodes them much more efficiently. |
46 | | * 3 special cases are defined: |
47 | | * * Pay to pubkey hash (encoded as 21 bytes) |
48 | | * * Pay to script hash (encoded as 21 bytes) |
49 | | * * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes) |
50 | | * |
51 | | * Other scripts up to 121 bytes require 1 byte + script length. Above |
52 | | * that, scripts up to 16505 bytes require 2 bytes + script length. |
53 | | */ |
54 | | struct ScriptCompression |
55 | | { |
56 | | /** |
57 | | * make this static for now (there are only 6 special scripts defined) |
58 | | * this can potentially be extended together with a new version for |
59 | | * transactions, in which case this value becomes dependent on version |
60 | | * and nHeight of the enclosing transaction. |
61 | | */ |
62 | | static constexpr unsigned int nSpecialScripts{6}; |
63 | | |
64 | | template<typename Stream> |
65 | 1.91M | void Ser(Stream &s, const CScript& script) { |
66 | 1.91M | CompressedScript compr; |
67 | 1.91M | if (CompressScript(script, compr)) { Branch (67:13): [True: 188k, False: 1.66M]
Branch (67:13): [True: 0, False: 61.5k]
Branch (67:13): [True: 0, False: 992]
Branch (67:13): [True: 0, False: 992]
Branch (67:13): [True: 0, False: 992]
|
68 | 188k | s << std::span{compr}; |
69 | 188k | return; |
70 | 188k | } |
71 | 1.73M | unsigned int nSize = script.size() + nSpecialScripts; |
72 | 1.73M | s << VARINT(nSize); |
73 | 1.73M | s << std::span{script}; |
74 | 1.73M | } _ZN17ScriptCompression3SerI10DataStreamEEvRT_RK7CScript Line | Count | Source | 65 | 1.85M | void Ser(Stream &s, const CScript& script) { | 66 | 1.85M | CompressedScript compr; | 67 | 1.85M | if (CompressScript(script, compr)) { Branch (67:13): [True: 188k, False: 1.66M]
| 68 | 188k | s << std::span{compr}; | 69 | 188k | return; | 70 | 188k | } | 71 | 1.66M | unsigned int nSize = script.size() + nSpecialScripts; | 72 | 1.66M | s << VARINT(nSize); | 73 | 1.66M | s << std::span{script}; | 74 | 1.66M | } |
_ZN17ScriptCompression3SerI8AutoFileEEvRT_RK7CScript Line | Count | Source | 65 | 61.5k | void Ser(Stream &s, const CScript& script) { | 66 | 61.5k | CompressedScript compr; | 67 | 61.5k | if (CompressScript(script, compr)) { Branch (67:13): [True: 0, False: 61.5k]
| 68 | 0 | s << std::span{compr}; | 69 | 0 | return; | 70 | 0 | } | 71 | 61.5k | unsigned int nSize = script.size() + nSpecialScripts; | 72 | 61.5k | s << VARINT(nSize); | 73 | 61.5k | s << std::span{script}; | 74 | 61.5k | } |
_ZN17ScriptCompression3SerI12SizeComputerEEvRT_RK7CScript Line | Count | Source | 65 | 992 | void Ser(Stream &s, const CScript& script) { | 66 | 992 | CompressedScript compr; | 67 | 992 | if (CompressScript(script, compr)) { Branch (67:13): [True: 0, False: 992]
| 68 | 0 | s << std::span{compr}; | 69 | 0 | return; | 70 | 0 | } | 71 | 992 | unsigned int nSize = script.size() + nSpecialScripts; | 72 | 992 | s << VARINT(nSize); | 73 | 992 | s << std::span{script}; | 74 | 992 | } |
_ZN17ScriptCompression3SerI10HashWriterEEvRT_RK7CScript Line | Count | Source | 65 | 992 | void Ser(Stream &s, const CScript& script) { | 66 | 992 | CompressedScript compr; | 67 | 992 | if (CompressScript(script, compr)) { Branch (67:13): [True: 0, False: 992]
| 68 | 0 | s << std::span{compr}; | 69 | 0 | return; | 70 | 0 | } | 71 | 992 | unsigned int nSize = script.size() + nSpecialScripts; | 72 | 992 | s << VARINT(nSize); | 73 | 992 | s << std::span{script}; | 74 | 992 | } |
_ZN17ScriptCompression3SerI14BufferedWriterI8AutoFileEEEvRT_RK7CScript Line | Count | Source | 65 | 992 | void Ser(Stream &s, const CScript& script) { | 66 | 992 | CompressedScript compr; | 67 | 992 | if (CompressScript(script, compr)) { Branch (67:13): [True: 0, False: 992]
| 68 | 0 | s << std::span{compr}; | 69 | 0 | return; | 70 | 0 | } | 71 | 992 | unsigned int nSize = script.size() + nSpecialScripts; | 72 | 992 | s << VARINT(nSize); | 73 | 992 | s << std::span{script}; | 74 | 992 | } |
|
75 | | |
76 | | template<typename Stream> |
77 | 11.4M | void Unser(Stream &s, CScript& script) { |
78 | 11.4M | unsigned int nSize = 0; |
79 | 11.4M | s >> VARINT(nSize); |
80 | 11.4M | if (nSize < nSpecialScripts) { Branch (80:13): [True: 321k, False: 2.90M]
Branch (80:13): [True: 0, False: 0]
Branch (80:13): [True: 20.1k, False: 6.61M]
Branch (80:13): [True: 95.2k, False: 1.45M]
|
81 | 436k | CompressedScript vch(GetSpecialScriptSize(nSize), 0x00); |
82 | 436k | s >> std::span{vch}; |
83 | 436k | DecompressScript(script, nSize, vch); |
84 | 436k | return; |
85 | 436k | } |
86 | 10.9M | nSize -= nSpecialScripts; |
87 | 10.9M | if (nSize > MAX_SCRIPT_SIZE) { Branch (87:13): [True: 5.06k, False: 2.90M]
Branch (87:13): [True: 0, False: 0]
Branch (87:13): [True: 0, False: 6.61M]
Branch (87:13): [True: 842, False: 1.45M]
|
88 | | // Overly long script, replace with a short invalid one |
89 | 5.91k | script << OP_RETURN; |
90 | 5.91k | s.ignore(nSize); |
91 | 10.9M | } else { |
92 | 10.9M | script.resize(nSize); |
93 | 10.9M | s >> std::span{script}; |
94 | 10.9M | } |
95 | 10.9M | } _ZN17ScriptCompression5UnserI10SpanReaderEEvRT_R7CScript Line | Count | Source | 77 | 3.23M | void Unser(Stream &s, CScript& script) { | 78 | 3.23M | unsigned int nSize = 0; | 79 | 3.23M | s >> VARINT(nSize); | 80 | 3.23M | if (nSize < nSpecialScripts) { Branch (80:13): [True: 321k, False: 2.90M]
| 81 | 321k | CompressedScript vch(GetSpecialScriptSize(nSize), 0x00); | 82 | 321k | s >> std::span{vch}; | 83 | 321k | DecompressScript(script, nSize, vch); | 84 | 321k | return; | 85 | 321k | } | 86 | 2.90M | nSize -= nSpecialScripts; | 87 | 2.90M | if (nSize > MAX_SCRIPT_SIZE) { Branch (87:13): [True: 5.06k, False: 2.90M]
| 88 | | // Overly long script, replace with a short invalid one | 89 | 5.06k | script << OP_RETURN; | 90 | 5.06k | s.ignore(nSize); | 91 | 2.90M | } else { | 92 | 2.90M | script.resize(nSize); | 93 | 2.90M | s >> std::span{script}; | 94 | 2.90M | } | 95 | 2.90M | } |
Unexecuted instantiation: _ZN17ScriptCompression5UnserI12HashVerifierI14BufferedReaderI8AutoFileEEEEvRT_R7CScript _ZN17ScriptCompression5UnserI10DataStreamEEvRT_R7CScript Line | Count | Source | 77 | 6.63M | void Unser(Stream &s, CScript& script) { | 78 | 6.63M | unsigned int nSize = 0; | 79 | 6.63M | s >> VARINT(nSize); | 80 | 6.63M | if (nSize < nSpecialScripts) { Branch (80:13): [True: 20.1k, False: 6.61M]
| 81 | 20.1k | CompressedScript vch(GetSpecialScriptSize(nSize), 0x00); | 82 | 20.1k | s >> std::span{vch}; | 83 | 20.1k | DecompressScript(script, nSize, vch); | 84 | 20.1k | return; | 85 | 20.1k | } | 86 | 6.61M | nSize -= nSpecialScripts; | 87 | 6.61M | if (nSize > MAX_SCRIPT_SIZE) { Branch (87:13): [True: 0, False: 6.61M]
| 88 | | // Overly long script, replace with a short invalid one | 89 | 0 | script << OP_RETURN; | 90 | 0 | s.ignore(nSize); | 91 | 6.61M | } else { | 92 | 6.61M | script.resize(nSize); | 93 | 6.61M | s >> std::span{script}; | 94 | 6.61M | } | 95 | 6.61M | } |
_ZN17ScriptCompression5UnserI8AutoFileEEvRT_R7CScript Line | Count | Source | 77 | 1.54M | void Unser(Stream &s, CScript& script) { | 78 | 1.54M | unsigned int nSize = 0; | 79 | 1.54M | s >> VARINT(nSize); | 80 | 1.54M | if (nSize < nSpecialScripts) { Branch (80:13): [True: 95.2k, False: 1.45M]
| 81 | 95.2k | CompressedScript vch(GetSpecialScriptSize(nSize), 0x00); | 82 | 95.2k | s >> std::span{vch}; | 83 | 95.2k | DecompressScript(script, nSize, vch); | 84 | 95.2k | return; | 85 | 95.2k | } | 86 | 1.45M | nSize -= nSpecialScripts; | 87 | 1.45M | if (nSize > MAX_SCRIPT_SIZE) { Branch (87:13): [True: 842, False: 1.45M]
| 88 | | // Overly long script, replace with a short invalid one | 89 | 842 | script << OP_RETURN; | 90 | 842 | s.ignore(nSize); | 91 | 1.45M | } else { | 92 | 1.45M | script.resize(nSize); | 93 | 1.45M | s >> std::span{script}; | 94 | 1.45M | } | 95 | 1.45M | } |
|
96 | | }; |
97 | | |
98 | | struct AmountCompression |
99 | | { |
100 | | template<typename Stream, typename I> void Ser(Stream& s, I val) |
101 | 1.91M | { |
102 | 1.91M | s << VARINT(CompressAmount(val)); |
103 | 1.91M | } _ZN17AmountCompression3SerI10DataStreamlEEvRT_T0_ Line | Count | Source | 101 | 1.85M | { | 102 | 1.85M | s << VARINT(CompressAmount(val)); | 103 | 1.85M | } |
_ZN17AmountCompression3SerI8AutoFilelEEvRT_T0_ Line | Count | Source | 101 | 61.5k | { | 102 | 61.5k | s << VARINT(CompressAmount(val)); | 103 | 61.5k | } |
_ZN17AmountCompression3SerI12SizeComputerlEEvRT_T0_ Line | Count | Source | 101 | 992 | { | 102 | 992 | s << VARINT(CompressAmount(val)); | 103 | 992 | } |
_ZN17AmountCompression3SerI10HashWriterlEEvRT_T0_ Line | Count | Source | 101 | 992 | { | 102 | 992 | s << VARINT(CompressAmount(val)); | 103 | 992 | } |
_ZN17AmountCompression3SerI14BufferedWriterI8AutoFileElEEvRT_T0_ Line | Count | Source | 101 | 992 | { | 102 | 992 | s << VARINT(CompressAmount(val)); | 103 | 992 | } |
|
104 | | template<typename Stream, typename I> void Unser(Stream& s, I& val) |
105 | 11.4M | { |
106 | 11.4M | uint64_t v; |
107 | 11.4M | s >> VARINT(v); |
108 | 11.4M | val = DecompressAmount(v); |
109 | 11.4M | } _ZN17AmountCompression5UnserI10SpanReaderlEEvRT_RT0_ Line | Count | Source | 105 | 3.23M | { | 106 | 3.23M | uint64_t v; | 107 | 3.23M | s >> VARINT(v); | 108 | 3.23M | val = DecompressAmount(v); | 109 | 3.23M | } |
Unexecuted instantiation: _ZN17AmountCompression5UnserI12HashVerifierI14BufferedReaderI8AutoFileEElEEvRT_RT0_ _ZN17AmountCompression5UnserI10DataStreamlEEvRT_RT0_ Line | Count | Source | 105 | 6.63M | { | 106 | 6.63M | uint64_t v; | 107 | 6.63M | s >> VARINT(v); | 108 | 6.63M | val = DecompressAmount(v); | 109 | 6.63M | } |
_ZN17AmountCompression5UnserI8AutoFilelEEvRT_RT0_ Line | Count | Source | 105 | 1.54M | { | 106 | 1.54M | uint64_t v; | 107 | 1.54M | s >> VARINT(v); | 108 | 1.54M | val = DecompressAmount(v); | 109 | 1.54M | } |
|
110 | | }; |
111 | | |
112 | | /** wrapper for CTxOut that provides a more compact serialization */ |
113 | | struct TxOutCompression |
114 | | { |
115 | 13.3M | FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); }_ZN16TxOutCompression16SerializationOpsI10SpanReader6CTxOut17ActionUnserializeEEvRT0_RT_T1_ Line | Count | Source | 115 | 3.23M | FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } |
_ZN16TxOutCompression16SerializationOpsI10DataStreamK6CTxOut15ActionSerializeEEvRT0_RT_T1_ Line | Count | Source | 115 | 1.85M | FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } |
_ZN16TxOutCompression16SerializationOpsI8AutoFileK6CTxOut15ActionSerializeEEvRT0_RT_T1_ Line | Count | Source | 115 | 61.5k | FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } |
Unexecuted instantiation: _ZN16TxOutCompression16SerializationOpsI12HashVerifierI14BufferedReaderI8AutoFileEE6CTxOut17ActionUnserializeEEvRT0_RT_T1_ _ZN16TxOutCompression16SerializationOpsI12SizeComputerK6CTxOut15ActionSerializeEEvRT0_RT_T1_ Line | Count | Source | 115 | 992 | FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } |
_ZN16TxOutCompression16SerializationOpsI10HashWriterK6CTxOut15ActionSerializeEEvRT0_RT_T1_ Line | Count | Source | 115 | 992 | FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } |
_ZN16TxOutCompression16SerializationOpsI14BufferedWriterI8AutoFileEK6CTxOut15ActionSerializeEEvRT0_RT_T1_ Line | Count | Source | 115 | 992 | FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } |
_ZN16TxOutCompression16SerializationOpsI10DataStream6CTxOut17ActionUnserializeEEvRT0_RT_T1_ Line | Count | Source | 115 | 6.63M | FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } |
_ZN16TxOutCompression16SerializationOpsI8AutoFile6CTxOut17ActionUnserializeEEvRT0_RT_T1_ Line | Count | Source | 115 | 1.54M | FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } |
|
116 | | }; |
117 | | |
118 | | #endif // BITCOIN_COMPRESSOR_H |