Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto 2 : // Copyright (c) 2009-2014 The Bitcoin developers 3 : // Copyright (c) 2017-2020 The PIVX Core developers 4 : // Distributed under the MIT software license, see the accompanying 5 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 6 : 7 : #ifndef PIVX_COMPRESSOR_H 8 : #define PIVX_COMPRESSOR_H 9 : 10 : #include "primitives/transaction.h" 11 : #include "script/script.h" 12 : #include "serialize.h" 13 : #include "span.h" 14 : 15 : bool CompressScript(const CScript& script, std::vector<unsigned char> &out); 16 : unsigned int GetSpecialScriptSize(unsigned int nSize); 17 : bool DecompressScript(CScript& script, unsigned int nSize, const std::vector<unsigned char> &out); 18 : 19 : uint64_t CompressAmount(uint64_t nAmount); 20 : uint64_t DecompressAmount(uint64_t nAmount); 21 : 22 : /** Compact serializer for scripts. 23 : * 24 : * It detects common cases and encodes them much more efficiently. 25 : * 3 special cases are defined: 26 : * * Pay to pubkey hash (encoded as 21 bytes) 27 : * * Pay to script hash (encoded as 21 bytes) 28 : * * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes) 29 : * 30 : * Other scripts up to 121 bytes require 1 byte + script length. Above 31 : * that, scripts up to 16505 bytes require 2 bytes + script length. 32 : */ 33 : struct ScriptCompression 34 : { 35 : /** 36 : * make this static for now (there are only 6 special scripts defined) 37 : * this can potentially be extended together with a new nVersion for 38 : * transactions, in which case this value becomes dependent on nVersion 39 : * and nHeight of the enclosing transaction. 40 : */ 41 : static const unsigned int nSpecialScripts = 6; 42 : 43 : template<typename Stream> 44 2563127 : void Ser(Stream &s, const CScript& script) { 45 122631 : std::vector<unsigned char> compr; 46 2563127 : if (CompressScript(script, compr)) { 47 2440496 : s << MakeSpan(compr); 48 4880990 : return; 49 : } 50 122913 : unsigned int nSize = script.size() + nSpecialScripts; 51 122631 : s << VARINT(nSize); 52 122631 : s << MakeSpan(script); 53 : } 54 : 55 : template<typename Stream> 56 7152755 : void Unser(Stream &s, CScript& script) { 57 7152755 : unsigned int nSize = 0; 58 7152755 : s >> VARINT(nSize); 59 7152755 : if (nSize < nSpecialScripts) { 60 14291046 : std::vector<unsigned char> vch(GetSpecialScriptSize(nSize), 0x00); 61 7145513 : s >> MakeSpan(vch); 62 7145513 : DecompressScript(script, nSize, vch); 63 7145513 : return; 64 : } 65 7244 : nSize -= nSpecialScripts; 66 7244 : if (nSize > MAX_SCRIPT_SIZE) { 67 : // Overly long script, replace with a short invalid one 68 1 : script << OP_RETURN; 69 1 : s.ignore(nSize); 70 : } else { 71 7243 : script.resize(nSize); 72 7243 : s >> MakeSpan(script); 73 : } 74 : } 75 : }; 76 : 77 : struct AmountCompression 78 : { 79 2563131 : template<typename Stream, typename I> void Ser(Stream& s, I val) 80 : { 81 2563131 : s << VARINT(CompressAmount(val)); 82 466998 : } 83 7152755 : template<typename Stream, typename I> void Unser(Stream& s, I& val) 84 : { 85 : uint64_t v; 86 7152755 : s >> VARINT(v); 87 7152755 : val = DecompressAmount(v); 88 : } 89 : }; 90 : 91 : /** wrapper for CTxOut that provides a more compact serialization */ 92 : struct TxOutCompression 93 : { 94 19431772 : FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); } 95 : }; 96 : 97 : #endif // PIVX_COMPRESSOR_H