Skip to content

Commit 1c0319b

Browse files
committed
Merge pull request #3965
b1fdd54 script: Add test for CScriptNum (Cory Fields) 90320d6 script: add additional script tests (Cory Fields) 05e3ecf script: remove bignum dependency (Cory Fields) 4f497cd script: switch outside users to CScriptNum (Cory Fields) 27bff74 script: switch to CScriptNum usage for scripts (Cory Fields) 48d8eb1 script: add CScriptNum class (Cory Fields)
2 parents d54985f + b1fdd54 commit 1c0319b

File tree

8 files changed

+387
-73
lines changed

8 files changed

+387
-73
lines changed

src/chainparams.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ class CMainParams : public CChainParams {
125125
CTransaction txNew;
126126
txNew.vin.resize(1);
127127
txNew.vout.resize(1);
128-
txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
128+
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
129129
txNew.vout[0].nValue = 50 * COIN;
130130
txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
131131
genesis.vtx.push_back(txNew);

src/miner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
355355
}
356356
++nExtraNonce;
357357
unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
358-
pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CBigNum(nExtraNonce)) + COINBASE_FLAGS;
358+
pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
359359
assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
360360

361361
pblock->hashMerkleRoot = pblock->BuildMerkleTree();

src/script.cpp

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
#include "script.h"
77

8-
#include "bignum.h"
98
#include "core.h"
109
#include "hash.h"
1110
#include "key.h"
@@ -25,22 +24,13 @@ typedef vector<unsigned char> valtype;
2524
static const valtype vchFalse(0);
2625
static const valtype vchZero(0);
2726
static const valtype vchTrue(1, 1);
28-
static const CBigNum bnZero(0);
29-
static const CBigNum bnOne(1);
30-
static const CBigNum bnFalse(0);
31-
static const CBigNum bnTrue(1);
32-
static const size_t nMaxNumSize = 4;
27+
static const CScriptNum bnZero(0);
28+
static const CScriptNum bnOne(1);
29+
static const CScriptNum bnFalse(0);
30+
static const CScriptNum bnTrue(1);
3331

3432
bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags);
3533

