diff options
author | Cory Fields <cory-nospam-@coryfields.com> | 2014-03-26 15:50:29 -0400 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2014-08-18 15:34:28 +0200 |
commit | 84efe0ec223c24fcdd3e3f971170783ce481bcff (patch) | |
tree | 8596d6d25add744fa34eb854117836eb2a803d4c | |
parent | 5baa4a90e3089b919aa3b01c734ca5a9a8f21722 (diff) |
Remove bignum dependency for scripts
Rebased-From: 48d8eb1 27bff74 4f497cd 05e3ecf 90320d6 b1fdd54
-rw-r--r-- | src/chainparams.cpp | 2 | ||||
-rw-r--r-- | src/miner.cpp | 2 | ||||
-rw-r--r-- | src/script.cpp | 45 | ||||
-rw-r--r-- | src/script.h | 198 | ||||
-rw-r--r-- | src/test/Makefile.am | 1 | ||||
-rw-r--r-- | src/test/data/script_invalid.json | 3 | ||||
-rw-r--r-- | src/test/data/script_valid.json | 13 | ||||
-rw-r--r-- | src/test/scriptnum_tests.cpp | 196 |
8 files changed, 387 insertions, 73 deletions
diff --git a/src/chainparams.cpp b/src/chainparams.cpp index b52774ee20..eb56800b92 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -125,7 +125,7 @@ public: CTransaction txNew; txNew.vin.resize(1); txNew.vout.resize(1); - txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); txNew.vout[0].nValue = 50 * COIN; txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; genesis.vtx.push_back(txNew); diff --git a/src/miner.cpp b/src/miner.cpp index 6bc6edf34f..e8abb8c614 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -355,7 +355,7 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& } ++nExtraNonce; unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 - pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CBigNum(nExtraNonce)) + COINBASE_FLAGS; + pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100); pblock->hashMerkleRoot = pblock->BuildMerkleTree(); diff --git a/src/script.cpp b/src/script.cpp index 810ba16d28..81d2754453 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -5,7 +5,6 @@ #include "script.h" -#include "bignum.h" #include "core.h" #include "hash.h" #include "key.h" @@ -25,22 +24,13 @@ typedef vector<unsigned char> valtype; static const valtype vchFalse(0); static const valtype vchZero(0); static const valtype vchTrue(1, 1); -static const CBigNum bnZero(0); -static const CBigNum bnOne(1); -static const CBigNum bnFalse(0); -static const CBigNum bnTrue(1); -static const size_t nMaxNumSize = 4; +static const CScriptNum bnZero(0); +static const CScriptNum bnOne(1); +static const CScriptNum bnFalse(0); +static const CScriptNum bnTrue(1); bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); -CBigNum CastToBigNum(const valtype& vch) -{ - if (vch.size() > nMaxNumSize) - throw runtime_error("CastToBigNum() : overflow"); - // Get rid of extra leading zeros - return CBigNum(CBigNum(vch).getvch()); -} - bool CastToBool(const valtype& vch) { for (unsigned int i = 0; i < vch.size(); i++) @@ -306,7 +296,6 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { - CAutoBN_CTX pctx; CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); CScript::const_iterator pbegincodehash = script.begin(); @@ -380,7 +369,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co case OP_16: { // ( -- value) - CBigNum bn((int)opcode - (int)(OP_1 - 1)); + CScriptNum bn((int)opcode - (int)(OP_1 - 1)); stack.push_back(bn.getvch()); } break; @@ -556,7 +545,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co case OP_DEPTH: { // -- stacksize - CBigNum bn(stack.size()); + CScriptNum bn(stack.size()); stack.push_back(bn.getvch()); } break; @@ -606,7 +595,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) if (stack.size() < 2) return false; - int n = CastToBigNum(stacktop(-1)).getint(); + int n = CScriptNum(stacktop(-1)).getint(); popstack(stack); if (n < 0 || n >= (int)stack.size()) return false; @@ -654,7 +643,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // (in -- in size) if (stack.size() < 1) return false; - CBigNum bn(stacktop(-1).size()); + CScriptNum bn(stacktop(-1).size()); stack.push_back(bn.getvch()); } break; @@ -705,7 +694,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // (in -- out) if (stack.size() < 1) return false; - CBigNum bn = CastToBigNum(stacktop(-1)); + CScriptNum bn(stacktop(-1)); switch (opcode) { case OP_1ADD: bn += bnOne; break; @@ -738,9 +727,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // (x1 x2 -- out) if (stack.size() < 2) return false; - CBigNum bn1 = CastToBigNum(stacktop(-2)); - CBigNum bn2 = CastToBigNum(stacktop(-1)); - CBigNum bn; + CScriptNum bn1(stacktop(-2)); + CScriptNum bn2(stacktop(-1)); + CScriptNum bn(0); switch (opcode) { case OP_ADD: @@ -783,9 +772,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // (x min max -- out) if (stack.size() < 3) return false; - CBigNum bn1 = CastToBigNum(stacktop(-3)); - CBigNum bn2 = CastToBigNum(stacktop(-2)); - CBigNum bn3 = CastToBigNum(stacktop(-1)); + CScriptNum bn1(stacktop(-3)); + CScriptNum bn2(stacktop(-2)); + CScriptNum bn3(stacktop(-1)); bool fValue = (bn2 <= bn1 && bn1 < bn3); popstack(stack); popstack(stack); @@ -882,7 +871,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co if ((int)stack.size() < i) return false; - int nKeysCount = CastToBigNum(stacktop(-i)).getint(); + int nKeysCount = CScriptNum(stacktop(-i)).getint(); if (nKeysCount < 0 || nKeysCount > 20) return false; nOpCount += nKeysCount; @@ -893,7 +882,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co if ((int)stack.size() < i) return false; - int nSigsCount = CastToBigNum(stacktop(-i)).getint(); + int nSigsCount = CScriptNum(stacktop(-i)).getint(); if (nSigsCount < 0 || nSigsCount > nKeysCount) return false; int isig = ++i; diff --git a/src/script.h b/src/script.h index 657ac0b388..1742ce81f8 100644 --- a/src/script.h +++ b/src/script.h @@ -6,7 +6,6 @@ #ifndef H_BITCOIN_SCRIPT #define H_BITCOIN_SCRIPT -#include "bignum.h" #include "key.h" #include "util.h" @@ -25,6 +24,155 @@ class CTransaction; static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes +class scriptnum_error : public std::runtime_error +{ +public: + explicit scriptnum_error(const std::string& str) : std::runtime_error(str) {} +}; + +class CScriptNum +{ +// Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers. +// The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1], +// but results may overflow (and are valid as long as they are not used in a subsequent +// numeric operation). CScriptNum enforces those semantics by storing results as +// an int64 and allowing out-of-range values to be returned as a vector of bytes but +// throwing an exception if arithmetic is done or the result is interpreted as an integer. +public: + + explicit CScriptNum(const int64_t& n) + { + m_value = n; + } + + explicit CScriptNum(const std::vector<unsigned char>& vch) + { + if (vch.size() > nMaxNumSize) + throw scriptnum_error("CScriptNum(const std::vector<unsigned char>&) : overflow"); + m_value = set_vch(vch); + } + + inline bool operator==(const int64_t& rhs) const { return m_value == rhs; } + inline bool operator!=(const int64_t& rhs) const { return m_value != rhs; } + inline bool operator<=(const int64_t& rhs) const { return m_value <= rhs; } + inline bool operator< (const int64_t& rhs) const { return m_value < rhs; } + inline bool operator>=(const int64_t& rhs) const { return m_value >= rhs; } + inline bool operator> (const int64_t& rhs) const { return m_value > rhs; } + + inline bool operator==(const CScriptNum& rhs) const { return operator==(rhs.m_value); } + inline bool operator!=(const CScriptNum& rhs) const { return operator!=(rhs.m_value); } + inline bool operator<=(const CScriptNum& rhs) const { return operator<=(rhs.m_value); } + inline bool operator< (const CScriptNum& rhs) const { return operator< (rhs.m_value); } + inline bool operator>=(const CScriptNum& rhs) const { return operator>=(rhs.m_value); } + inline bool operator> (const CScriptNum& rhs) const { return operator> (rhs.m_value); } + + inline CScriptNum operator+( const int64_t& rhs) const { return CScriptNum(m_value + rhs);} + inline CScriptNum operator-( const int64_t& rhs) const { return CScriptNum(m_value - rhs);} + inline CScriptNum operator+( const CScriptNum& rhs) const { return operator+(rhs.m_value); } + inline CScriptNum operator-( const CScriptNum& rhs) const { return operator-(rhs.m_value); } + + inline CScriptNum& operator+=( const CScriptNum& rhs) { return operator+=(rhs.m_value); } + inline CScriptNum& operator-=( const CScriptNum& rhs) { return operator-=(rhs.m_value); } + + inline CScriptNum operator-() const + { + assert(m_value != std::numeric_limits<int64_t>::min()); + return CScriptNum(-m_value); + } + + inline CScriptNum& operator=( const int64_t& rhs) + { + m_value = rhs; + return *this; + } + + inline CScriptNum& operator+=( const int64_t& rhs) + { + assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || + (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)); + m_value += rhs; + return *this; + } + + inline CScriptNum& operator-=( const int64_t& rhs) + { + assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || + (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)); + m_value -= rhs; + return *this; + } + + int getint() const + { + if (m_value > std::numeric_limits<int>::max()) + return std::numeric_limits<int>::max(); + else if (m_value < std::numeric_limits<int>::min()) + return std::numeric_limits<int>::min(); + return m_value; + } + + std::vector<unsigned char> getvch() const + { + return serialize(m_value); + } + + static std::vector<unsigned char> serialize(const int64_t& value) + { + if(value == 0) + return std::vector<unsigned char>(); + + std::vector<unsigned char> result; + const bool neg = value < 0; + uint64_t absvalue = neg ? -value : value; + + while(absvalue) + { + result.push_back(absvalue & 0xff); + absvalue >>= 8; + } + + +// - If the most significant byte is >= 0x80 and the value is positive, push a +// new zero-byte to make the significant byte < 0x80 again. + +// - If the most significant byte is >= 0x80 and the value is negative, push a +// new 0x80 byte that will be popped off when converting to an integral. + +// - If the most significant byte is < 0x80 and the value is negative, add +// 0x80 to it, since it will be subtracted and interpreted as a negative when +// converting to an integral. + + if (result.back() & 0x80) + result.push_back(neg ? 0x80 : 0); + else if (neg) + result.back() |= 0x80; + + return result; + } + + static const size_t nMaxNumSize = 4; + +private: + static int64_t set_vch(const std::vector<unsigned char>& vch) + { + if (vch.empty()) + return 0; + + int64_t result = 0; + for (size_t i = 0; i != vch.size(); ++i) + result |= static_cast<int64_t>(vch[i]) << 8*i; + + // If the input vector's most significant byte is 0x80, remove it from + // the result's msb and return a negative. + if (vch.back() & 0x80) + return -(result & ~(0x80 << (8 * (vch.size() - 1)))); + + return result; + } + + int64_t m_value; +}; + /** Signature hash types/flags */ enum { @@ -225,7 +373,7 @@ const char* GetOpName(opcodetype opcode); inline std::string ValueString(const std::vector<unsigned char>& vch) { if (vch.size() <= 4) - return strprintf("%d", CBigNum(vch).getint()); + return strprintf("%d", CScriptNum(vch).getint()); else return HexStr(vch); } @@ -261,26 +409,10 @@ protected: } else { - CBigNum bn(n); - *this << bn.getvch(); + *this << CScriptNum::serialize(n); } return *this; } - - CScript& push_uint64(uint64_t n) - { - if (n >= 1 && n <= 16) - { - push_back(n + (OP_1 - 1)); - } - else - { - CBigNum bn(n); - *this << bn.getvch(); - } - return *this; - } - public: CScript() { } CScript(const CScript& b) : std::vector<unsigned char>(b.begin(), b.end()) { } @@ -303,35 +435,15 @@ public: } - //explicit CScript(char b) is not portable. Use 'signed char' or 'unsigned char'. - explicit CScript(signed char b) { operator<<(b); } - explicit CScript(short b) { operator<<(b); } - explicit CScript(int b) { operator<<(b); } - explicit CScript(long b) { operator<<(b); } - explicit CScript(long long b) { operator<<(b); } - explicit CScript(unsigned char b) { operator<<(b); } - explicit CScript(unsigned int b) { operator<<(b); } - explicit CScript(unsigned short b) { operator<<(b); } - explicit CScript(unsigned long b) { operator<<(b); } - explicit CScript(unsigned long long b) { operator<<(b); } + CScript(int64_t b) { operator<<(b); } explicit CScript(opcodetype b) { operator<<(b); } explicit CScript(const uint256& b) { operator<<(b); } - explicit CScript(const CBigNum& b) { operator<<(b); } + explicit CScript(const CScriptNum& b) { operator<<(b); } explicit CScript(const std::vector<unsigned char>& b) { operator<<(b); } - //CScript& operator<<(char b) is not portable. Use 'signed char' or 'unsigned char'. - CScript& operator<<(signed char b) { return push_int64(b); } - CScript& operator<<(short b) { return push_int64(b); } - CScript& operator<<(int b) { return push_int64(b); } - CScript& operator<<(long b) { return push_int64(b); } - CScript& operator<<(long long b) { return push_int64(b); } - CScript& operator<<(unsigned char b) { return push_uint64(b); } - CScript& operator<<(unsigned int b) { return push_uint64(b); } - CScript& operator<<(unsigned short b) { return push_uint64(b); } - CScript& operator<<(unsigned long b) { return push_uint64(b); } - CScript& operator<<(unsigned long long b) { return push_uint64(b); } + CScript& operator<<(int64_t b) { return push_int64(b); } CScript& operator<<(opcodetype opcode) { @@ -363,7 +475,7 @@ public: return *this; } - CScript& operator<<(const CBigNum& b) + CScript& operator<<(const CScriptNum& b) { *this << b.getvch(); return *this; diff --git a/src/test/Makefile.am b/src/test/Makefile.am index b375ba1306..e12f4904f1 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -61,6 +61,7 @@ test_bitcoin_SOURCES = \ transaction_tests.cpp \ uint256_tests.cpp \ util_tests.cpp \ + scriptnum_tests.cpp \ sighash_tests.cpp \ $(JSON_TEST_FILES) $(RAW_TEST_FILES) diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json index 8cb365a46f..fdceb1ffa9 100644 --- a/src/test/data/script_invalid.json +++ b/src/test/data/script_invalid.json @@ -257,7 +257,10 @@ ["1","0xba", "0xba == OP_NOP10 + 1"], ["2147483648", "1ADD 1", "We cannot do math on 5-byte integers"], +["2147483648", "NEGATE 1", "We cannot do math on 5-byte integers"], ["-2147483648", "1ADD 1", "Because we use a sign bit, -2147483648 is also 5 bytes"], +["2147483647", "1ADD 1SUB 1", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], +["2147483648", "1SUB 1", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], ["1", "1 ENDIF", "ENDIF without IF"], ["1", "IF 1", "IF without ENDIF"], diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json index 3b4c191865..67b985e355 100644 --- a/src/test/data/script_valid.json +++ b/src/test/data/script_valid.json @@ -97,6 +97,9 @@ ["8388608", "SIZE 4 EQUAL"], ["2147483647", "SIZE 4 EQUAL"], ["2147483648", "SIZE 5 EQUAL"], +["549755813887", "SIZE 5 EQUAL"], +["549755813888", "SIZE 6 EQUAL"], +["9223372036854775807", "SIZE 8 EQUAL"], ["-1", "SIZE 1 EQUAL"], ["-127", "SIZE 1 EQUAL"], ["-128", "SIZE 2 EQUAL"], @@ -106,6 +109,9 @@ ["-8388608", "SIZE 4 EQUAL"], ["-2147483647", "SIZE 4 EQUAL"], ["-2147483648", "SIZE 5 EQUAL"], +["-549755813887", "SIZE 5 EQUAL"], +["-549755813888", "SIZE 6 EQUAL"], +["-9223372036854775807", "SIZE 8 EQUAL"], ["'abcdefghijklmnopqrstuvwxyz'", "SIZE 26 EQUAL"], @@ -306,6 +312,9 @@ ["8388608", "0x04 0x00008000 EQUAL"], ["2147483647", "0x04 0xFFFFFF7F EQUAL"], ["2147483648", "0x05 0x0000008000 EQUAL"], +["549755813887", "0x05 0xFFFFFFFF7F EQUAL"], +["549755813888", "0x06 0xFFFFFFFF7F EQUAL"], +["9223372036854775807", "0x08 0xFFFFFFFFFFFFFF7F EQUAL"], ["-1", "0x01 0x81 EQUAL", "Numbers are little-endian with the MSB being a sign bit"], ["-127", "0x01 0xFF EQUAL"], ["-128", "0x02 0x8080 EQUAL"], @@ -315,6 +324,10 @@ ["-8388608", "0x04 0x00008080 EQUAL"], ["-2147483647", "0x04 0xFFFFFFFF EQUAL"], ["-2147483648", "0x05 0x0000008080 EQUAL"], +["-4294967295", "0x05 0xFFFFFFFF80 EQUAL"], +["-549755813887", "0x05 0xFFFFFFFFFF EQUAL"], +["-549755813888", "0x06 0x000000008080 EQUAL"], +["-9223372036854775807", "0x08 0xFFFFFFFFFFFFFFFF EQUAL"], ["2147483647", "1ADD 2147483648 EQUAL", "We can do math on 4-byte integers, and compare 5-byte ones"], ["2147483647", "1ADD 1"], diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp new file mode 100644 index 0000000000..cd194cc4d9 --- /dev/null +++ b/src/test/scriptnum_tests.cpp @@ -0,0 +1,196 @@ +// Copyright (c) 2012-2014 The Bitcoin Core developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bignum.h" +#include "script.h" +#include <boost/test/unit_test.hpp> +#include <limits.h> +#include <stdint.h> +BOOST_AUTO_TEST_SUITE(scriptnum_tests) + +static const int64_t values[] = \ +{ 0, 1, CHAR_MIN, CHAR_MAX, UCHAR_MAX, SHRT_MIN, USHRT_MAX, INT_MIN, INT_MAX, UINT_MAX, LONG_MIN, LONG_MAX }; +static const int64_t offsets[] = { 1, 0x79, 0x80, 0x81, 0xFF, 0x7FFF, 0x8000, 0xFFFF, 0x10000}; + +static bool verify(const CBigNum& bignum, const CScriptNum& scriptnum) +{ + return bignum.getvch() == scriptnum.getvch() && bignum.getint() == scriptnum.getint(); +} + +static void CheckCreateVch(const int64_t& num) +{ + CBigNum bignum(num); + CScriptNum scriptnum(num); + BOOST_CHECK(verify(bignum, scriptnum)); + + CBigNum bignum2(bignum.getvch()); + CScriptNum scriptnum2(scriptnum.getvch()); + BOOST_CHECK(verify(bignum2, scriptnum2)); + + CBigNum bignum3(scriptnum2.getvch()); + CScriptNum scriptnum3(bignum2.getvch()); + BOOST_CHECK(verify(bignum3, scriptnum3)); +} + +static void CheckCreateInt(const int64_t& num) +{ + CBigNum bignum(num); + CScriptNum scriptnum(num); + BOOST_CHECK(verify(bignum, scriptnum)); + BOOST_CHECK(verify(bignum.getint(), CScriptNum(scriptnum.getint()))); + BOOST_CHECK(verify(scriptnum.getint(), CScriptNum(bignum.getint()))); + BOOST_CHECK(verify(CBigNum(scriptnum.getint()).getint(), CScriptNum(CScriptNum(bignum.getint()).getint()))); +} + + +static void CheckAdd(const int64_t& num1, const int64_t& num2) +{ + const CBigNum bignum1(num1); + const CBigNum bignum2(num2); + const CScriptNum scriptnum1(num1); + const CScriptNum scriptnum2(num2); + CBigNum bignum3(num1); + CBigNum bignum4(num1); + CScriptNum scriptnum3(num1); + CScriptNum scriptnum4(num1); + + // int64_t overflow is undefined. + bool invalid = (((num2 > 0) && (num1 > (std::numeric_limits<int64_t>::max() - num2))) || + ((num2 < 0) && (num1 < (std::numeric_limits<int64_t>::min() - num2)))); + if (!invalid) + { + BOOST_CHECK(verify(bignum1 + bignum2, scriptnum1 + scriptnum2)); + BOOST_CHECK(verify(bignum1 + bignum2, scriptnum1 + num2)); + BOOST_CHECK(verify(bignum1 + bignum2, scriptnum2 + num1)); + } +} + +static void CheckNegate(const int64_t& num) +{ + const CBigNum bignum(num); + const CScriptNum scriptnum(num); + + // -INT64_MIN is undefined + if (num != std::numeric_limits<int64_t>::min()) + BOOST_CHECK(verify(-bignum, -scriptnum)); +} + +static void CheckSubtract(const int64_t& num1, const int64_t& num2) +{ + const CBigNum bignum1(num1); + const CBigNum bignum2(num2); + const CScriptNum scriptnum1(num1); + const CScriptNum scriptnum2(num2); + bool invalid = false; + + // int64_t overflow is undefined. + invalid = ((num2 > 0 && num1 < std::numeric_limits<int64_t>::min() + num2) || + (num2 < 0 && num1 > std::numeric_limits<int64_t>::max() + num2)); + if (!invalid) + { + BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - scriptnum2)); + BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - num2)); + } + + invalid = ((num1 > 0 && num2 < std::numeric_limits<int64_t>::min() + num1) || + (num1 < 0 && num2 > std::numeric_limits<int64_t>::max() + num1)); + if (!invalid) + { + BOOST_CHECK(verify(bignum2 - bignum1, scriptnum2 - scriptnum1)); + BOOST_CHECK(verify(bignum2 - bignum1, scriptnum2 - num1)); + } +} + +static void CheckCompare(const int64_t& num1, const int64_t& num2) +{ + const CBigNum bignum1(num1); + const CBigNum bignum2(num2); + const CScriptNum scriptnum1(num1); + const CScriptNum scriptnum2(num2); + + BOOST_CHECK((bignum1 == bignum1) == (scriptnum1 == scriptnum1)); + BOOST_CHECK((bignum1 != bignum1) == (scriptnum1 != scriptnum1)); + BOOST_CHECK((bignum1 < bignum1) == (scriptnum1 < scriptnum1)); + BOOST_CHECK((bignum1 > bignum1) == (scriptnum1 > scriptnum1)); + BOOST_CHECK((bignum1 >= bignum1) == (scriptnum1 >= scriptnum1)); + BOOST_CHECK((bignum1 <= bignum1) == (scriptnum1 <= scriptnum1)); + + BOOST_CHECK((bignum1 == bignum1) == (scriptnum1 == num1)); + BOOST_CHECK((bignum1 != bignum1) == (scriptnum1 != num1)); + BOOST_CHECK((bignum1 < bignum1) == (scriptnum1 < num1)); + BOOST_CHECK((bignum1 > bignum1) == (scriptnum1 > num1)); + BOOST_CHECK((bignum1 >= bignum1) == (scriptnum1 >= num1)); + BOOST_CHECK((bignum1 <= bignum1) == (scriptnum1 <= num1)); + + BOOST_CHECK((bignum1 == bignum2) == (scriptnum1 == scriptnum2)); + BOOST_CHECK((bignum1 != bignum2) == (scriptnum1 != scriptnum2)); + BOOST_CHECK((bignum1 < bignum2) == (scriptnum1 < scriptnum2)); + BOOST_CHECK((bignum1 > bignum2) == (scriptnum1 > scriptnum2)); + BOOST_CHECK((bignum1 >= bignum2) == (scriptnum1 >= scriptnum2)); + BOOST_CHECK((bignum1 <= bignum2) == (scriptnum1 <= scriptnum2)); + + BOOST_CHECK((bignum1 == bignum2) == (scriptnum1 == num2)); + BOOST_CHECK((bignum1 != bignum2) == (scriptnum1 != num2)); + BOOST_CHECK((bignum1 < bignum2) == (scriptnum1 < num2)); + BOOST_CHECK((bignum1 > bignum2) == (scriptnum1 > num2)); + BOOST_CHECK((bignum1 >= bignum2) == (scriptnum1 >= num2)); + BOOST_CHECK((bignum1 <= bignum2) == (scriptnum1 <= num2)); +} + +static void RunCreate(const int64_t& num) +{ + CheckCreateInt(num); + CScriptNum scriptnum(num); + if (scriptnum.getvch().size() <= CScriptNum::nMaxNumSize) + CheckCreateVch(num); + else + { + BOOST_CHECK_THROW (CheckCreateVch(num), scriptnum_error); + } +} + +static void RunOperators(const int64_t& num1, const int64_t& num2) +{ + CheckAdd(num1, num2); + CheckSubtract(num1, num2); + CheckNegate(num1); + CheckCompare(num1, num2); +} + +BOOST_AUTO_TEST_CASE(creation) +{ + for(size_t i = 0; i < sizeof(values) / sizeof(values[0]); ++i) + { + for(size_t j = 0; j < sizeof(offsets) / sizeof(offsets[0]); ++j) + { + RunCreate(values[i]); + RunCreate(values[i] + offsets[j]); + RunCreate(values[i] - offsets[j]); + } + } +} + +BOOST_AUTO_TEST_CASE(operators) +{ + for(size_t i = 0; i < sizeof(values) / sizeof(values[0]); ++i) + { + for(size_t j = 0; j < sizeof(offsets) / sizeof(offsets[0]); ++j) + { + RunOperators(values[i], values[i]); + RunOperators(values[i], -values[i]); + RunOperators(values[i], values[j]); + RunOperators(values[i], -values[j]); + RunOperators(values[i] + values[j], values[j]); + RunOperators(values[i] + values[j], -values[j]); + RunOperators(values[i] - values[j], values[j]); + RunOperators(values[i] - values[j], -values[j]); + RunOperators(values[i] + values[j], values[i] + values[j]); + RunOperators(values[i] + values[j], values[i] - values[j]); + RunOperators(values[i] - values[j], values[i] + values[j]); + RunOperators(values[i] - values[j], values[i] - values[j]); + } + } +} + +BOOST_AUTO_TEST_SUITE_END() |