Branch data Line data Source code
1 : : // Copyright (c) 2009-2010 Satoshi Nakamoto 2 : : // Copyright (c) 2009-2021 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_TEST_SCRIPTNUM10_H 7 : : #define BITCOIN_TEST_SCRIPTNUM10_H 8 : : 9 : : #include <assert.h> 10 : : #include <limits> 11 : : #include <stdexcept> 12 : : #include <stdint.h> 13 : : #include <string> 14 : : #include <vector> 15 : : 16 : : class scriptnum10_error : public std::runtime_error 17 : : { 18 : : public: 19 : 0 : explicit scriptnum10_error(const std::string& str) : std::runtime_error(str) {} 20 : : }; 21 : : 22 : : class CScriptNum10 23 : : { 24 : : /** 25 : : * The ScriptNum implementation from Bitcoin Core 0.10.0, for cross-comparison. 26 : : */ 27 : : public: 28 : : 29 : 0 : explicit CScriptNum10(const int64_t& n) 30 : : { 31 : 0 : m_value = n; 32 : 0 : } 33 : : 34 : : static const size_t nDefaultMaxNumSize = 4; 35 : : 36 : 0 : explicit CScriptNum10(const std::vector<unsigned char>& vch, bool fRequireMinimal, 37 : : const size_t nMaxNumSize = nDefaultMaxNumSize) 38 : : { 39 : 0 : if (vch.size() > nMaxNumSize) { 40 : 0 : throw scriptnum10_error("script number overflow"); 41 : : } 42 : 0 : if (fRequireMinimal && vch.size() > 0) { 43 : : // Check that the number is encoded with the minimum possible 44 : : // number of bytes. 45 : : // 46 : : // If the most-significant-byte - excluding the sign bit - is zero 47 : : // then we're not minimal. Note how this test also rejects the 48 : : // negative-zero encoding, 0x80. 49 : 0 : if ((vch.back() & 0x7f) == 0) { 50 : : // One exception: if there's more than one byte and the most 51 : : // significant bit of the second-most-significant-byte is set 52 : : // it would conflict with the sign bit. An example of this case 53 : : // is +-255, which encode to 0xff00 and 0xff80 respectively. 54 : : // (big-endian). 55 : 0 : if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) { 56 : 0 : throw scriptnum10_error("non-minimally encoded script number"); 57 : : } 58 : 0 : } 59 : 0 : } 60 : 0 : m_value = set_vch(vch); 61 : 0 : } 62 : : 63 : 0 : inline bool operator==(const int64_t& rhs) const { return m_value == rhs; } 64 : 0 : inline bool operator!=(const int64_t& rhs) const { return m_value != rhs; } 65 : 0 : inline bool operator<=(const int64_t& rhs) const { return m_value <= rhs; } 66 : 0 : inline bool operator< (const int64_t& rhs) const { return m_value < rhs; } 67 : 0 : inline bool operator>=(const int64_t& rhs) const { return m_value >= rhs; } 68 : 0 : inline bool operator> (const int64_t& rhs) const { return m_value > rhs; } 69 : : 70 : 0 : inline bool operator==(const CScriptNum10& rhs) const { return operator==(rhs.m_value); } 71 : 0 : inline bool operator!=(const CScriptNum10& rhs) const { return operator!=(rhs.m_value); } 72 : 0 : inline bool operator<=(const CScriptNum10& rhs) const { return operator<=(rhs.m_value); } 73 : 0 : inline bool operator< (const CScriptNum10& rhs) const { return operator< (rhs.m_value); } 74 : 0 : inline bool operator>=(const CScriptNum10& rhs) const { return operator>=(rhs.m_value); } 75 : 0 : inline bool operator> (const CScriptNum10& rhs) const { return operator> (rhs.m_value); } 76 : : 77 : 0 : inline CScriptNum10 operator+( const int64_t& rhs) const { return CScriptNum10(m_value + rhs);} 78 : 0 : inline CScriptNum10 operator-( const int64_t& rhs) const { return CScriptNum10(m_value - rhs);} 79 : 0 : inline CScriptNum10 operator+( const CScriptNum10& rhs) const { return operator+(rhs.m_value); } 80 : 0 : inline CScriptNum10 operator-( const CScriptNum10& rhs) const { return operator-(rhs.m_value); } 81 : : 82 : : inline CScriptNum10& operator+=( const CScriptNum10& rhs) { return operator+=(rhs.m_value); } 83 : : inline CScriptNum10& operator-=( const CScriptNum10& rhs) { return operator-=(rhs.m_value); } 84 : : 85 : 0 : inline CScriptNum10 operator-() const 86 : : { 87 : 0 : assert(m_value != std::numeric_limits<int64_t>::min()); 88 : 0 : return CScriptNum10(-m_value); 89 : : } 90 : : 91 : : inline CScriptNum10& operator=( const int64_t& rhs) 92 : : { 93 : : m_value = rhs; 94 : : return *this; 95 : : } 96 : : 97 : : inline CScriptNum10& operator+=( const int64_t& rhs) 98 : : { 99 : : assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || 100 : : (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)); 101 : : m_value += rhs; 102 : : return *this; 103 : : } 104 : : 105 : : inline CScriptNum10& operator-=( const int64_t& rhs) 106 : : { 107 : : assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || 108 : : (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)); 109 : : m_value -= rhs; 110 : : return *this; 111 : : } 112 : : 113 : 0 : int getint() const 114 : : { 115 : 0 : if (m_value > std::numeric_limits<int>::max()) 116 : 0 : return std::numeric_limits<int>::max(); 117 : 0 : else if (m_value < std::numeric_limits<int>::min()) 118 : 0 : return std::numeric_limits<int>::min(); 119 : 0 : return m_value; 120 : 0 : } 121 : : 122 : 0 : std::vector<unsigned char> getvch() const 123 : : { 124 : 0 : return serialize(m_value); 125 : : } 126 : : 127 : 0 : static std::vector<unsigned char> serialize(const int64_t& value) 128 : : { 129 : 0 : if(value == 0) 130 : 0 : return std::vector<unsigned char>(); 131 : : 132 : 0 : std::vector<unsigned char> result; 133 : 0 : const bool neg = value < 0; 134 : 0 : uint64_t absvalue = neg ? -value : value; 135 : : 136 : 0 : while(absvalue) 137 : : { 138 : 0 : result.push_back(absvalue & 0xff); 139 : 0 : absvalue >>= 8; 140 : : } 141 : : 142 : : // - If the most significant byte is >= 0x80 and the value is positive, push a 143 : : // new zero-byte to make the significant byte < 0x80 again. 144 : : 145 : : // - If the most significant byte is >= 0x80 and the value is negative, push a 146 : : // new 0x80 byte that will be popped off when converting to an integral. 147 : : 148 : : // - If the most significant byte is < 0x80 and the value is negative, add 149 : : // 0x80 to it, since it will be subtracted and interpreted as a negative when 150 : : // converting to an integral. 151 : : 152 : 0 : if (result.back() & 0x80) 153 : 0 : result.push_back(neg ? 0x80 : 0); 154 : 0 : else if (neg) 155 : 0 : result.back() |= 0x80; 156 : : 157 : 0 : return result; 158 : 0 : } 159 : : 160 : : private: 161 : 0 : static int64_t set_vch(const std::vector<unsigned char>& vch) 162 : : { 163 : 0 : if (vch.empty()) 164 : 0 : return 0; 165 : : 166 : 0 : int64_t result = 0; 167 : 0 : for (size_t i = 0; i != vch.size(); ++i) 168 : 0 : result |= static_cast<int64_t>(vch[i]) << 8*i; 169 : : 170 : : // If the input vector's most significant byte is 0x80, remove it from 171 : : // the result's msb and return a negative. 172 : 0 : if (vch.back() & 0x80) 173 : 0 : return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1))))); 174 : : 175 : 0 : return result; 176 : 0 : } 177 : : 178 : : int64_t m_value; 179 : : }; 180 : : 181 : : 182 : : #endif // BITCOIN_TEST_SCRIPTNUM10_H