36-
CBigNum CastToBigNum(const valtype& vch)
37-
{
38-
if (vch.size() > nMaxNumSize)
39-
throw runtime_error("CastToBigNum() : overflow");
40-
// Get rid of extra leading zeros
41-
return CBigNum(CBigNum(vch).getvch());
42-
}
43-
4434
bool CastToBool(const valtype& vch)
4535
{
4636
for (unsigned int i = 0; i < vch.size(); i++)
@@ -306,7 +296,6 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) {
306296

307297
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType)
308298
{
309-
CAutoBN_CTX pctx;
310299
CScript::const_iterator pc = script.begin();
311300
CScript::const_iterator pend = script.end();
312301
CScript::const_iterator pbegincodehash = script.begin();
@@ -380,7 +369,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
380369
case OP_16:
381370
{
382371
// ( -- value)
383-
CBigNum bn((int)opcode - (int)(OP_1 - 1));
372+
CScriptNum bn((int)opcode - (int)(OP_1 - 1));
384373
stack.push_back(bn.getvch());
385374
}
386375
break;
@@ -556,7 +545,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
556545
case OP_DEPTH:
557546
{
558547
// -- stacksize
559-
CBigNum bn(stack.size());
548+
CScriptNum bn(stack.size());
560549
stack.push_back(bn.getvch());
561550
}
562551
break;
@@ -606,7 +595,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
606595
// (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
607596
if (stack.size() < 2)
608597
return false;
609-
int n = CastToBigNum(stacktop(-1)).getint();
598+
int n = CScriptNum(stacktop(-1)).getint();
610599
popstack(stack);
611600
if (n < 0 || n >= (int)stack.size())
612601
return false;
@@ -654,7 +643,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
654643
// (in -- in size)
655644
if (stack.size() < 1)
656645
return false;
657-
CBigNum bn(stacktop(-1).size());
646+
CScriptNum bn(stacktop(-1).size());
658647
stack.push_back(bn.getvch());
659648
}
660649
break;
@@ -705,7 +694,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
705694
// (in -- out)
706695
if (stack.size() < 1)
707696
return false;
708-
CBigNum bn = CastToBigNum(stacktop(-1));
697+
CScriptNum bn(stacktop(-1));
709698
switch (opcode)
710699
{
711700
case OP_1ADD: bn += bnOne; break;
@@ -738,9 +727,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
738727
// (x1 x2 -- out)
739728
if (stack.size() < 2)
740729
return false;
741-
CBigNum bn1 = CastToBigNum(stacktop(-2));
742-
CBigNum bn2 = CastToBigNum(stacktop(-1));
743-
CBigNum bn;
730+
CScriptNum bn1(stacktop(-2));
731+
CScriptNum bn2(stacktop(-1));
732+
CScriptNum bn(0);
744733
switch (opcode)
745734
{
746735
case OP_ADD:
@@ -783,9 +772,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
783772
// (x min max -- out)
784773
if (stack.size() < 3)
785774
return false;
786-
CBigNum bn1 = CastToBigNum(stacktop(-3));
787-
CBigNum bn2 = CastToBigNum(stacktop(-2));
788-
CBigNum bn3 = CastToBigNum(stacktop(-1));
775+
CScriptNum bn1(stacktop(-3));
776+
CScriptNum bn2(stacktop(-2));
777+
CScriptNum bn3(stacktop(-1));
789778
bool fValue = (bn2 <= bn1 && bn1 < bn3);
790779
popstack(stack);
791780
popstack(stack);
@@ -882,7 +871,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
882871
if ((int)stack.size() < i)
883872
return false;
884873

885-
int nKeysCount = CastToBigNum(stacktop(-i)).getint();
874+
int nKeysCount = CScriptNum(stacktop(-i)).getint();
886875
if (nKeysCount < 0 || nKeysCount > 20)
887876
return false;
888877
nOpCount += nKeysCount;
@@ -893,7 +882,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
893882
if ((int)stack.size() < i)
894883
return false;
895884

896-
int nSigsCount = CastToBigNum(stacktop(-i)).getint();
885+
int nSigsCount = CScriptNum(stacktop(-i)).getint();
897886
if (nSigsCount < 0 || nSigsCount > nKeysCount)
898887
return false;
899888
int isig = ++i;

src/script.h

Lines changed: 155 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#ifndef H_BITCOIN_SCRIPT
77
#define H_BITCOIN_SCRIPT
88

9-
#include "bignum.h"
109
#include "key.h"
1110
#include "util.h"
1211

@@ -25,6 +24,155 @@ class CTransaction;
2524
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
2625
static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes
2726

27+
class scriptnum_error : public std::runtime_error
28+
{
29+
public:
30+
explicit scriptnum_error(const std::string& str) : std::runtime_error(str) {}
31+
};
32+
33+
class CScriptNum
34+
{
35+
// Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers.
36+
// The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1],
37+
// but results may overflow (and are valid as long as they are not used in a subsequent
38+
// numeric operation). CScriptNum enforces those semantics by storing results as
39+
// an int64 and allowing out-of-range values to be returned as a vector of bytes but
40+
// throwing an exception if arithmetic is done or the result is interpreted as an integer.
41+
public:
42+
43+
explicit CScriptNum(const int64_t& n)
44+
{
45+
m_value = n;
46+
}
47+
48+
explicit CScriptNum(const std::vector<unsigned char>& vch)
49+
{
50+
if (vch.size() > nMaxNumSize)
51+
throw scriptnum_error("CScriptNum(const std::vector<unsigned char>&) : overflow");
52+
m_value = set_vch(vch);
53+
}
54+
55+
inline bool operator==(const int64_t& rhs) const { return m_value == rhs; }
56+
inline bool operator!=(const int64_t& rhs) const { return m_value != rhs; }
57+
inline bool operator<=(const int64_t& rhs) const { return m_value <= rhs; }
58+
inline bool operator< (const int64_t& rhs) const { return m_value < rhs; }
59+
inline bool operator>=(const int64_t& rhs) const { return m_value >= rhs; }
60+
inline bool operator> (const int64_t& rhs) const { return m_value > rhs; }
61+
62+
inline bool operator==(const CScriptNum& rhs) const { return operator==(rhs.m_value); }
63+
inline bool operator!=(const CScriptNum& rhs) const { return operator!=(rhs.m_value); }
64+
inline bool operator<=(const CScriptNum& rhs) const { return operator<=(rhs.m_value); }
65+
inline bool operator< (const CScriptNum& rhs) const { return operator< (rhs.m_value); }
66+
inline bool operator>=(const CScriptNum& rhs) const { return operator>=(rhs.m_value); }
67+
inline bool operator> (const CScriptNum& rhs) const { return operator> (rhs.m_value); }
68+
69+
inline CScriptNum operator+( const int64_t& rhs) const { return CScriptNum(m_value + rhs);}
70+
inline CScriptNum operator-( const int64_t& rhs) const { return CScriptNum(m_value - rhs);}
71+
inline CScriptNum operator+( const CScriptNum& rhs) const { return operator+(rhs.m_value); }
72+
inline CScriptNum operator-( const CScriptNum& rhs) const { return operator-(rhs.m_value); }
73+
74+
inline CScriptNum& operator+=( const CScriptNum& rhs) { return operator+=(rhs.m_value); }
75+
inline CScriptNum& operator-=( const CScriptNum& rhs) { return operator-=(rhs.m_value); }
76+
77+
inline CScriptNum operator-() const
78+
{
79+
assert(m_value != std::numeric_limits<int64_t>::min());
80+
return CScriptNum(-m_value);
81+
}
82+
83+
inline CScriptNum& operator=( const int64_t& rhs)
84+
{
85+
m_value = rhs;
86+
return *this;
87+
}
88+
89+
inline CScriptNum& operator+=( const int64_t& rhs)
90+
{
91+
assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) ||
92+
(rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs));
93+
m_value += rhs;
94+
return *this;
95+
}
96+
97+
inline CScriptNum& operator-=( const int64_t& rhs)
98+
{
99+
assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) ||
100+
(rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs));
101+
m_value -= rhs;
102+
return *this;
103+
}
104+
105+
int getint() const
106+
{
107+
if (m_value > std::numeric_limits<int>::max())
108+
return std::numeric_limits<int>::max();
109+
else if (m_value < std::numeric_limits<int>::min())
110+
return std::numeric_limits<int>::min();
111+
return m_value;
112+
}
113+
114+
std::vector<unsigned char> getvch() const
115+
{
116+
return serialize(m_value);
117+
}
118+
119+
static std::vector<unsigned char> serialize(const int64_t& value)
120+
{
121+
if(value == 0)
122+
return std::vector<unsigned char>();
123+
124+
std::vector<unsigned char> result;
125+
const bool neg = value < 0;
126+
uint64_t absvalue = neg ? -value : value;
127+
128+
while(absvalue)
129+
{
130+
result.push_back(absvalue & 0xff);
131+
absvalue >>= 8;
132+
}
133+
134+
135+
// - If the most significant byte is >= 0x80 and the value is positive, push a
136+
// new zero-byte to make the significant byte < 0x80 again.
137+
138+
// - If the most significant byte is >= 0x80 and the value is negative, push a
139+
// new 0x80 byte that will be popped off when converting to an integral.
140+
141+
// - If the most significant byte is < 0x80 and the value is negative, add
142+
// 0x80 to it, since it will be subtracted and interpreted as a negative when
143+
// converting to an integral.
144+
145+
if (result.back() & 0x80)
146+
result.push_back(neg ? 0x80 : 0);
147+
else if (neg)
148+
result.back() |= 0x80;
149+
150+
return result;
151+
}
152+
153+
static const size_t nMaxNumSize = 4;
154+
155+
private:
156+
static int64_t set_vch(const std::vector<unsigned char>& vch)
157+
{
158+
if (vch.empty())
159+
return 0;
160+
161+
int64_t result = 0;
162+
for (size_t i = 0; i != vch.size(); ++i)
163+
result |= static_cast<int64_t>(vch[i]) << 8*i;
164+
165+
// If the input vector's most significant byte is 0x80, remove it from
166+
// the result's msb and return a negative.
167+
if (vch.back() & 0x80)
168+
return -(result & ~(0x80 << (8 * (vch.size() - 1))));
169+
170+
return result;
171+
}
172+
173+
int64_t m_value;
174+
};
175+
28176
/** Signature hash types/flags */
29177
enum
30178
{
@@ -225,7 +373,7 @@ const char* GetOpName(opcodetype opcode);
225373
inline std::string ValueString(const std::vector<unsigned char>& vch)
226374
{
227375
if (vch.size() <= 4)
228-
return strprintf("%d", CBigNum(vch).getint());
376+
return strprintf("%d", CScriptNum(vch).getint());
229377
else
230378
return HexStr(vch);
231379
}
@@ -261,26 +409,10 @@ class CScript : public std::vector<unsigned char>
261409
}
262410
else
263411
{
264-
CBigNum bn(n);
265-
*this << bn.getvch();
412+
*this << CScriptNum::serialize(n);
266413
}
267414
return *this;
268415
}
269-
270-
CScript& push_uint64(uint64_t n)
271-
{
272-
if (n >= 1 && n <= 16)
273-
{
274-
push_back(n + (OP_1 - 1));
275-
}
276-
else
277-
{
278-
CBigNum bn(n);
279-
*this << bn.getvch();
280-
}
281-
return *this;
282-
}
283-
284416
public:
285417
CScript() { }
286418
CScript(const CScript& b) : std::vector<unsigned char>(b.begin(), b.end()) { }
@@ -303,35 +435,15 @@ class CScript : public std::vector<unsigned char>
303435
}
304436

