@ -70,7 +70,7 @@ static inline void popstack(vector<valtype>& stack)
}
}
const char * GetTxnTypeNam e ( txntype t )
const char * GetTxnOutput Type ( txnout type t )
{
{
switch ( t )
switch ( t )
{
{
@ -230,12 +230,12 @@ const char* GetOpName(opcodetype opcode)
}
}
}
}
//
//
// Returns true if script is valid.
// Returns true if script is valid.
//
//
bool EvalScriptInner ( vector < vector < unsigned char > > & stack , const CScript & script , const CTransaction & txTo , unsigned int nIn , int nHashType ,
bool EvalScriptInner ( vector < vector < unsigned char > > & stack , const CScript & script , const CTransaction & txTo , unsigned int nIn , int nHashType ,
CScript : : const_iterator pbegincodehash , CScript : : const_iterator pendcodehash , int & nOpCount , int & nSigOpCount , int nRecurseDepth )
CScript : : const_iterator pbegincodehash , CScript : : const_iterator pendcodehash , int & nOpCount , int & nSigOpCount ,
bool fStrictOpEval , int nRecurseDepth )
{
{
CAutoBN_CTX pctx ;
CAutoBN_CTX pctx ;
CScript : : const_iterator pc = script . begin ( ) ;
CScript : : const_iterator pc = script . begin ( ) ;
@ -1014,17 +1014,9 @@ bool EvalScriptInner(vector<vector<unsigned char> >& stack, const CScript& scrip
case OP_EVAL :
case OP_EVAL :
{
{
// This code should be removed when OP_EVAL has
if ( ! fStrictOpEval )
// a majority of hashing power on the network.
break ; // Act as a NO_OP
// OP_EVAL behaves just like OP_NOP until
// opevaltime :
if ( ! fTestNet | | fDebug )
{
// 1328054400 is Feb 1, 2012
int64 nEvalSwitchTime = GetArg ( " opevaltime " , 1328054400 ) ;
if ( GetTime ( ) < nEvalSwitchTime )
break ;
}
// Evaluate the top item on the stack as a Script
// Evaluate the top item on the stack as a Script
// [serialized script ] -- [result(s) of executing script]
// [serialized script ] -- [result(s) of executing script]
@ -1034,12 +1026,14 @@ bool EvalScriptInner(vector<vector<unsigned char> >& stack, const CScript& scrip
CScript subscript ( vchScript . begin ( ) , vchScript . end ( ) ) ;
CScript subscript ( vchScript . begin ( ) , vchScript . end ( ) ) ;
popstack ( stack ) ;
popstack ( stack ) ;
// Codeseparators not allowed
// Codeseparators not allowed; they don't make sense 'inside' an OP_EVAL, because
// their purpose is to change which parts of the scriptPubKey script is copied
// and signed by OP_CHECKSIG, but OP_EVAl'ed code is in the scriptSig, not the scriptPubKey.
if ( subscript . Find ( OP_CODESEPARATOR ) )
if ( subscript . Find ( OP_CODESEPARATOR ) )
return false ;
return false ;
if ( ! EvalScriptInner ( stack , subscript , txTo , nIn , nHashType ,
if ( ! EvalScriptInner ( stack , subscript , txTo , nIn , nHashType ,
pbegincodehash , pendcodehash , nOpCount , nSigOpCount , nRecurseDepth + + ) )
pbegincodehash , pendcodehash , nOpCount , nSigOpCount , fStrictOpEval , nRecurseDepth + + ) )
return false ;
return false ;
}
}
break ;
break ;
@ -1066,14 +1060,15 @@ bool EvalScriptInner(vector<vector<unsigned char> >& stack, const CScript& scrip
}
}
bool EvalScript ( vector < vector < unsigned char > > & stack , const CScript & script ,
bool EvalScript ( vector < vector < unsigned char > > & stack , const CScript & script ,
const CTransaction & txTo , unsigned int nIn , int nHashType , int & nSigOpCountRet )
const CTransaction & txTo , unsigned int nIn , int nHashType ,
bool fStrictOpEval , int & nSigOpCountRet )
{
{
CScript : : const_iterator pbegincodehash = script . begin ( ) ;
CScript : : const_iterator pbegincodehash = script . begin ( ) ;
CScript : : const_iterator pendcodehash = script . end ( ) ;
CScript : : const_iterator pendcodehash = script . end ( ) ;
int nOpCount = 0 ;
int nOpCount = 0 ;
return EvalScriptInner ( stack , script , txTo , nIn , nHashType , pbegincodehash , pendcodehash ,
return EvalScriptInner ( stack , script , txTo , nIn , nHashType , pbegincodehash , pendcodehash ,
nOpCount , nSigOpCountRet , 0 ) ;
nOpCount , nSigOpCountRet , fStrictOpEval , 0 ) ;
}
}
@ -1177,10 +1172,10 @@ bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CSc
//
//
// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
//
//
bool Solver ( const CScript & scriptPubKey , txntype & typeRet , vector < vector < unsigned char > > & vSolutionsRet )
bool Solver ( const CScript & scriptPubKey , txnout type & typeRet , vector < vector < unsigned char > > & vSolutionsRet )
{
{
// Templates
// Templates
static map < txntype , CScript > mTemplates ;
static map < txnout type , CScript > mTemplates ;
if ( mTemplates . empty ( ) )
if ( mTemplates . empty ( ) )
{
{
// Standard tx, sender provides pubkey, receiver adds signature
// Standard tx, sender provides pubkey, receiver adds signature
@ -1199,7 +1194,7 @@ bool Solver(const CScript& scriptPubKey, txntype& typeRet, vector<vector<unsigne
// Scan templates
// Scan templates
const CScript & script1 = scriptPubKey ;
const CScript & script1 = scriptPubKey ;
BOOST_FOREACH ( const PAIRTYPE ( txntype , CScript ) & tplate , mTemplates )
BOOST_FOREACH ( const PAIRTYPE ( txnout type , CScript ) & tplate , mTemplates )
{
{
const CScript & script2 = tplate . second ;
const CScript & script2 = tplate . second ;
vSolutionsRet . clear ( ) ;
vSolutionsRet . clear ( ) ;
@ -1331,13 +1326,13 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
{
{
scriptSigRet . clear ( ) ;
scriptSigRet . clear ( ) ;
txntype whichType ;
txnout type whichType ;
vector < valtype > vSolutions ;
vector < valtype > vSolutions ;
if ( ! Solver ( scriptPubKey , whichType , vSolutions ) )
if ( ! Solver ( scriptPubKey , whichType , vSolutions ) )
return false ;
return false ;
CBitcoinAddress address ;
CBitcoinAddress address ;
valtype subscript ;
CScript subscript ;
switch ( whichType )
switch ( whichType )
{
{
case TX_NONSTANDARD :
case TX_NONSTANDARD :
@ -1359,10 +1354,11 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
case TX_SCRIPTHASH :
case TX_SCRIPTHASH :
if ( ! keystore . GetCScript ( uint160 ( vSolutions [ 0 ] ) , subscript ) )
if ( ! keystore . GetCScript ( uint160 ( vSolutions [ 0 ] ) , subscript ) )
return false ;
return false ;
if ( ! Solver ( keystore , CScript ( subscript . begin ( ) , subscript . end ( ) ) , hash , nHashType , scriptSigRet ) )
if ( ! Solver ( keystore , subscript , hash , nHashType , scriptSigRet ) )
return false ;
return false ;
if ( hash ! = 0 )
if ( hash ! = 0 )
scriptSigRet < < subscript ; // signatures AND serialized script
// static_cast to get vector.operator<< instead of CScript.operator<<
scriptSigRet < < static_cast < valtype > ( subscript ) ; // signatures AND serialized script
break ;
break ;
case TX_MULTISIG :
case TX_MULTISIG :
scriptSigRet < < OP_0 ; // workaround CHECKMULTISIG bug
scriptSigRet < < OP_0 ; // workaround CHECKMULTISIG bug
@ -1375,7 +1371,7 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
bool IsStandard ( const CScript & scriptPubKey )
bool IsStandard ( const CScript & scriptPubKey )
{
{
vector < valtype > vSolutions ;
vector < valtype > vSolutions ;
txntype whichType ;
txnout type whichType ;
if ( ! Solver ( scriptPubKey , whichType , vSolutions ) )
if ( ! Solver ( scriptPubKey , whichType , vSolutions ) )
return false ;
return false ;
@ -1410,7 +1406,7 @@ int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
bool IsMine ( const CKeyStore & keystore , const CScript & scriptPubKey )
bool IsMine ( const CKeyStore & keystore , const CScript & scriptPubKey )
{
{
vector < valtype > vSolutions ;
vector < valtype > vSolutions ;
txntype whichType ;
txnout type whichType ;
if ( ! Solver ( scriptPubKey , whichType , vSolutions ) )
if ( ! Solver ( scriptPubKey , whichType , vSolutions ) )
return false ;
return false ;
@ -1427,10 +1423,10 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
return keystore . HaveKey ( address ) ;
return keystore . HaveKey ( address ) ;
case TX_SCRIPTHASH :
case TX_SCRIPTHASH :
{
{
valtype subscript ;
CScript subscript ;
if ( ! keystore . GetCScript ( uint160 ( vSolutions [ 0 ] ) , subscript ) )
if ( ! keystore . GetCScript ( uint160 ( vSolutions [ 0 ] ) , subscript ) )
return false ;
return false ;
return IsMine ( keystore , CScript ( subscript . begin ( ) , subscript . end ( ) ) ) ;
return IsMine ( keystore , subscript ) ;
}
}
case TX_MULTISIG :
case TX_MULTISIG :
{
{
@ -1449,7 +1445,7 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
bool ExtractAddress ( const CScript & scriptPubKey , const CKeyStore * keystore , CBitcoinAddress & addressRet )
bool ExtractAddress ( const CScript & scriptPubKey , const CKeyStore * keystore , CBitcoinAddress & addressRet )
{
{
vector < valtype > vSolutions ;
vector < valtype > vSolutions ;
txntype whichType ;
txnout type whichType ;
if ( ! Solver ( scriptPubKey , whichType , vSolutions ) )
if ( ! Solver ( scriptPubKey , whichType , vSolutions ) )
return false ;
return false ;
@ -1472,7 +1468,7 @@ bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBit
return false ;
return false ;
}
}
bool ExtractAddresses ( const CScript & scriptPubKey , const CKeyStore * keystore , txntype & typeRet , vector < CBitcoinAddress > & addressRet , int & nRequiredRet )
bool ExtractAddresses ( const CScript & scriptPubKey , const CKeyStore * keystore , txnout type & typeRet , vector < CBitcoinAddress > & addressRet , int & nRequiredRet )
{
{
addressRet . clear ( ) ;
addressRet . clear ( ) ;
typeRet = TX_NONSTANDARD ;
typeRet = TX_NONSTANDARD ;
@ -1484,10 +1480,10 @@ bool ExtractAddresses(const CScript& scriptPubKey, const CKeyStore* keystore, tx
{
{
nRequiredRet = vSolutions . front ( ) [ 0 ] ;
nRequiredRet = vSolutions . front ( ) [ 0 ] ;
int n = vSolutions . back ( ) [ 0 ] ;
int n = vSolutions . back ( ) [ 0 ] ;
for ( vector < valtype > : : const_iterator it = vSolutions . begin ( ) + 1 ; it ! = vSolutions . begin ( ) + vSolutions . size ( ) - 1 ; it + + )
for ( int i = 1 ; i < vSolutions . size ( ) - 1 ; i + + )
{
{
CBitcoinAddress address ;
CBitcoinAddress address ;
address . SetPubKey ( * it ) ;
address . SetPubKey ( vSolutions [ i ] ) ;
addressRet . push_back ( address ) ;
addressRet . push_back ( address ) ;
}
}
}
}
@ -1507,12 +1503,13 @@ bool ExtractAddresses(const CScript& scriptPubKey, const CKeyStore* keystore, tx
return true ;
return true ;
}
}
bool VerifyScript ( const CScript & scriptSig , const CScript & scriptPubKey , const CTransaction & txTo , unsigned int nIn , int & nSigOpCountRet , int nHashType )
bool VerifyScript ( const CScript & scriptSig , const CScript & scriptPubKey , const CTransaction & txTo , unsigned int nIn , int & nSigOpCountRet ,
int nHashType , bool fStrictOpEval )
{
{
vector < vector < unsigned char > > stack ;
vector < vector < unsigned char > > stack ;
if ( ! EvalScript ( stack , scriptSig , txTo , nIn , nHashType , nSigOpCountRet ) )
if ( ! EvalScript ( stack , scriptSig , txTo , nIn , nHashType , fStrictOpEval , nSigOpCountRet ) )
return false ;
return false ;
if ( ! EvalScript ( stack , scriptPubKey , txTo , nIn , nHashType , nSigOpCountRet ) )
if ( ! EvalScript ( stack , scriptPubKey , txTo , nIn , nHashType , fStrictOpEval , nSigOpCountRet ) )
return false ;
return false ;
if ( stack . empty ( ) )
if ( stack . empty ( ) )
return false ;
return false ;
@ -1521,24 +1518,8 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
// This code should be removed when a compatibility-breaking block chain split has passed.
// This code should be removed when a compatibility-breaking block chain split has passed.
// Special check for OP_EVAL backwards-compatibility: if scriptPubKey or scriptSig contains
// Special check for OP_EVAL backwards-compatibility: if scriptPubKey or scriptSig contains
// OP_EVAL, then result must be identical if OP_EVAL is treated as a no-op:
// OP_EVAL, then result must be identical if OP_EVAL is treated as a no-op:
if ( scriptSig . Find ( OP_EVAL ) + scriptPubKey . Find ( OP_EVAL ) > 0 )
if ( fResult & & fStrictOpEval & & ( scriptPubKey . Find ( OP_EVAL ) | | scriptSig . Find ( OP_EVAL ) ) )
{
return VerifyScript ( scriptSig , scriptPubKey , txTo , nIn , nSigOpCountRet , nHashType , false ) ;
int nUnused = 0 ;
stack . clear ( ) ;
CScript sigCopy = scriptSig ;
sigCopy . FindAndDelete ( CScript ( OP_EVAL ) ) ;
CScript pubKeyCopy = scriptPubKey ;
pubKeyCopy . FindAndDelete ( CScript ( OP_EVAL ) ) ;
if ( ! EvalScript ( stack , sigCopy , txTo , nIn , nHashType , nUnused ) )
return false ;
if ( ! EvalScript ( stack , pubKeyCopy , txTo , nIn , nHashType , nUnused ) )
return false ;
if ( stack . empty ( ) )
return false ;
if ( fResult ! = CastToBool ( stack . back ( ) ) )
return false ;
}
return fResult ;
return fResult ;
}
}
@ -1563,14 +1544,14 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTrans
// Test solution
// Test solution
int nUnused = 0 ;
int nUnused = 0 ;
if ( scriptPrereq . empty ( ) )
if ( scriptPrereq . empty ( ) )
if ( ! VerifyScript ( txin . scriptSig , txout . scriptPubKey , txTo , nIn , nUnused , 0 ) )
if ( ! VerifyScript ( txin . scriptSig , txout . scriptPubKey , txTo , nIn , nUnused , 0 , true ) )
return false ;
return false ;
return true ;
return true ;
}
}
bool VerifySignature ( const CTransaction & txFrom , const CTransaction & txTo , unsigned int nIn , int & nSigOpCountRet , int nHashType )
bool VerifySignature ( const CTransaction & txFrom , const CTransaction & txTo , unsigned int nIn , int & nSigOpCountRet , int nHashType , bool fStrictOpEval )
{
{
assert ( nIn < txTo . vin . size ( ) ) ;
assert ( nIn < txTo . vin . size ( ) ) ;
const CTxIn & txin = txTo . vin [ nIn ] ;
const CTxIn & txin = txTo . vin [ nIn ] ;
@ -1581,7 +1562,7 @@ bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsig
if ( txin . prevout . hash ! = txFrom . GetHash ( ) )
if ( txin . prevout . hash ! = txFrom . GetHash ( ) )
return false ;
return false ;
if ( ! VerifyScript ( txin . scriptSig , txout . scriptPubKey , txTo , nIn , nSigOpCountRet , nHashType ) )
if ( ! VerifyScript ( txin . scriptSig , txout . scriptPubKey , txTo , nIn , nSigOpCountRet , nHashType , fStrictOpEval ) )
return false ;
return false ;
return true ;
return true ;