Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2009-2010 Satoshi Nakamoto2// Copyright (c) 2009-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or http://www.opensource.org/licenses/mit-license.php.6#ifndef BITCOIN_COMPRESSOR_H7#define BITCOIN_COMPRESSOR_H9#include <prevector.h>10#include <primitives/transaction.h>11#include <script/script.h>12#include <serialize.h>13#include <span.h>15/**16* This saves us from making many heap allocations when serializing17* and deserializing compressed scripts.18*19* This prevector size is determined by the largest .resize() in the20* CompressScript function. The largest compressed script format is a21* compressed public key, which is 33 bytes.22*/23using CompressedScript = prevector<33, unsigned char>;26bool CompressScript(const CScript& script, CompressedScript& out);27unsigned int GetSpecialScriptSize(unsigned int nSize);28bool DecompressScript(CScript& script, unsigned int nSize, const CompressedScript& in);30/**31* Compress amount.32*33* nAmount is of type uint64_t and thus cannot be negative. If you're passing in34* a CAmount (int64_t), make sure to properly handle the case where the amount35* is negative before calling CompressAmount(...).36*37* @pre Function defined only for 0 <= nAmount <= MAX_MONEY.38*/39uint64_t CompressAmount(uint64_t nAmount);41uint64_t DecompressAmount(uint64_t nAmount);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. Above52* that, scripts up to 16505 bytes require 2 bytes + script length.53*/54struct ScriptCompression55{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 for59* transactions, in which case this value becomes dependent on version60* and nHeight of the enclosing transaction.61*/62static constexpr unsigned int nSpecialScripts{6};64template<typename Stream>65void Ser(Stream &s, const CScript& script) {66CompressedScript compr;67if (CompressScript(script, compr)) {68s << std::span{compr};69return;70}71unsigned int nSize = script.size() + nSpecialScripts;72s << VARINT(nSize);73s << std::span{script};74}76template<typename Stream>77void Unser(Stream &s, CScript& script) {78unsigned int nSize = 0;79s >> VARINT(nSize);80if (nSize < nSpecialScripts) {81CompressedScript vch(GetSpecialScriptSize(nSize), 0x00);82s >> std::span{vch};83DecompressScript(script, nSize, vch);84return;85}86nSize -= nSpecialScripts;87if (nSize > MAX_SCRIPT_SIZE) {88// Overly long script, replace with a short invalid one89script << OP_RETURN;90s.ignore(nSize);91} else {92script.resize(nSize);93s >> std::span{script};94}95}96};98struct AmountCompression99{100template<typename Stream, typename I> void Ser(Stream& s, I val)101{102s << VARINT(CompressAmount(val));103}104template<typename Stream, typename I> void Unser(Stream& s, I& val)105{106uint64_t v;107s >> VARINT(v);108val = DecompressAmount(v);109}110};112/** wrapper for CTxOut that provides a more compact serialization */113struct TxOutCompression114{115FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); }116};118#endif // BITCOIN_COMPRESSOR_H