/Users/eugenesiegel/btc/bitcoin/src/compressor.h
Line | Count | Source (jump to first uncovered line) |
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 const unsigned int nSpecialScripts = 6; |
63 | | |
64 | | template<typename Stream> |
65 | 103k | void Ser(Stream &s, const CScript& script) { |
66 | 103k | CompressedScript compr; |
67 | 103k | if (CompressScript(script, compr)) { |
68 | 0 | s << std::span{compr}; |
69 | 0 | return; |
70 | 0 | } |
71 | 103k | unsigned int nSize = script.size() + nSpecialScripts; |
72 | 103k | s << VARINT(nSize); Line | Count | Source | 500 | 103k | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| s << VARINT(nSize); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| s << VARINT(nSize); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| s << VARINT(nSize); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| s << VARINT(nSize); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
|
73 | 103k | s << std::span{script}; |
74 | 103k | } _ZN17ScriptCompression3SerI10DataStreamEEvRT_RK7CScript Line | Count | Source | 65 | 103k | void Ser(Stream &s, const CScript& script) { | 66 | 103k | CompressedScript compr; | 67 | 103k | if (CompressScript(script, compr)) { | 68 | 0 | s << std::span{compr}; | 69 | 0 | return; | 70 | 0 | } | 71 | 103k | unsigned int nSize = script.size() + nSpecialScripts; | 72 | 103k | s << VARINT(nSize); Line | Count | Source | 500 | 103k | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| 73 | 103k | s << std::span{script}; | 74 | 103k | } |
Unexecuted instantiation: _ZN17ScriptCompression3SerI8AutoFileEEvRT_RK7CScript Unexecuted instantiation: _ZN17ScriptCompression3SerI12SizeComputerEEvRT_RK7CScript Unexecuted instantiation: _ZN17ScriptCompression3SerI10HashWriterEEvRT_RK7CScript Unexecuted instantiation: _ZN17ScriptCompression3SerI14BufferedWriterI8AutoFileEEEvRT_RK7CScript |
75 | | |
76 | | template<typename Stream> |
77 | 0 | void Unser(Stream &s, CScript& script) { |
78 | 0 | unsigned int nSize = 0; |
79 | 0 | s >> VARINT(nSize); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| s >> VARINT(nSize); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| s >> VARINT(nSize); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
|
80 | 0 | if (nSize < nSpecialScripts) { |
81 | 0 | CompressedScript vch(GetSpecialScriptSize(nSize), 0x00); |
82 | 0 | s >> std::span{vch}; |
83 | 0 | DecompressScript(script, nSize, vch); |
84 | 0 | return; |
85 | 0 | } |
86 | 0 | nSize -= nSpecialScripts; |
87 | 0 | if (nSize > MAX_SCRIPT_SIZE) { |
88 | | // Overly long script, replace with a short invalid one |
89 | 0 | script << OP_RETURN; |
90 | 0 | s.ignore(nSize); |
91 | 0 | } else { |
92 | 0 | script.resize(nSize); |
93 | 0 | s >> std::span{script}; |
94 | 0 | } |
95 | 0 | } Unexecuted instantiation: _ZN17ScriptCompression5UnserI10DataStreamEEvRT_R7CScript Unexecuted instantiation: _ZN17ScriptCompression5UnserI12HashVerifierI14BufferedReaderI8AutoFileEEEEvRT_R7CScript Unexecuted instantiation: _ZN17ScriptCompression5UnserI8AutoFileEEvRT_R7CScript |
96 | | }; |
97 | | |
98 | | struct AmountCompression |
99 | | { |
100 | | template<typename Stream, typename I> void Ser(Stream& s, I val) |
101 | 103k | { |
102 | 103k | s << VARINT(CompressAmount(val)); Line | Count | Source | 500 | 103k | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| s << VARINT(CompressAmount(val)); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| s << VARINT(CompressAmount(val)); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| s << VARINT(CompressAmount(val)); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| s << VARINT(CompressAmount(val)); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
|
103 | 103k | } _ZN17AmountCompression3SerI10DataStreamxEEvRT_T0_ Line | Count | Source | 101 | 103k | { | 102 | 103k | s << VARINT(CompressAmount(val)); Line | Count | Source | 500 | 103k | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| 103 | 103k | } |
Unexecuted instantiation: _ZN17AmountCompression3SerI8AutoFilexEEvRT_T0_ Unexecuted instantiation: _ZN17AmountCompression3SerI12SizeComputerxEEvRT_T0_ Unexecuted instantiation: _ZN17AmountCompression3SerI10HashWriterxEEvRT_T0_ Unexecuted instantiation: _ZN17AmountCompression3SerI14BufferedWriterI8AutoFileExEEvRT_T0_ |
104 | | template<typename Stream, typename I> void Unser(Stream& s, I& val) |
105 | 0 | { |
106 | 0 | uint64_t v; |
107 | 0 | s >> VARINT(v); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| s >> VARINT(v); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
| s >> VARINT(v); Line | Count | Source | 500 | 0 | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) |
|
108 | 0 | val = DecompressAmount(v); |
109 | 0 | } Unexecuted instantiation: _ZN17AmountCompression5UnserI10DataStreamxEEvRT_RT0_ Unexecuted instantiation: _ZN17AmountCompression5UnserI12HashVerifierI14BufferedReaderI8AutoFileEExEEvRT_RT0_ Unexecuted instantiation: _ZN17AmountCompression5UnserI8AutoFilexEEvRT_RT0_ |
110 | | }; |
111 | | |
112 | | /** wrapper for CTxOut that provides a more compact serialization */ |
113 | | struct TxOutCompression |
114 | | { |
115 | 103k | FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } Line | Count | Source | 156 | 0 | #define READWRITE(...) (ser_action.SerReadWriteMany(s, __VA_ARGS__)) |
| FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } Line | Count | Source | 156 | 103k | #define READWRITE(...) (ser_action.SerReadWriteMany(s, __VA_ARGS__)) |
| FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } Line | Count | Source | 156 | 0 | #define READWRITE(...) (ser_action.SerReadWriteMany(s, __VA_ARGS__)) |
| FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } Line | Count | Source | 156 | 0 | #define READWRITE(...) (ser_action.SerReadWriteMany(s, __VA_ARGS__)) |
| FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } Line | Count | Source | 156 | 0 | #define READWRITE(...) (ser_action.SerReadWriteMany(s, __VA_ARGS__)) |
| FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } Line | Count | Source | 156 | 0 | #define READWRITE(...) (ser_action.SerReadWriteMany(s, __VA_ARGS__)) |
| FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } Line | Count | Source | 156 | 0 | #define READWRITE(...) (ser_action.SerReadWriteMany(s, __VA_ARGS__)) |
| FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } Line | Count | Source | 156 | 0 | #define READWRITE(...) (ser_action.SerReadWriteMany(s, __VA_ARGS__)) |
Unexecuted instantiation: _ZN16TxOutCompression16SerializationOpsI10DataStream6CTxOut17ActionUnserializeEEvRT0_RT_T1_ _ZN16TxOutCompression16SerializationOpsI10DataStreamK6CTxOut15ActionSerializeEEvRT0_RT_T1_ Line | Count | Source | 115 | 103k | FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } Line | Count | Source | 156 | 103k | #define READWRITE(...) (ser_action.SerReadWriteMany(s, __VA_ARGS__)) |
|
Unexecuted instantiation: _ZN16TxOutCompression16SerializationOpsI8AutoFileK6CTxOut15ActionSerializeEEvRT0_RT_T1_ Unexecuted instantiation: _ZN16TxOutCompression16SerializationOpsI12HashVerifierI14BufferedReaderI8AutoFileEE6CTxOut17ActionUnserializeEEvRT0_RT_T1_ Unexecuted instantiation: _ZN16TxOutCompression16SerializationOpsI12SizeComputerK6CTxOut15ActionSerializeEEvRT0_RT_T1_ Unexecuted instantiation: _ZN16TxOutCompression16SerializationOpsI10HashWriterK6CTxOut15ActionSerializeEEvRT0_RT_T1_ Unexecuted instantiation: _ZN16TxOutCompression16SerializationOpsI14BufferedWriterI8AutoFileEK6CTxOut15ActionSerializeEEvRT0_RT_T1_ Unexecuted instantiation: _ZN16TxOutCompression16SerializationOpsI8AutoFile6CTxOut17ActionUnserializeEEvRT0_RT_T1_ |
116 | | }; |
117 | | |
118 | | #endif // BITCOIN_COMPRESSOR_H |