Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class CMainParams : public CChainParams {
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);
Expand Down
2 changes: 1 addition & 1 deletion src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
45 changes: 17 additions & 28 deletions src/script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

#include "script.h"

#include "bignum.h"
#include "core.h"
#include "hash.h"
#include "key.h"
Expand All @@ -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++)
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
198 changes: 155 additions & 43 deletions src/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#ifndef H_BITCOIN_SCRIPT
#define H_BITCOIN_SCRIPT

#include "bignum.h"
#include "key.h"
#include "util.h"

Expand All @@ -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],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is not wrong, but misleading. An input 0x0000000000 would be rejected, even though it is within that range.

// 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
{
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -261,26 +409,10 @@ class CScript : public std::vector<unsigned char>
}
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()) { }
Expand All @@ -303,35 +435,15 @@ class CScript : public std::vector<unsigned char>
}


//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)
{
Expand Down Expand Up @@ -363,7 +475,7 @@ class CScript : public std::vector<unsigned char>
return *this;
}

CScript& operator<<(const CBigNum& b)
CScript& operator<<(const CScriptNum& b)
{
*this << b.getvch();
return *this;
Expand Down
Loading