/* * This file is part of the Flowee project * Copyright (C) 2009-2010 Satoshi Nakamoto * Copyright (C) 2009-2014 The Bitcoin Core developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef FLOWEE_COMPRESSOR_H #define FLOWEE_COMPRESSOR_H #include "primitives/transaction.h" #include "primitives/script.h" #include "serialize.h" class KeyId; class PublicKey; class CScriptID; /** Compact serializer for scripts. * * It detects common cases and encodes them much more efficiently. * 3 special cases are defined: * * Pay to pubkey hash (encoded as 21 bytes) * * Pay to script hash (encoded as 21 bytes) * * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes) * * Other scripts up to 121 bytes require 1 byte + script length. Above * that, scripts up to 16505 bytes require 2 bytes + script length. */ class CScriptCompressor { private: /** * make this static for now (there are only 6 special scripts defined) * this can potentially be extended together with a new nVersion for * transactions, in which case this value becomes dependent on nVersion * and nHeight of the enclosing transaction. */ static const unsigned int nSpecialScripts = 6; CScript &script; protected: /** * These check for scripts for which a special case with a shorter encoding is defined. * They are implemented separately from the CScript test, as these test for exact byte * sequence correspondences, and are more strict. For example, IsToPubKey also verifies * whether the public key is valid (as invalid ones cannot be represented in compressed * form). */ bool IsToKeyID(KeyId &hash) const; bool IsToScriptID(CScriptID &hash) const; bool IsToPubKey(PublicKey &pubkey) const; bool Compress(std::vector &out) const; unsigned int GetSpecialSize(unsigned int nSize) const; bool Decompress(unsigned int nSize, const std::vector &out); public: CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } unsigned int GetSerializeSize(int nType, int nVersion) const { std::vector compr; if (Compress(compr)) return compr.size(); unsigned int nSize = script.size() + nSpecialScripts; return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion); } template void Serialize(Stream &s, int nType, int nVersion) const { std::vector compr; if (Compress(compr)) { s << CFlatData(compr); return; } unsigned int nSize = script.size() + nSpecialScripts; s << VARINT(nSize); s << CFlatData(script); } template void Unserialize(Stream &s, int nType, int nVersion) { unsigned int nSize = 0; s >> VARINT(nSize); if (nSize < nSpecialScripts) { std::vector vch(GetSpecialSize(nSize), 0x00); s >> REF(CFlatData(vch)); Decompress(nSize, vch); return; } nSize -= nSpecialScripts; script.resize(nSize); s >> REF(CFlatData(script)); } }; /** wrapper for CTxOut that provides a more compact serialization */ class CTxOutCompressor { private: CTxOut &txout; public: static uint64_t CompressAmount(uint64_t nAmount); static uint64_t DecompressAmount(uint64_t nAmount); CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { } ADD_SERIALIZE_METHODS template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { if (!ser_action.ForRead()) { uint64_t nVal = CompressAmount(txout.nValue); READWRITE(VARINT(nVal)); } else { uint64_t nVal = 0; READWRITE(VARINT(nVal)); txout.nValue = DecompressAmount(nVal); } CScriptCompressor cscript(REF(txout.scriptPubKey)); READWRITE(cscript); } }; #endif