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.
251}252if (fRequireMinimal && vch.size() > 0) {253// Check that the number is encoded with the minimum possible254// number of bytes.255//256// If the most-significant-byte - excluding the sign bit - is zero257// then we're not minimal. Note how this test also rejects the258// negative-zero encoding, 0x80.259if ((vch.back() & 0x7f) == 0) {260// One exception: if there's more than one byte and the most261// significant bit of the second-most-significant-byte is set262// it would conflict with the sign bit. An example of this case263// is +-255, which encode to 0xff00 and 0xff80 respectively.264// (big-endian).265if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) {266throw scriptnum_error("non-minimally encoded script number");267}268}269}270m_value = set_vch(vch);271}273inline bool operator==(const int64_t& rhs) const { return m_value == rhs; }274inline auto operator<=>(const int64_t& rhs) const { return m_value <=> rhs; }276inline bool operator==(const CScriptNum& rhs) const { return operator==(rhs.m_value); }277inline auto operator<=>(const CScriptNum& rhs) const { return operator<=>(rhs.m_value); }279inline CScriptNum operator+( const int64_t& rhs) const { return CScriptNum(m_value + rhs);}280inline CScriptNum operator-( const int64_t& rhs) const { return CScriptNum(m_value - rhs);}281inline CScriptNum operator+( const CScriptNum& rhs) const { return operator+(rhs.m_value); }282inline CScriptNum operator-( const CScriptNum& rhs) const { return operator-(rhs.m_value); }284inline CScriptNum& operator+=( const CScriptNum& rhs) { return operator+=(rhs.m_value); }285inline CScriptNum& operator-=( const CScriptNum& rhs) { return operator-=(rhs.m_value); }287inline CScriptNum operator&( const int64_t& rhs) const { return CScriptNum(m_value & rhs);}288inline CScriptNum operator&( const CScriptNum& rhs) const { return operator&(rhs.m_value); }290inline CScriptNum& operator&=( const CScriptNum& rhs) { return operator&=(rhs.m_value); }292inline CScriptNum operator-() const293{294assert(m_value != std::numeric_limits<int64_t>::min());295return CScriptNum(-m_value);296}298inline CScriptNum& operator=( const int64_t& rhs)299{300m_value = rhs;301return *this;302}304inline CScriptNum& operator+=( const int64_t& rhs)305{306assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) ||307(rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs));308m_value += rhs;309return *this;310}312inline CScriptNum& operator-=( const int64_t& rhs)313{314assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) ||315(rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs));316m_value -= rhs;317return *this;318}320inline CScriptNum& operator&=( const int64_t& rhs)321{322m_value &= rhs;323return *this;324}326int getint() const327{328if (m_value > std::numeric_limits<int>::max())329return std::numeric_limits<int>::max();330else if (m_value < std::numeric_limits<int>::min())331return std::numeric_limits<int>::min();332return m_value;333}335int64_t GetInt64() const { return m_value; }337std::vector<unsigned char> getvch() const338{339return serialize(m_value);340}342static std::vector<unsigned char> serialize(const int64_t& value)343{344if(value == 0)345return std::vector<unsigned char>();347std::vector<unsigned char> result;348const bool neg = value < 0;349uint64_t absvalue = neg ? ~static_cast<uint64_t>(value) + 1 : static_cast<uint64_t>(value);351while(absvalue)352{353result.push_back(absvalue & 0xff);354absvalue >>= 8;355}357// - If the most significant byte is >= 0x80 and the value is positive, push a358// new zero-byte to make the significant byte < 0x80 again.360// - If the most significant byte is >= 0x80 and the value is negative, push a361// new 0x80 byte that will be popped off when converting to an integral.363// - If the most significant byte is < 0x80 and the value is negative, add364// 0x80 to it, since it will be subtracted and interpreted as a negative when365// converting to an integral.367if (result.back() & 0x80)368result.push_back(neg ? 0x80 : 0);369else if (neg)370result.back() |= 0x80;372return result;373}375private:376static int64_t set_vch(const std::vector<unsigned char>& vch)377{378if (vch.empty())379return 0;381int64_t result = 0;382for (size_t i = 0; i != vch.size(); ++i)383result |= static_cast<int64_t>(vch[i]) << 8*i;385// If the input vector's most significant byte is 0x80, remove it from386// the result's msb and return a negative.387if (vch.back() & 0x80)388return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1)))));390return result;391}393int64_t m_value;394};396/**397* We use a prevector for the script to reduce the considerable memory overhead398* of vectors in cases where they normally contain a small number of small elements.399*/400using CScriptBase = prevector<36, uint8_t>;402bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator end, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet);404/** Serialized script, used inside transaction inputs and outputs */405class CScript : public CScriptBase406{407private:408inline void AppendDataSize(const uint32_t size)409{410if (size < OP_PUSHDATA1) {411insert(end(), static_cast<value_type>(size));412} else if (size <= 0xff) {413insert(end(), OP_PUSHDATA1);414insert(end(), static_cast<value_type>(size));415} else if (size <= 0xffff) {416insert(end(), OP_PUSHDATA2);417value_type data[2];418WriteLE16(data, size);419insert(end(), std::cbegin(data), std::cend(data));420} else {421insert(end(), OP_PUSHDATA4);422value_type data[4];423WriteLE32(data, size);424insert(end(), std::cbegin(data), std::cend(data));425}426}428void AppendData(std::span<const value_type> data)429{430insert(end(), data.begin(), data.end());431}433protected:434CScript& push_int64(int64_t n)435{436if (n == -1 || (n >= 1 && n <= 16))437{438push_back(n + (OP_1 - 1));439}440else if (n == 0)441{442push_back(OP_0);443}444else445{446*this << CScriptNum::serialize(n);447}448return *this;449}451public:452CScript() = default;453template <std::input_iterator InputIterator>454CScript(InputIterator first, InputIterator last) : CScriptBase{first, last} { }456SERIALIZE_METHODS(CScript, obj) { READWRITE(AsBase<CScriptBase>(obj)); }458explicit CScript(int64_t b) { operator<<(b); }459explicit CScript(opcodetype b) { operator<<(b); }460explicit CScript(const CScriptNum& b) { operator<<(b); }461// delete non-existent constructor to defend against future introduction462// e.g. via prevector463explicit CScript(const std::vector<unsigned char>& b) = delete;465/** Delete non-existent operator to defend against future introduction */466CScript& operator<<(const CScript& b) = delete;468CScript& operator<<(int64_t b) LIFETIMEBOUND { return push_int64(b); }470CScript& operator<<(opcodetype opcode) LIFETIMEBOUND471{472if (opcode < 0 || opcode > 0xff)473throw std::runtime_error("CScript::operator<<(): invalid opcode");474insert(end(), (unsigned char)opcode);475return *this;476}478CScript& operator<<(const CScriptNum& b) LIFETIMEBOUND479{480*this << b.getvch();481return *this;482}484CScript& operator<<(std::span<const std::byte> b) LIFETIMEBOUND485{486AppendDataSize(b.size());487AppendData({reinterpret_cast<const value_type*>(b.data()), b.size()});488return *this;489}491// For compatibility reasons. In new code, prefer using std::byte instead of uint8_t.492CScript& operator<<(std::span<const value_type> b) LIFETIMEBOUND493{494return *this << std::as_bytes(b);495}497bool GetOp(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet) const498{499return GetScriptOp(pc, end(), opcodeRet, &vchRet);500}