305437

306-
//explicit CScript(char b) is not portable. Use 'signed char' or 'unsigned char'.
307-
explicit CScript(signed char b) { operator<<(b); }
308-
explicit CScript(short b) { operator<<(b); }
309-
explicit CScript(int b) { operator<<(b); }
310-
explicit CScript(long b) { operator<<(b); }
311-
explicit CScript(long long b) { operator<<(b); }
312-
explicit CScript(unsigned char b) { operator<<(b); }
313-
explicit CScript(unsigned int b) { operator<<(b); }
314-
explicit CScript(unsigned short b) { operator<<(b); }
315-
explicit CScript(unsigned long b) { operator<<(b); }
316-
explicit CScript(unsigned long long b) { operator<<(b); }
438+
CScript(int64_t b) { operator<<(b); }
317439

318440
explicit CScript(opcodetype b) { operator<<(b); }
319441
explicit CScript(const uint256& b) { operator<<(b); }
320-
explicit CScript(const CBigNum& b) { operator<<(b); }
442+
explicit CScript(const CScriptNum& b) { operator<<(b); }
321443
explicit CScript(const std::vector<unsigned char>& b) { operator<<(b); }
322444

323445

324-
//CScript& operator<<(char b) is not portable. Use 'signed char' or 'unsigned char'.
325-
CScript& operator<<(signed char b) { return push_int64(b); }
326-
CScript& operator<<(short b) { return push_int64(b); }
327-
CScript& operator<<(int b) { return push_int64(b); }
328-
CScript& operator<<(long b) { return push_int64(b); }
329-
CScript& operator<<(long long b) { return push_int64(b); }
330-
CScript& operator<<(unsigned char b) { return push_uint64(b); }
331-
CScript& operator<<(unsigned int b) { return push_uint64(b); }
332-
CScript& operator<<(unsigned short b) { return push_uint64(b); }
333-
CScript& operator<<(unsigned long b) { return push_uint64(b); }
334-
CScript& operator<<(unsigned long long b) { return push_uint64(b); }
446+
CScript& operator<<(int64_t b) { return push_int64(b); }
335447

336448
CScript& operator<<(opcodetype opcode)
337449
{
@@ -363,7 +475,7 @@ class CScript : public std::vector<unsigned char>
363475
return *this;
364476
}
365477

366-
CScript& operator<<(const CBigNum& b)
478+
CScript& operator<<(const CScriptNum& b)
367479
{
368480
*this << b.getvch();
369481
return *this;

0 commit comments

Comments
 (0)