Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto 2 : // Copyright (c) 2009-2020 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 <primitives/transaction.h> 10 : #include <script/script.h> 11 : #include <serialize.h> 12 : #include <span.h> 13 : 14 : bool CompressScript(const CScript& script, std::vector<unsigned char> &out); 15 : unsigned int GetSpecialScriptSize(unsigned int nSize); 16 : bool DecompressScript(CScript& script, unsigned int nSize, const std::vector<unsigned char> &out); 17 : 18 : /** 19 : * Compress amount. 20 : * 21 : * nAmount is of type uint64_t and thus cannot be negative. If you're passing in 22 : * a CAmount (int64_t), make sure to properly handle the case where the amount 23 : * is negative before calling CompressAmount(...). 24 : * 25 : * @pre Function defined only for 0 <= nAmount <= MAX_MONEY. 26 : */ 27 : uint64_t CompressAmount(uint64_t nAmount); 28 : 29 : uint64_t DecompressAmount(uint64_t nAmount); 30 : 31 : /** Compact serializer for scripts. 32 : * 33 : * It detects common cases and encodes them much more efficiently. 34 : * 3 special cases are defined: 35 : * * Pay to pubkey hash (encoded as 21 bytes) 36 : * * Pay to script hash (encoded as 21 bytes) 37 : * * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes) 38 : * 39 : * Other scripts up to 121 bytes require 1 byte + script length. Above 40 : * that, scripts up to 16505 bytes require 2 bytes + script length. 41 : */ 42 : struct ScriptCompression 43 : { 44 : /** 45 : * make this static for now (there are only 6 special scripts defined) 46 : * this can potentially be extended together with a new nVersion for 47 : * transactions, in which case this value becomes dependent on nVersion 48 : * and nHeight of the enclosing transaction. 49 : */ 50 : static const unsigned int nSpecialScripts = 6; 51 : 52 : template<typename Stream> 53 435753 : void Ser(Stream &s, const CScript& script) { 54 435753 : std::vector<unsigned char> compr; 55 435753 : if (CompressScript(script, compr)) { 56 185015 : s << MakeSpan(compr); 57 185015 : return; 58 : } 59 250738 : unsigned int nSize = script.size() + nSpecialScripts; 60 250738 : s << VARINT(nSize); 61 250738 : s << MakeSpan(script); 62 435753 : } 63 : 64 : template<typename Stream> 65 114583 : void Unser(Stream &s, CScript& script) { 66 114583 : unsigned int nSize = 0; 67 114583 : s >> VARINT(nSize); 68 114583 : if (nSize < nSpecialScripts) { 69 19078 : std::vector<unsigned char> vch(GetSpecialScriptSize(nSize), 0x00); 70 19078 : s >> MakeSpan(vch); 71 19078 : DecompressScript(script, nSize, vch); 72 : return; 73 19078 : } 74 95505 : nSize -= nSpecialScripts; 75 95505 : if (nSize > MAX_SCRIPT_SIZE) { 76 : // Overly long script, replace with a short invalid one 77 1 : script << OP_RETURN; 78 1 : s.ignore(nSize); 79 1 : } else { 80 95504 : script.resize(nSize); 81 95504 : s >> MakeSpan(script); 82 : } 83 114581 : } 84 : }; 85 : 86 : struct AmountCompression 87 : { 88 435753 : template<typename Stream, typename I> void Ser(Stream& s, I val) 89 : { 90 435753 : s << VARINT(CompressAmount(val)); 91 435753 : } 92 114583 : template<typename Stream, typename I> void Unser(Stream& s, I& val) 93 : { 94 114583 : uint64_t v; 95 114583 : s >> VARINT(v); 96 114583 : val = DecompressAmount(v); 97 114583 : } 98 : }; 99 : 100 : /** wrapper for CTxOut that provides a more compact serialization */ 101 : struct TxOutCompression 102 : { 103 1100672 : FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } 104 : }; 105 : 106 : #endif // BITCOIN_COMPRESSOR_H