@ -13,7 +13,6 @@
# include "pubkey.h"
# include "pubkey.h"
# include "script/script.h"
# include "script/script.h"
# include "uint256.h"
# include "uint256.h"
# include "util.h"
using namespace std ;
using namespace std ;
@ -26,6 +25,24 @@ static const CScriptNum bnOne(1);
static const CScriptNum bnFalse ( 0 ) ;
static const CScriptNum bnFalse ( 0 ) ;
static const CScriptNum bnTrue ( 1 ) ;
static const CScriptNum bnTrue ( 1 ) ;
namespace {
inline bool set_success ( ScriptError * ret )
{
if ( ret )
* ret = SCRIPT_ERR_OK ;
return true ;
}
inline bool set_error ( ScriptError * ret , const ScriptError serror )
{
if ( ret )
* ret = serror ;
return false ;
}
} // anon namespace
bool CastToBool ( const valtype & vch )
bool CastToBool ( const valtype & vch )
{
{
for ( unsigned int i = 0 ; i < vch . size ( ) ; i + + )
for ( unsigned int i = 0 ; i < vch . size ( ) ; i + + )
@ -55,16 +72,23 @@ static inline void popstack(vector<valtype>& stack)
}
}
bool static IsCompressedOrUncompressedPubKey ( const valtype & vchPubKey ) {
bool static IsCompressedOrUncompressedPubKey ( const valtype & vchPubKey ) {
if ( vchPubKey . size ( ) < 33 )
if ( vchPubKey . size ( ) < 33 ) {
return error ( " Non-canonical public key: too short " ) ;
// Non-canonical public key: too short
return false ;
}
if ( vchPubKey [ 0 ] = = 0x04 ) {
if ( vchPubKey [ 0 ] = = 0x04 ) {
if ( vchPubKey . size ( ) ! = 65 )
if ( vchPubKey . size ( ) ! = 65 ) {
return error ( " Non-canonical public key: invalid length for uncompressed key " ) ;
// Non-canonical public key: invalid length for uncompressed key
return false ;
}
} else if ( vchPubKey [ 0 ] = = 0x02 | | vchPubKey [ 0 ] = = 0x03 ) {
} else if ( vchPubKey [ 0 ] = = 0x02 | | vchPubKey [ 0 ] = = 0x03 ) {
if ( vchPubKey . size ( ) ! = 33 )
if ( vchPubKey . size ( ) ! = 33 ) {
return error ( " Non-canonical public key: invalid length for compressed key " ) ;
// Non-canonical public key: invalid length for compressed key
return false ;
}
} else {
} else {
return error ( " Non-canonical public key: neither compressed nor uncompressed " ) ;
// Non-canonical public key: neither compressed nor uncompressed
return false ;
}
}
return true ;
return true ;
}
}
@ -79,47 +103,74 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
*/
*/
bool static IsDERSignature ( const valtype & vchSig ) {
bool static IsDERSignature ( const valtype & vchSig ) {
if ( vchSig . size ( ) < 9 )
if ( vchSig . size ( ) < 9 ) {
return error ( " Non-canonical signature: too short " ) ;
// Non-canonical signature: too short
if ( vchSig . size ( ) > 73 )
return false ;
return error ( " Non-canonical signature: too long " ) ;
}
if ( vchSig [ 0 ] ! = 0x30 )
if ( vchSig . size ( ) > 73 ) {
return error ( " Non-canonical signature: wrong type " ) ;
// Non-canonical signature: too long
if ( vchSig [ 1 ] ! = vchSig . size ( ) - 3 )
return false ;
return error ( " Non-canonical signature: wrong length marker " ) ;
}
if ( vchSig [ 0 ] ! = 0x30 ) {
// Non-canonical signature: wrong type
return false ;
}
if ( vchSig [ 1 ] ! = vchSig . size ( ) - 3 ) {
// Non-canonical signature: wrong length marker
return false ;
}
unsigned int nLenR = vchSig [ 3 ] ;
unsigned int nLenR = vchSig [ 3 ] ;
if ( 5 + nLenR > = vchSig . size ( ) )
if ( 5 + nLenR > = vchSig . size ( ) ) {
return error ( " Non-canonical signature: S length misplaced " ) ;
// Non-canonical signature: S length misplaced
return false ;
}
unsigned int nLenS = vchSig [ 5 + nLenR ] ;
unsigned int nLenS = vchSig [ 5 + nLenR ] ;
if ( ( unsigned long ) ( nLenR + nLenS + 7 ) ! = vchSig . size ( ) )
if ( ( unsigned long ) ( nLenR + nLenS + 7 ) ! = vchSig . size ( ) ) {
return error ( " Non-canonical signature: R+S length mismatch " ) ;
// Non-canonical signature: R+S length mismatch
return false ;
}
const unsigned char * R = & vchSig [ 4 ] ;
const unsigned char * R = & vchSig [ 4 ] ;
if ( R [ - 2 ] ! = 0x02 )
if ( R [ - 2 ] ! = 0x02 ) {
return error ( " Non-canonical signature: R value type mismatch " ) ;
// Non-canonical signature: R value type mismatch
if ( nLenR = = 0 )
return false ;
return error ( " Non-canonical signature: R length is zero " ) ;
}
if ( R [ 0 ] & 0x80 )
if ( nLenR = = 0 ) {
return error ( " Non-canonical signature: R value negative " ) ;
// Non-canonical signature: R length is zero
if ( nLenR > 1 & & ( R [ 0 ] = = 0x00 ) & & ! ( R [ 1 ] & 0x80 ) )
return false ;
return error ( " Non-canonical signature: R value excessively padded " ) ;
}
if ( R [ 0 ] & 0x80 ) {
// Non-canonical signature: R value negative
return false ;
}
if ( nLenR > 1 & & ( R [ 0 ] = = 0x00 ) & & ! ( R [ 1 ] & 0x80 ) ) {
// Non-canonical signature: R value excessively padded
return false ;
}
const unsigned char * S = & vchSig [ 6 + nLenR ] ;
const unsigned char * S = & vchSig [ 6 + nLenR ] ;
if ( S [ - 2 ] ! = 0x02 )
if ( S [ - 2 ] ! = 0x02 ) {
return error ( " Non-canonical signature: S value type mismatch " ) ;
// Non-canonical signature: S value type mismatch
if ( nLenS = = 0 )
return false ;
return error ( " Non-canonical signature: S length is zero " ) ;
}
if ( S [ 0 ] & 0x80 )
if ( nLenS = = 0 ) {
return error ( " Non-canonical signature: S value negative " ) ;
// Non-canonical signature: S length is zero
if ( nLenS > 1 & & ( S [ 0 ] = = 0x00 ) & & ! ( S [ 1 ] & 0x80 ) )
return false ;
return error ( " Non-canonical signature: S value excessively padded " ) ;
}
if ( S [ 0 ] & 0x80 ) {
// Non-canonical signature: S value negative
return false ;
}
if ( nLenS > 1 & & ( S [ 0 ] = = 0x00 ) & & ! ( S [ 1 ] & 0x80 ) ) {
// Non-canonical signature: S value excessively padded
return false ;
}
return true ;
return true ;
}
}
bool static IsLowDERSignature ( const valtype & vchSig ) {
bool static IsLowDERSignature ( const valtype & vchSig , ScriptError * serror ) {
if ( ! IsDERSignature ( vchSig ) ) {
if ( ! IsDERSignature ( vchSig ) ) {
return false ;
return set_error ( serror , SCRIPT_ERR_SIG_DER ) ;
}
}
unsigned int nLenR = vchSig [ 3 ] ;
unsigned int nLenR = vchSig [ 3 ] ;
unsigned int nLenS = vchSig [ 5 + nLenR ] ;
unsigned int nLenS = vchSig [ 5 + nLenR ] ;
@ -128,7 +179,7 @@ bool static IsLowDERSignature(const valtype &vchSig) {
// complement modulo the order could have been used instead, which is
// complement modulo the order could have been used instead, which is
// one byte shorter when encoded correctly.
// one byte shorter when encoded correctly.
if ( ! eccrypto : : CheckSignatureElement ( S , nLenS , true ) )
if ( ! eccrypto : : CheckSignatureElement ( S , nLenS , true ) )
return error ( " Non-canonical signature: S value is unnecessarily high " ) ;
return set_error ( serror , SCRIPT_ERR_SIG_HIGH_S ) ;
return true ;
return true ;
}
}
@ -139,18 +190,19 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
}
}
unsigned char nHashType = vchSig [ vchSig . size ( ) - 1 ] & ( ~ ( SIGHASH_ANYONECANPAY ) ) ;
unsigned char nHashType = vchSig [ vchSig . size ( ) - 1 ] & ( ~ ( SIGHASH_ANYONECANPAY ) ) ;
if ( nHashType < SIGHASH_ALL | | nHashType > SIGHASH_SINGLE )
if ( nHashType < SIGHASH_ALL | | nHashType > SIGHASH_SINGLE )
return error ( " Non-canonical signature: unknown hashtype byte " ) ;
return false ;
return true ;
return true ;
}
}
bool static CheckSignatureEncoding ( const valtype & vchSig , unsigned int flags ) {
bool static CheckSignatureEncoding ( const valtype & vchSig , unsigned int flags , ScriptError * serror ) {
if ( ( flags & ( SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC ) ) ! = 0 & & ! IsDERSignature ( vchSig ) ) {
if ( ( flags & ( SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC ) ) ! = 0 & & ! IsDERSignature ( vchSig ) ) {
return false ;
return set_error ( serror , SCRIPT_ERR_SIG_DER ) ;
} else if ( ( flags & SCRIPT_VERIFY_LOW_S ) ! = 0 & & ! IsLowDERSignature ( vchSig ) ) {
} else if ( ( flags & SCRIPT_VERIFY_LOW_S ) ! = 0 & & ! IsLowDERSignature ( vchSig , serror ) ) {
// serror is set
return false ;
return false ;
} else if ( ( flags & SCRIPT_VERIFY_STRICTENC ) ! = 0 & & ! IsDefinedHashtypeSignature ( vchSig ) ) {
} else if ( ( flags & SCRIPT_VERIFY_STRICTENC ) ! = 0 & & ! IsDefinedHashtypeSignature ( vchSig ) ) {
return false ;
return set_error ( serror , SCRIPT_ERR_SIG_HASHTYPE ) ;
}
}
return true ;
return true ;
}
}
@ -185,7 +237,7 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
return true ;
return true ;
}
}
bool EvalScript ( vector < vector < unsigned char > > & stack , const CScript & script , unsigned int flags , const BaseSignatureChecker & checker )
bool EvalScript ( vector < vector < unsigned char > > & stack , const CScript & script , unsigned int flags , const BaseSignatureChecker & checker , ScriptError * serror )
{
{
CScript : : const_iterator pc = script . begin ( ) ;
CScript : : const_iterator pc = script . begin ( ) ;
CScript : : const_iterator pend = script . end ( ) ;
CScript : : const_iterator pend = script . end ( ) ;
@ -194,8 +246,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
valtype vchPushValue ;
valtype vchPushValue ;
vector < bool > vfExec ;
vector < bool > vfExec ;
vector < valtype > altstack ;
vector < valtype > altstack ;
set_error ( serror , SCRIPT_ERR_UNKNOWN_ERROR ) ;
if ( script . size ( ) > 10000 )
if ( script . size ( ) > 10000 )
return false ;
return set_error ( serror , SCRIPT_ERR_SCRIPT_SIZE ) ;
int nOpCount = 0 ;
int nOpCount = 0 ;
bool fRequireMinimal = ( flags & SCRIPT_VERIFY_MINIMALDATA ) ! = 0 ;
bool fRequireMinimal = ( flags & SCRIPT_VERIFY_MINIMALDATA ) ! = 0 ;
@ -209,13 +262,13 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Read instruction
// Read instruction
//
//
if ( ! script . GetOp ( pc , opcode , vchPushValue ) )
if ( ! script . GetOp ( pc , opcode , vchPushValue ) )
return false ;
return set_error ( serror , SCRIPT_ERR_BAD_OPCODE ) ;
if ( vchPushValue . size ( ) > MAX_SCRIPT_ELEMENT_SIZE )
if ( vchPushValue . size ( ) > MAX_SCRIPT_ELEMENT_SIZE )
return false ;
return set_error ( serror , SCRIPT_ERR_PUSH_SIZE ) ;
// Note how OP_RESERVED does not count towards the opcode limit.
// Note how OP_RESERVED does not count towards the opcode limit.
if ( opcode > OP_16 & & + + nOpCount > 201 )
if ( opcode > OP_16 & & + + nOpCount > 201 )
return false ;
return set_error ( serror , SCRIPT_ERR_OP_COUNT ) ;
if ( opcode = = OP_CAT | |
if ( opcode = = OP_CAT | |
opcode = = OP_SUBSTR | |
opcode = = OP_SUBSTR | |
@ -232,11 +285,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
opcode = = OP_MOD | |
opcode = = OP_MOD | |
opcode = = OP_LSHIFT | |
opcode = = OP_LSHIFT | |
opcode = = OP_RSHIFT )
opcode = = OP_RSHIFT )
return false ; // Disabled opcodes.
return set_error ( serror , SCRIPT_ERR_DISABLED_OPCODE ) ; // Disabled opcodes.
if ( fExec & & 0 < = opcode & & opcode < = OP_PUSHDATA4 ) {
if ( fExec & & 0 < = opcode & & opcode < = OP_PUSHDATA4 ) {
if ( fRequireMinimal & & ! CheckMinimalPush ( vchPushValue , opcode ) ) {
if ( fRequireMinimal & & ! CheckMinimalPush ( vchPushValue , opcode ) ) {
return false ;
return set_error ( serror , SCRIPT_ERR_MINIMALDATA ) ;
}
}
stack . push_back ( vchPushValue ) ;
stack . push_back ( vchPushValue ) ;
} else if ( fExec | | ( OP_IF < = opcode & & opcode < = OP_ENDIF ) )
} else if ( fExec | | ( OP_IF < = opcode & & opcode < = OP_ENDIF ) )
@ -288,7 +341,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if ( fExec )
if ( fExec )
{
{
if ( stack . size ( ) < 1 )
if ( stack . size ( ) < 1 )
return false ;
return set_error ( serror , SCRIPT_ERR_UNBALANCED_CONDITIONAL ) ;
valtype & vch = stacktop ( - 1 ) ;
valtype & vch = stacktop ( - 1 ) ;
fValue = CastToBool ( vch ) ;
fValue = CastToBool ( vch ) ;
if ( opcode = = OP_NOTIF )
if ( opcode = = OP_NOTIF )
@ -302,7 +355,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
case OP_ELSE :
case OP_ELSE :
{
{
if ( vfExec . empty ( ) )
if ( vfExec . empty ( ) )
return false ;
return set_error ( serror , SCRIPT_ERR_UNBALANCED_CONDITIONAL ) ;
vfExec . back ( ) = ! vfExec . back ( ) ;
vfExec . back ( ) = ! vfExec . back ( ) ;
}
}
break ;
break ;
@ -310,7 +363,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
case OP_ENDIF :
case OP_ENDIF :
{
{
if ( vfExec . empty ( ) )
if ( vfExec . empty ( ) )
return false ;
return set_error ( serror , SCRIPT_ERR_UNBALANCED_CONDITIONAL ) ;
vfExec . pop_back ( ) ;
vfExec . pop_back ( ) ;
}
}
break ;
break ;
@ -320,18 +373,18 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// (true -- ) or
// (true -- ) or
// (false -- false) and return
// (false -- false) and return
if ( stack . size ( ) < 1 )
if ( stack . size ( ) < 1 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
bool fValue = CastToBool ( stacktop ( - 1 ) ) ;
bool fValue = CastToBool ( stacktop ( - 1 ) ) ;
if ( fValue )
if ( fValue )
popstack ( stack ) ;
popstack ( stack ) ;
else
else
return false ;
return set_error ( serror , SCRIPT_ERR_VERIFY ) ;
}
}
break ;
break ;
case OP_RETURN :
case OP_RETURN :
{
{
return false ;
return set_error ( serror , SCRIPT_ERR_OP_RETURN ) ;
}
}
break ;
break ;
@ -342,7 +395,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
case OP_TOALTSTACK :
case OP_TOALTSTACK :
{
{
if ( stack . size ( ) < 1 )
if ( stack . size ( ) < 1 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
altstack . push_back ( stacktop ( - 1 ) ) ;
altstack . push_back ( stacktop ( - 1 ) ) ;
popstack ( stack ) ;
popstack ( stack ) ;
}
}
@ -351,7 +404,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
case OP_FROMALTSTACK :
case OP_FROMALTSTACK :
{
{
if ( altstack . size ( ) < 1 )
if ( altstack . size ( ) < 1 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_ALTSTACK_OPERATION ) ;
stack . push_back ( altstacktop ( - 1 ) ) ;
stack . push_back ( altstacktop ( - 1 ) ) ;
popstack ( altstack ) ;
popstack ( altstack ) ;
}
}
@ -361,7 +414,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x1 x2 -- )
// (x1 x2 -- )
if ( stack . size ( ) < 2 )
if ( stack . size ( ) < 2 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
popstack ( stack ) ;
popstack ( stack ) ;
popstack ( stack ) ;
popstack ( stack ) ;
}
}
@ -371,7 +424,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x1 x2 -- x1 x2 x1 x2)
// (x1 x2 -- x1 x2 x1 x2)
if ( stack . size ( ) < 2 )
if ( stack . size ( ) < 2 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
valtype vch1 = stacktop ( - 2 ) ;
valtype vch1 = stacktop ( - 2 ) ;
valtype vch2 = stacktop ( - 1 ) ;
valtype vch2 = stacktop ( - 1 ) ;
stack . push_back ( vch1 ) ;
stack . push_back ( vch1 ) ;
@ -383,7 +436,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
// (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
if ( stack . size ( ) < 3 )
if ( stack . size ( ) < 3 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
valtype vch1 = stacktop ( - 3 ) ;
valtype vch1 = stacktop ( - 3 ) ;
valtype vch2 = stacktop ( - 2 ) ;
valtype vch2 = stacktop ( - 2 ) ;
valtype vch3 = stacktop ( - 1 ) ;
valtype vch3 = stacktop ( - 1 ) ;
@ -397,7 +450,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
// (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
if ( stack . size ( ) < 4 )
if ( stack . size ( ) < 4 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
valtype vch1 = stacktop ( - 4 ) ;
valtype vch1 = stacktop ( - 4 ) ;
valtype vch2 = stacktop ( - 3 ) ;
valtype vch2 = stacktop ( - 3 ) ;
stack . push_back ( vch1 ) ;
stack . push_back ( vch1 ) ;
@ -409,7 +462,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
// (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
if ( stack . size ( ) < 6 )
if ( stack . size ( ) < 6 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
valtype vch1 = stacktop ( - 6 ) ;
valtype vch1 = stacktop ( - 6 ) ;
valtype vch2 = stacktop ( - 5 ) ;
valtype vch2 = stacktop ( - 5 ) ;
stack . erase ( stack . end ( ) - 6 , stack . end ( ) - 4 ) ;
stack . erase ( stack . end ( ) - 6 , stack . end ( ) - 4 ) ;
@ -422,7 +475,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x1 x2 x3 x4 -- x3 x4 x1 x2)
// (x1 x2 x3 x4 -- x3 x4 x1 x2)
if ( stack . size ( ) < 4 )
if ( stack . size ( ) < 4 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
swap ( stacktop ( - 4 ) , stacktop ( - 2 ) ) ;
swap ( stacktop ( - 4 ) , stacktop ( - 2 ) ) ;
swap ( stacktop ( - 3 ) , stacktop ( - 1 ) ) ;
swap ( stacktop ( - 3 ) , stacktop ( - 1 ) ) ;
}
}
@ -432,7 +485,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x - 0 | x x)
// (x - 0 | x x)
if ( stack . size ( ) < 1 )
if ( stack . size ( ) < 1 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
valtype vch = stacktop ( - 1 ) ;
valtype vch = stacktop ( - 1 ) ;
if ( CastToBool ( vch ) )
if ( CastToBool ( vch ) )
stack . push_back ( vch ) ;
stack . push_back ( vch ) ;
@ -451,7 +504,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x -- )
// (x -- )
if ( stack . size ( ) < 1 )
if ( stack . size ( ) < 1 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
popstack ( stack ) ;
popstack ( stack ) ;
}
}
break ;
break ;
@ -460,7 +513,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x -- x x)
// (x -- x x)
if ( stack . size ( ) < 1 )
if ( stack . size ( ) < 1 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
valtype vch = stacktop ( - 1 ) ;
valtype vch = stacktop ( - 1 ) ;
stack . push_back ( vch ) ;
stack . push_back ( vch ) ;
}
}
@ -470,7 +523,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x1 x2 -- x2)
// (x1 x2 -- x2)
if ( stack . size ( ) < 2 )
if ( stack . size ( ) < 2 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
stack . erase ( stack . end ( ) - 2 ) ;
stack . erase ( stack . end ( ) - 2 ) ;
}
}
break ;
break ;
@ -479,7 +532,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x1 x2 -- x1 x2 x1)
// (x1 x2 -- x1 x2 x1)
if ( stack . size ( ) < 2 )
if ( stack . size ( ) < 2 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
valtype vch = stacktop ( - 2 ) ;
valtype vch = stacktop ( - 2 ) ;
stack . push_back ( vch ) ;
stack . push_back ( vch ) ;
}
}
@ -491,11 +544,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
// (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
// (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
// (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
if ( stack . size ( ) < 2 )
if ( stack . size ( ) < 2 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
int n = CScriptNum ( stacktop ( - 1 ) , fRequireMinimal ) . getint ( ) ;
int n = CScriptNum ( stacktop ( - 1 ) , fRequireMinimal ) . getint ( ) ;
popstack ( stack ) ;
popstack ( stack ) ;
if ( n < 0 | | n > = ( int ) stack . size ( ) )
if ( n < 0 | | n > = ( int ) stack . size ( ) )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
valtype vch = stacktop ( - n - 1 ) ;
valtype vch = stacktop ( - n - 1 ) ;
if ( opcode = = OP_ROLL )
if ( opcode = = OP_ROLL )
stack . erase ( stack . end ( ) - n - 1 ) ;
stack . erase ( stack . end ( ) - n - 1 ) ;
@ -509,7 +562,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// x2 x1 x3 after first swap
// x2 x1 x3 after first swap
// x2 x3 x1 after second swap
// x2 x3 x1 after second swap
if ( stack . size ( ) < 3 )
if ( stack . size ( ) < 3 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
swap ( stacktop ( - 3 ) , stacktop ( - 2 ) ) ;
swap ( stacktop ( - 3 ) , stacktop ( - 2 ) ) ;
swap ( stacktop ( - 2 ) , stacktop ( - 1 ) ) ;
swap ( stacktop ( - 2 ) , stacktop ( - 1 ) ) ;
}
}
@ -519,7 +572,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x1 x2 -- x2 x1)
// (x1 x2 -- x2 x1)
if ( stack . size ( ) < 2 )
if ( stack . size ( ) < 2 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
swap ( stacktop ( - 2 ) , stacktop ( - 1 ) ) ;
swap ( stacktop ( - 2 ) , stacktop ( - 1 ) ) ;
}
}
break ;
break ;
@ -528,7 +581,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x1 x2 -- x2 x1 x2)
// (x1 x2 -- x2 x1 x2)
if ( stack . size ( ) < 2 )
if ( stack . size ( ) < 2 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
valtype vch = stacktop ( - 1 ) ;
valtype vch = stacktop ( - 1 ) ;
stack . insert ( stack . end ( ) - 2 , vch ) ;
stack . insert ( stack . end ( ) - 2 , vch ) ;
}
}
@ -539,7 +592,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (in -- in size)
// (in -- in size)
if ( stack . size ( ) < 1 )
if ( stack . size ( ) < 1 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
CScriptNum bn ( stacktop ( - 1 ) . size ( ) ) ;
CScriptNum bn ( stacktop ( - 1 ) . size ( ) ) ;
stack . push_back ( bn . getvch ( ) ) ;
stack . push_back ( bn . getvch ( ) ) ;
}
}
@ -555,7 +608,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x1 x2 - bool)
// (x1 x2 - bool)
if ( stack . size ( ) < 2 )
if ( stack . size ( ) < 2 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
valtype & vch1 = stacktop ( - 2 ) ;
valtype & vch1 = stacktop ( - 2 ) ;
valtype & vch2 = stacktop ( - 1 ) ;
valtype & vch2 = stacktop ( - 1 ) ;
bool fEqual = ( vch1 = = vch2 ) ;
bool fEqual = ( vch1 = = vch2 ) ;
@ -572,7 +625,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if ( fEqual )
if ( fEqual )
popstack ( stack ) ;
popstack ( stack ) ;
else
else
return false ;
return set_error ( serror , SCRIPT_ERR_EQUALVERIFY ) ;
}
}
}
}
break ;
break ;
@ -590,7 +643,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (in -- out)
// (in -- out)
if ( stack . size ( ) < 1 )
if ( stack . size ( ) < 1 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
CScriptNum bn ( stacktop ( - 1 ) , fRequireMinimal ) ;
CScriptNum bn ( stacktop ( - 1 ) , fRequireMinimal ) ;
switch ( opcode )
switch ( opcode )
{
{
@ -623,7 +676,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x1 x2 -- out)
// (x1 x2 -- out)
if ( stack . size ( ) < 2 )
if ( stack . size ( ) < 2 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
CScriptNum bn1 ( stacktop ( - 2 ) , fRequireMinimal ) ;
CScriptNum bn1 ( stacktop ( - 2 ) , fRequireMinimal ) ;
CScriptNum bn2 ( stacktop ( - 1 ) , fRequireMinimal ) ;
CScriptNum bn2 ( stacktop ( - 1 ) , fRequireMinimal ) ;
CScriptNum bn ( 0 ) ;
CScriptNum bn ( 0 ) ;
@ -659,7 +712,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if ( CastToBool ( stacktop ( - 1 ) ) )
if ( CastToBool ( stacktop ( - 1 ) ) )
popstack ( stack ) ;
popstack ( stack ) ;
else
else
return false ;
return set_error ( serror , SCRIPT_ERR_NUMEQUALVERIFY ) ;
}
}
}
}
break ;
break ;
@ -668,7 +721,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (x min max -- out)
// (x min max -- out)
if ( stack . size ( ) < 3 )
if ( stack . size ( ) < 3 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
CScriptNum bn1 ( stacktop ( - 3 ) , fRequireMinimal ) ;
CScriptNum bn1 ( stacktop ( - 3 ) , fRequireMinimal ) ;
CScriptNum bn2 ( stacktop ( - 2 ) , fRequireMinimal ) ;
CScriptNum bn2 ( stacktop ( - 2 ) , fRequireMinimal ) ;
CScriptNum bn3 ( stacktop ( - 1 ) , fRequireMinimal ) ;
CScriptNum bn3 ( stacktop ( - 1 ) , fRequireMinimal ) ;
@ -692,7 +745,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (in -- hash)
// (in -- hash)
if ( stack . size ( ) < 1 )
if ( stack . size ( ) < 1 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
valtype & vch = stacktop ( - 1 ) ;
valtype & vch = stacktop ( - 1 ) ;
valtype vchHash ( ( opcode = = OP_RIPEMD160 | | opcode = = OP_SHA1 | | opcode = = OP_HASH160 ) ? 20 : 32 ) ;
valtype vchHash ( ( opcode = = OP_RIPEMD160 | | opcode = = OP_SHA1 | | opcode = = OP_HASH160 ) ? 20 : 32 ) ;
if ( opcode = = OP_RIPEMD160 )
if ( opcode = = OP_RIPEMD160 )
@ -722,7 +775,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{
{
// (sig pubkey -- bool)
// (sig pubkey -- bool)
if ( stack . size ( ) < 2 )
if ( stack . size ( ) < 2 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
valtype & vchSig = stacktop ( - 2 ) ;
valtype & vchSig = stacktop ( - 2 ) ;
valtype & vchPubKey = stacktop ( - 1 ) ;
valtype & vchPubKey = stacktop ( - 1 ) ;
@ -733,10 +786,10 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Drop the signature, since there's no way for a signature to sign itself
// Drop the signature, since there's no way for a signature to sign itself
scriptCode . FindAndDelete ( CScript ( vchSig ) ) ;
scriptCode . FindAndDelete ( CScript ( vchSig ) ) ;
if ( ! CheckSignatureEncoding ( vchSig , flags ) ) {
if ( ! CheckSignatureEncoding ( vchSig , flags , serror ) ) {
//serror is set
return false ;
return false ;
}
}
bool fSuccess = CheckPubKeyEncoding ( vchPubKey , flags ) & & checker . CheckSig ( vchSig , vchPubKey , scriptCode ) ;
bool fSuccess = CheckPubKeyEncoding ( vchPubKey , flags ) & & checker . CheckSig ( vchSig , vchPubKey , scriptCode ) ;
popstack ( stack ) ;
popstack ( stack ) ;
@ -747,7 +800,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if ( fSuccess )
if ( fSuccess )
popstack ( stack ) ;
popstack ( stack ) ;
else
else
return false ;
return set_error ( serror , SCRIPT_ERR_CHECKSIGVERIFY ) ;
}
}
}
}
break ;
break ;
@ -759,26 +812,26 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
int i = 1 ;
int i = 1 ;
if ( ( int ) stack . size ( ) < i )
if ( ( int ) stack . size ( ) < i )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
int nKeysCount = CScriptNum ( stacktop ( - i ) , fRequireMinimal ) . getint ( ) ;
int nKeysCount = CScriptNum ( stacktop ( - i ) , fRequireMinimal ) . getint ( ) ;
if ( nKeysCount < 0 | | nKeysCount > 20 )
if ( nKeysCount < 0 | | nKeysCount > 20 )
return false ;
return set_error ( serror , SCRIPT_ERR_PUBKEY_COUNT ) ;
nOpCount + = nKeysCount ;
nOpCount + = nKeysCount ;
if ( nOpCount > 201 )
if ( nOpCount > 201 )
return false ;
return set_error ( serror , SCRIPT_ERR_OP_COUNT ) ;
int ikey = + + i ;
int ikey = + + i ;
i + = nKeysCount ;
i + = nKeysCount ;
if ( ( int ) stack . size ( ) < i )
if ( ( int ) stack . size ( ) < i )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
int nSigsCount = CScriptNum ( stacktop ( - i ) , fRequireMinimal ) . getint ( ) ;
int nSigsCount = CScriptNum ( stacktop ( - i ) , fRequireMinimal ) . getint ( ) ;
if ( nSigsCount < 0 | | nSigsCount > nKeysCount )
if ( nSigsCount < 0 | | nSigsCount > nKeysCount )
return false ;
return set_error ( serror , SCRIPT_ERR_SIG_COUNT ) ;
int isig = + + i ;
int isig = + + i ;
i + = nSigsCount ;
i + = nSigsCount ;
if ( ( int ) stack . size ( ) < i )
if ( ( int ) stack . size ( ) < i )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
// Subset of script starting at the most recent codeseparator
// Subset of script starting at the most recent codeseparator
CScript scriptCode ( pbegincodehash , pend ) ;
CScript scriptCode ( pbegincodehash , pend ) ;
@ -796,7 +849,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
valtype & vchSig = stacktop ( - isig ) ;
valtype & vchSig = stacktop ( - isig ) ;
valtype & vchPubKey = stacktop ( - ikey ) ;
valtype & vchPubKey = stacktop ( - ikey ) ;
if ( ! CheckSignatureEncoding ( vchSig , flags ) ) {
if ( ! CheckSignatureEncoding ( vchSig , flags , serror ) ) {
// serror is set
return false ;
return false ;
}
}
@ -827,9 +881,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// so optionally verify it is exactly equal to zero prior
// so optionally verify it is exactly equal to zero prior
// to removing it from the stack.
// to removing it from the stack.
if ( stack . size ( ) < 1 )
if ( stack . size ( ) < 1 )
return false ;
return set_error ( serror , SCRIPT_ERR_INVALID_STACK_OPERATION ) ;
if ( ( flags & SCRIPT_VERIFY_NULLDUMMY ) & & stacktop ( - 1 ) . size ( ) )
if ( ( flags & SCRIPT_VERIFY_NULLDUMMY ) & & stacktop ( - 1 ) . size ( ) )
return error ( " CHECKMULTISIG dummy argument not null " ) ;
return set_error ( serror , SCRIPT_ERR_SIG_NULLDUMMY ) ;
popstack ( stack ) ;
popstack ( stack ) ;
stack . push_back ( fSuccess ? vchTrue : vchFalse ) ;
stack . push_back ( fSuccess ? vchTrue : vchFalse ) ;
@ -839,29 +893,29 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if ( fSuccess )
if ( fSuccess )
popstack ( stack ) ;
popstack ( stack ) ;
else
else
return false ;
return set_error ( serror , SCRIPT_ERR_CHECKMULTISIGVERIFY ) ;
}
}
}
}
break ;
break ;
default :
default :
return false ;
return set_error ( serror , SCRIPT_ERR_BAD_OPCODE ) ;
}
}
// Size limits
// Size limits
if ( stack . size ( ) + altstack . size ( ) > 1000 )
if ( stack . size ( ) + altstack . size ( ) > 1000 )
return false ;
return set_error ( serror , SCRIPT_ERR_STACK_SIZE ) ;
}
}
}
}
catch ( . . . )
catch ( . . . )
{
{
return false ;
return set_error ( serror , SCRIPT_ERR_UNKNOWN_ERROR ) ;
}
}
if ( ! vfExec . empty ( ) )
if ( ! vfExec . empty ( ) )
return false ;
return set_error ( serror , SCRIPT_ERR_UNBALANCED_CONDITIONAL ) ;
return true ;
return set_success ( serror ) ;
}
}
namespace {
namespace {
@ -966,14 +1020,14 @@ public:
uint256 SignatureHash ( const CScript & scriptCode , const CTransaction & txTo , unsigned int nIn , int nHashType )
uint256 SignatureHash ( const CScript & scriptCode , const CTransaction & txTo , unsigned int nIn , int nHashType )
{
{
if ( nIn > = txTo . vin . size ( ) ) {
if ( nIn > = txTo . vin . size ( ) ) {
LogPrintf ( " ERROR: SignatureHash() : nIn=%d out of range \n " , nIn ) ;
// nIn out of range
return 1 ;
return 1 ;
}
}
// Check for invalid use of SIGHASH_SINGLE
// Check for invalid use of SIGHASH_SINGLE
if ( ( nHashType & 0x1f ) = = SIGHASH_SINGLE ) {
if ( ( nHashType & 0x1f ) = = SIGHASH_SINGLE ) {
if ( nIn > = txTo . vout . size ( ) ) {
if ( nIn > = txTo . vout . size ( ) ) {
LogPrintf ( " ERROR: SignatureHash() : nOut=%d out of range \n " , nIn ) ;
// nOut out of range
return 1 ;
return 1 ;
}
}
}
}
@ -1013,30 +1067,35 @@ bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vec
return true ;
return true ;
}
}
bool VerifyScript ( const CScript & scriptSig , const CScript & scriptPubKey , unsigned int flags , const BaseSignatureChecker & checker )
bool VerifyScript ( const CScript & scriptSig , const CScript & scriptPubKey , unsigned int flags , const BaseSignatureChecker & checker , ScriptError * serror )
{
{
set_error ( serror , SCRIPT_ERR_UNKNOWN_ERROR ) ;
if ( ( flags & SCRIPT_VERIFY_SIGPUSHONLY ) ! = 0 & & ! scriptSig . IsPushOnly ( ) ) {
if ( ( flags & SCRIPT_VERIFY_SIGPUSHONLY ) ! = 0 & & ! scriptSig . IsPushOnly ( ) ) {
return false ;
return set_error ( serror , SCRIPT_ERR_SIG_PUSHONLY ) ;
}
}
vector < vector < unsigned char > > stack , stackCopy ;
vector < vector < unsigned char > > stack , stackCopy ;
if ( ! EvalScript ( stack , scriptSig , flags , checker ) )
if ( ! EvalScript ( stack , scriptSig , flags , checker , serror ) )
// serror is set
return false ;
return false ;
if ( flags & SCRIPT_VERIFY_P2SH )
if ( flags & SCRIPT_VERIFY_P2SH )
stackCopy = stack ;
stackCopy = stack ;
if ( ! EvalScript ( stack , scriptPubKey , flags , checker ) )
if ( ! EvalScript ( stack , scriptPubKey , flags , checker , serror ) )
// serror is set
return false ;
return false ;
if ( stack . empty ( ) )
if ( stack . empty ( ) )
return false ;
return set_error ( serror , SCRIPT_ERR_EVAL_FALSE ) ;
if ( CastToBool ( stack . back ( ) ) = = false )
if ( CastToBool ( stack . back ( ) ) = = false )
return false ;
return set_error ( serror , SCRIPT_ERR_EVAL_FALSE ) ;
// Additional validation for spend-to-script-hash transactions:
// Additional validation for spend-to-script-hash transactions:
if ( ( flags & SCRIPT_VERIFY_P2SH ) & & scriptPubKey . IsPayToScriptHash ( ) )
if ( ( flags & SCRIPT_VERIFY_P2SH ) & & scriptPubKey . IsPayToScriptHash ( ) )
{
{
if ( ! scriptSig . IsPushOnly ( ) ) // scriptSig must be literals-only
// scriptSig must be literals-only or validation fails
return false ; // or validation fails
if ( ! scriptSig . IsPushOnly ( ) )
return set_error ( serror , SCRIPT_ERR_SIG_PUSHONLY ) ;
// stackCopy cannot be empty here, because if it was the
// stackCopy cannot be empty here, because if it was the
// P2SH HASH <> EQUAL scriptPubKey would be evaluated with
// P2SH HASH <> EQUAL scriptPubKey would be evaluated with
@ -1047,12 +1106,16 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
CScript pubKey2 ( pubKeySerialized . begin ( ) , pubKeySerialized . end ( ) ) ;
CScript pubKey2 ( pubKeySerialized . begin ( ) , pubKeySerialized . end ( ) ) ;
popstack ( stackCopy ) ;
popstack ( stackCopy ) ;
if ( ! EvalScript ( stackCopy , pubKey2 , flags , checker ) )
if ( ! EvalScript ( stackCopy , pubKey2 , flags , checker , serror ) )
// serror is set
return false ;
return false ;
if ( stackCopy . empty ( ) )
if ( stackCopy . empty ( ) )
return false ;
return set_error ( serror , SCRIPT_ERR_EVAL_FALSE ) ;
return CastToBool ( stackCopy . back ( ) ) ;
if ( ! CastToBool ( stackCopy . back ( ) ) )
return set_error ( serror , SCRIPT_ERR_EVAL_FALSE ) ;
else
return set_success ( serror ) ;
}
}
return true ;
return set_success ( serror ) ;
}
}