2014-03-18 10:11:00 +01:00
// Copyright (c) 2011-2013 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.
2013-04-13 07:13:08 +02:00
# include "data/script_invalid.json.h"
# include "data/script_valid.json.h"
2014-09-20 03:13:04 +02:00
# include "core_io.h"
2013-04-13 07:13:08 +02:00
# include "key.h"
# include "keystore.h"
# include "main.h"
2014-08-20 17:37:40 +02:00
# include "script/script.h"
2014-08-27 17:22:33 +02:00
# include "script/sign.h"
2014-09-20 03:13:04 +02:00
# include "util.h"
2013-04-13 07:13:08 +02:00
2012-04-17 23:57:06 +02:00
# include <fstream>
2013-04-13 07:13:08 +02:00
# include <stdint.h>
# include <string>
2011-07-31 20:01:31 +02:00
# include <vector>
2013-04-13 07:13:08 +02:00
2012-04-17 23:57:06 +02:00
# include <boost/algorithm/string/classification.hpp>
# include <boost/algorithm/string/predicate.hpp>
# include <boost/algorithm/string/replace.hpp>
# include <boost/algorithm/string/split.hpp>
2013-04-13 07:13:08 +02:00
# include <boost/filesystem/operations.hpp>
# include <boost/filesystem/path.hpp>
2011-07-31 20:01:31 +02:00
# include <boost/foreach.hpp>
2012-04-26 17:20:44 +02:00
# include <boost/test/unit_test.hpp>
2012-04-17 23:57:06 +02:00
# include "json/json_spirit_reader_template.h"
# include "json/json_spirit_utils.h"
2013-04-13 07:13:08 +02:00
# include "json/json_spirit_writer_template.h"
2011-07-31 20:01:31 +02:00
using namespace std ;
2012-04-17 23:57:06 +02:00
using namespace json_spirit ;
using namespace boost : : algorithm ;
2012-11-13 23:03:25 +01:00
static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC ;
2011-07-31 20:01:31 +02:00
2014-09-08 21:15:31 +02:00
unsigned int ParseScriptFlags ( string strFlags ) ;
2014-09-20 03:13:04 +02:00
string FormatScriptFlags ( unsigned int flags ) ;
2014-09-08 21:15:31 +02:00
2012-04-17 23:57:06 +02:00
Array
2013-09-10 21:18:09 +02:00
read_json ( const std : : string & jsondata )
2012-04-17 23:57:06 +02:00
{
Value v ;
2013-09-10 21:18:09 +02:00
if ( ! read_string ( jsondata , v ) | | v . type ( ) ! = array_type )
2012-04-17 23:57:06 +02:00
{
2013-09-10 21:18:09 +02:00
BOOST_ERROR ( " Parse error. " ) ;
2012-04-17 23:57:06 +02:00
return Array ( ) ;
}
return v . get_array ( ) ;
}
2011-07-31 20:01:31 +02:00
BOOST_AUTO_TEST_SUITE ( script_tests )
2014-09-20 00:20:53 +02:00
CMutableTransaction BuildCreditingTransaction ( const CScript & scriptPubKey )
{
CMutableTransaction txCredit ;
txCredit . nVersion = 1 ;
txCredit . nLockTime = 0 ;
txCredit . vin . resize ( 1 ) ;
txCredit . vout . resize ( 1 ) ;
txCredit . vin [ 0 ] . prevout . SetNull ( ) ;
txCredit . vin [ 0 ] . scriptSig = CScript ( ) < < CScriptNum ( 0 ) < < CScriptNum ( 0 ) ;
txCredit . vin [ 0 ] . nSequence = std : : numeric_limits < unsigned int > : : max ( ) ;
txCredit . vout [ 0 ] . scriptPubKey = scriptPubKey ;
txCredit . vout [ 0 ] . nValue = 0 ;
return txCredit ;
}
2014-09-20 03:13:04 +02:00
CMutableTransaction BuildSpendingTransaction ( const CScript & scriptSig , const CTransaction & txCredit )
2014-09-20 00:20:53 +02:00
{
CMutableTransaction txSpend ;
txSpend . nVersion = 1 ;
txSpend . nLockTime = 0 ;
txSpend . vin . resize ( 1 ) ;
txSpend . vout . resize ( 1 ) ;
txSpend . vin [ 0 ] . prevout . hash = txCredit . GetHash ( ) ;
txSpend . vin [ 0 ] . prevout . n = 0 ;
txSpend . vin [ 0 ] . scriptSig = scriptSig ;
txSpend . vin [ 0 ] . nSequence = std : : numeric_limits < unsigned int > : : max ( ) ;
txSpend . vout [ 0 ] . scriptPubKey = CScript ( ) ;
txSpend . vout [ 0 ] . nValue = 0 ;
return txSpend ;
}
2014-09-20 03:13:04 +02:00
void DoTest ( const CScript & scriptPubKey , const CScript & scriptSig , int flags , bool expect , const std : : string & message )
{
BOOST_CHECK_MESSAGE ( VerifyScript ( scriptSig , scriptPubKey , BuildSpendingTransaction ( scriptSig , BuildCreditingTransaction ( scriptPubKey ) ) , 0 , flags ) = = expect , message ) ;
}
namespace
{
const unsigned char vchKey0 [ 32 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 } ;
const unsigned char vchKey1 [ 32 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ;
const unsigned char vchKey2 [ 32 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 } ;
struct KeyData
{
CKey key0 , key0C , key1 , key1C , key2 , key2C ;
CPubKey pubkey0 , pubkey0C , pubkey0H ;
CPubKey pubkey1 , pubkey1C ;
CPubKey pubkey2 , pubkey2C ;
KeyData ( )
{
key0 . Set ( & vchKey0 [ 0 ] , & vchKey0 [ 32 ] , false ) ;
key0C . Set ( & vchKey0 [ 0 ] , & vchKey0 [ 32 ] , true ) ;
pubkey0 = key0 . GetPubKey ( ) ;
pubkey0H = key0 . GetPubKey ( ) ;
pubkey0C = key0C . GetPubKey ( ) ;
* const_cast < unsigned char * > ( & pubkey0H [ 0 ] ) = 0x06 | ( pubkey0H [ 64 ] & 1 ) ;
key1 . Set ( & vchKey1 [ 0 ] , & vchKey1 [ 32 ] , false ) ;
key1C . Set ( & vchKey1 [ 0 ] , & vchKey1 [ 32 ] , true ) ;
pubkey1 = key1 . GetPubKey ( ) ;
pubkey1C = key1C . GetPubKey ( ) ;
key2 . Set ( & vchKey2 [ 0 ] , & vchKey2 [ 32 ] , false ) ;
key2C . Set ( & vchKey2 [ 0 ] , & vchKey2 [ 32 ] , true ) ;
pubkey2 = key2 . GetPubKey ( ) ;
pubkey2C = key2C . GetPubKey ( ) ;
}
} ;
const KeyData keys ;
class TestBuilder
{
private :
CScript scriptPubKey ;
CTransaction creditTx ;
CMutableTransaction spendTx ;
bool havePush ;
std : : vector < unsigned char > push ;
std : : string comment ;
int flags ;
void DoPush ( )
{
if ( havePush ) {
spendTx . vin [ 0 ] . scriptSig < < push ;
havePush = false ;
}
}
void DoPush ( const std : : vector < unsigned char > & data )
{
DoPush ( ) ;
push = data ;
havePush = true ;
}
public :
TestBuilder ( const CScript & redeemScript , const std : : string & comment_ , int flags_ , bool P2SH = false ) : scriptPubKey ( redeemScript ) , havePush ( false ) , comment ( comment_ ) , flags ( flags_ )
{
if ( P2SH ) {
creditTx = BuildCreditingTransaction ( CScript ( ) < < OP_HASH160 < < redeemScript . GetID ( ) < < OP_EQUAL ) ;
} else {
creditTx = BuildCreditingTransaction ( redeemScript ) ;
}
spendTx = BuildSpendingTransaction ( CScript ( ) , creditTx ) ;
}
TestBuilder & Add ( const CScript & script )
{
spendTx . vin [ 0 ] . scriptSig + = script ;
return * this ;
}
TestBuilder & Num ( int num )
{
spendTx . vin [ 0 ] . scriptSig < < CScriptNum ( num ) ;
return * this ;
}
TestBuilder & Push ( const std : : string & hex )
{
DoPush ( ParseHex ( hex ) ) ;
return * this ;
}
TestBuilder & PushSig ( const CKey & key , int nHashType = SIGHASH_ALL , unsigned int lenR = 32 , unsigned int lenS = 32 )
{
uint256 hash = SignatureHash ( scriptPubKey , spendTx , 0 , nHashType ) ;
std : : vector < unsigned char > vchSig , r , s ;
do {
key . Sign ( hash , vchSig , lenS < = 32 ) ;
r = std : : vector < unsigned char > ( & vchSig [ 4 ] , & vchSig [ 4 + vchSig [ 3 ] ] ) ;
s = std : : vector < unsigned char > ( & vchSig [ 6 + vchSig [ 3 ] ] , & vchSig [ 6 + vchSig [ 3 ] + vchSig [ 5 + vchSig [ 3 ] ] ] ) ;
} while ( lenR ! = r . size ( ) | | lenS ! = s . size ( ) ) ;
vchSig . push_back ( static_cast < unsigned char > ( nHashType ) ) ;
DoPush ( vchSig ) ;
return * this ;
}
TestBuilder & Push ( const CPubKey & pubkey )
{
DoPush ( std : : vector < unsigned char > ( pubkey . begin ( ) , pubkey . end ( ) ) ) ;
return * this ;
}
TestBuilder & PushRedeem ( )
{
DoPush ( static_cast < std : : vector < unsigned char > > ( scriptPubKey ) ) ;
return * this ;
}
TestBuilder & EditPush ( unsigned int pos , const std : : string & hexin , const std : : string & hexout )
{
assert ( havePush ) ;
std : : vector < unsigned char > datain = ParseHex ( hexin ) ;
std : : vector < unsigned char > dataout = ParseHex ( hexout ) ;
assert ( pos + datain . size ( ) < = push . size ( ) ) ;
BOOST_CHECK_MESSAGE ( std : : vector < unsigned char > ( push . begin ( ) + pos , push . begin ( ) + pos + datain . size ( ) ) = = datain , comment ) ;
push . erase ( push . begin ( ) + pos , push . begin ( ) + pos + datain . size ( ) ) ;
push . insert ( push . begin ( ) + pos , dataout . begin ( ) , dataout . end ( ) ) ;
return * this ;
}
TestBuilder & DamagePush ( unsigned int pos )
{
assert ( havePush ) ;
assert ( pos < push . size ( ) ) ;
push [ pos ] ^ = 1 ;
return * this ;
}
TestBuilder & Test ( bool expect )
{
TestBuilder copy = * this ; // Make a copy so we can rollback the push.
DoPush ( ) ;
DoTest ( creditTx . vout [ 0 ] . scriptPubKey , spendTx . vin [ 0 ] . scriptSig , flags , expect , comment ) ;
* this = copy ;
return * this ;
}
operator std : : string ( )
{
DoPush ( ) ;
return " [ \" " +
FormatScript ( spendTx . vin [ 0 ] . scriptSig ) + " \" , \" " +
FormatScript ( creditTx . vout [ 0 ] . scriptPubKey ) + " \" , \" " +
FormatScriptFlags ( flags ) + " \" , \" " +
comment + " \" ], \n " ;
}
std : : string GetComment ( )
{
return comment ;
}
const CScript & GetScriptPubKey ( )
{
return creditTx . vout [ 0 ] . scriptPubKey ;
}
} ;
}
BOOST_AUTO_TEST_CASE ( script_build )
{
std : : vector < TestBuilder > good ;
std : : vector < TestBuilder > bad ;
good . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey0 < < OP_CHECKSIG ,
" P2PK " , 0
) . PushSig ( keys . key0 ) ) ;
bad . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey0 < < OP_CHECKSIG ,
" P2PK, bad sig " , 0
) . PushSig ( keys . key0 ) . DamagePush ( 10 ) ) ;
good . push_back ( TestBuilder ( CScript ( ) < < OP_DUP < < OP_HASH160 < < keys . pubkey1C . GetID ( ) < < OP_EQUALVERIFY < < OP_CHECKSIG ,
" P2PKH " , 0
) . PushSig ( keys . key1 ) . Push ( keys . pubkey1C ) ) ;
bad . push_back ( TestBuilder ( CScript ( ) < < OP_DUP < < OP_HASH160 < < keys . pubkey2C . GetID ( ) < < OP_EQUALVERIFY < < OP_CHECKSIG ,
" P2PKH, bad pubkey " , 0
) . PushSig ( keys . key2 ) . Push ( keys . pubkey2C ) . DamagePush ( 5 ) ) ;
good . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey1 < < OP_CHECKSIG ,
" P2PK anyonecanpay " , 0
) . PushSig ( keys . key1 , SIGHASH_ALL | SIGHASH_ANYONECANPAY ) ) ;
bad . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey1 < < OP_CHECKSIG ,
" P2PK anyonecanpay marked with normal hashtype " , 0
) . PushSig ( keys . key1 , SIGHASH_ALL | SIGHASH_ANYONECANPAY ) . EditPush ( 70 , " 81 " , " 01 " ) ) ;
good . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey0C < < OP_CHECKSIG ,
" P2SH(P2PK) " , SCRIPT_VERIFY_P2SH , true
) . PushSig ( keys . key0 ) . PushRedeem ( ) ) ;
bad . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey0C < < OP_CHECKSIG ,
" P2SH(P2PK), bad redeemscript " , SCRIPT_VERIFY_P2SH , true
) . PushSig ( keys . key0 ) . PushRedeem ( ) . DamagePush ( 10 ) ) ;
good . push_back ( TestBuilder ( CScript ( ) < < OP_DUP < < OP_HASH160 < < keys . pubkey1 . GetID ( ) < < OP_EQUALVERIFY < < OP_CHECKSIG ,
" P2SH(P2PKH), bad sig but no VERIFY_P2SH " , 0 , true
) . PushSig ( keys . key0 ) . DamagePush ( 10 ) . PushRedeem ( ) ) ;
bad . push_back ( TestBuilder ( CScript ( ) < < OP_DUP < < OP_HASH160 < < keys . pubkey1 . GetID ( ) < < OP_EQUALVERIFY < < OP_CHECKSIG ,
" P2SH(P2PKH), bad sig " , SCRIPT_VERIFY_P2SH , true
) . PushSig ( keys . key0 ) . DamagePush ( 10 ) . PushRedeem ( ) ) ;
good . push_back ( TestBuilder ( CScript ( ) < < OP_3 < < keys . pubkey0C < < keys . pubkey1C < < keys . pubkey2C < < OP_3 < < OP_CHECKMULTISIG ,
" 3-of-3 " , 0
) . Num ( 0 ) . PushSig ( keys . key0 ) . PushSig ( keys . key1 ) . PushSig ( keys . key2 ) ) ;
bad . push_back ( TestBuilder ( CScript ( ) < < OP_3 < < keys . pubkey0C < < keys . pubkey1C < < keys . pubkey2C < < OP_3 < < OP_CHECKMULTISIG ,
" 3-of-3, 2 sigs " , 0
) . Num ( 0 ) . PushSig ( keys . key0 ) . PushSig ( keys . key1 ) . Num ( 0 ) ) ;
good . push_back ( TestBuilder ( CScript ( ) < < OP_2 < < keys . pubkey0C < < keys . pubkey1C < < keys . pubkey2C < < OP_3 < < OP_CHECKMULTISIG ,
" P2SH(2-of-3) " , SCRIPT_VERIFY_P2SH , true
) . Num ( 0 ) . PushSig ( keys . key1 ) . PushSig ( keys . key2 ) . PushRedeem ( ) ) ;
bad . push_back ( TestBuilder ( CScript ( ) < < OP_2 < < keys . pubkey0C < < keys . pubkey1C < < keys . pubkey2C < < OP_3 < < OP_CHECKMULTISIG ,
" P2SH(2-of-3), 1 sig " , SCRIPT_VERIFY_P2SH , true
) . Num ( 0 ) . PushSig ( keys . key1 ) . Num ( 0 ) . PushRedeem ( ) ) ;
good . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey1C < < OP_CHECKSIG ,
" P2PK with too much R padding but no STRICTENC " , 0
) . PushSig ( keys . key1 , SIGHASH_ALL , 31 , 32 ) . EditPush ( 1 , " 43021F " , " 44022000 " ) ) ;
bad . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey1C < < OP_CHECKSIG ,
" P2PK with too much R padding " , SCRIPT_VERIFY_STRICTENC
) . PushSig ( keys . key1 , SIGHASH_ALL , 31 , 32 ) . EditPush ( 1 , " 43021F " , " 44022000 " ) ) ;
good . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey1C < < OP_CHECKSIG ,
" P2PK with too much S padding but no STRICTENC " , 0
) . PushSig ( keys . key1 , SIGHASH_ALL ) . EditPush ( 1 , " 44 " , " 45 " ) . EditPush ( 37 , " 20 " , " 2100 " ) ) ;
bad . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey1C < < OP_CHECKSIG ,
" P2PK with too much S padding " , SCRIPT_VERIFY_STRICTENC
) . PushSig ( keys . key1 , SIGHASH_ALL ) . EditPush ( 1 , " 44 " , " 45 " ) . EditPush ( 37 , " 20 " , " 2100 " ) ) ;
good . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey1C < < OP_CHECKSIG ,
" P2PK with too little R padding but no STRICTENC " , 0
) . PushSig ( keys . key1 , SIGHASH_ALL , 33 , 32 ) . EditPush ( 1 , " 45022100 " , " 440220 " ) ) ;
bad . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey1C < < OP_CHECKSIG ,
" P2PK with too little R padding " , SCRIPT_VERIFY_STRICTENC
) . PushSig ( keys . key1 , SIGHASH_ALL , 33 , 32 ) . EditPush ( 1 , " 45022100 " , " 440220 " ) ) ;
good . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey2C < < OP_CHECKSIG ,
" P2PK with high S but no LOW_S " , SCRIPT_VERIFY_STRICTENC
) . PushSig ( keys . key2 , SIGHASH_ALL , 32 , 33 ) ) ;
good . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey2C < < OP_CHECKSIG ,
" P2PK with high S but no STRICTENC " , SCRIPT_VERIFY_LOW_S
) . PushSig ( keys . key2 , SIGHASH_ALL , 32 , 33 ) ) ;
bad . push_back ( TestBuilder ( CScript ( ) < < keys . pubkey2C < < OP_CHECKSIG ,
" P2PK with high S " , SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC
) . PushSig ( keys . key2 , SIGHASH_ALL , 32 , 33 ) ) ;
good . push_back ( TestBuilder ( CScript ( ) < < OP_3 < < keys . pubkey0C < < keys . pubkey1C < < keys . pubkey2C < < OP_3 < < OP_CHECKMULTISIG ,
" 3-of-3 with nonzero dummy but no NULLDUMMY " , 0
) . Num ( 1 ) . PushSig ( keys . key0 ) . PushSig ( keys . key1 ) . PushSig ( keys . key2 ) ) ;
bad . push_back ( TestBuilder ( CScript ( ) < < OP_3 < < keys . pubkey0C < < keys . pubkey1C < < keys . pubkey2C < < OP_3 < < OP_CHECKMULTISIG ,
" 3-of-3 with nonzero dummy " , SCRIPT_VERIFY_NULLDUMMY
) . Num ( 1 ) . PushSig ( keys . key0 ) . PushSig ( keys . key1 ) . PushSig ( keys . key2 ) ) ;
std : : map < std : : string , Array > tests_good ;
std : : map < std : : string , Array > tests_bad ;
{
Array json_good = read_json ( std : : string ( json_tests : : script_valid , json_tests : : script_valid + sizeof ( json_tests : : script_valid ) ) ) ;
Array json_bad = read_json ( std : : string ( json_tests : : script_invalid , json_tests : : script_invalid + sizeof ( json_tests : : script_invalid ) ) ) ;
BOOST_FOREACH ( Value & tv , json_good ) {
Array test = tv . get_array ( ) ;
if ( test . size ( ) > = 4 ) {
tests_good [ test [ 3 ] . get_str ( ) ] = test ;
}
}
BOOST_FOREACH ( Value & tv , json_bad ) {
Array test = tv . get_array ( ) ;
if ( test . size ( ) > = 4 ) {
tests_bad [ test [ 3 ] . get_str ( ) ] = test ;
}
}
}
std : : string strGood ;
std : : string strBad ;
BOOST_FOREACH ( TestBuilder & test , good ) {
test . Test ( true ) ;
BOOST_CHECK_MESSAGE ( tests_good . count ( test . GetComment ( ) ) > 0 , " Missing auto script_valid test: " + test . GetComment ( ) ) ;
BOOST_CHECK_MESSAGE ( ParseScript ( tests_good [ test . GetComment ( ) ] [ 1 ] . get_str ( ) ) = = test . GetScriptPubKey ( ) , " ScriptPubKey mismatch in auto script_valid test: " + test . GetComment ( ) ) ;
strGood + = test ;
}
BOOST_FOREACH ( TestBuilder & test , bad ) {
test . Test ( false ) ;
BOOST_CHECK_MESSAGE ( tests_bad . count ( test . GetComment ( ) ) > 0 , " Missing auto script_invalid test: " + test . GetComment ( ) ) ;
BOOST_CHECK_MESSAGE ( ParseScript ( tests_bad [ test . GetComment ( ) ] [ 1 ] . get_str ( ) ) = = test . GetScriptPubKey ( ) , " ScriptPubKey mismatch in auto script_invalid test: " + test . GetComment ( ) ) ;
strBad + = test ;
}
#if 0
FILE * valid = fopen ( " script_valid.json.gen " , " w " ) ;
fputs ( strGood . c_str ( ) , valid ) ;
fclose ( valid ) ;
FILE * invalid = fopen ( " script_invalid.json.gen " , " w " ) ;
fputs ( strBad . c_str ( ) , invalid ) ;
fclose ( invalid ) ;
# endif
}
2012-04-17 23:57:06 +02:00
BOOST_AUTO_TEST_CASE ( script_valid )
{
// Read tests from test/data/script_valid.json
// Format is an array of arrays
2014-09-08 21:15:31 +02:00
// Inner arrays are [ "scriptSig", "scriptPubKey", "flags" ]
2012-04-17 23:57:06 +02:00
// ... where scriptSig and scriptPubKey are stringified
// scripts.
2013-09-10 21:18:09 +02:00
Array tests = read_json ( std : : string ( json_tests : : script_valid , json_tests : : script_valid + sizeof ( json_tests : : script_valid ) ) ) ;
2012-04-17 23:57:06 +02:00
BOOST_FOREACH ( Value & tv , tests )
{
Array test = tv . get_array ( ) ;
2013-10-22 11:43:38 +02:00
string strTest = write_string ( tv , false ) ;
2014-09-08 21:15:31 +02:00
if ( test . size ( ) < 3 ) // Allow size > 3; extra stuff ignored (useful for comments)
2012-04-17 23:57:06 +02:00
{
2014-09-20 00:20:53 +02:00
if ( test . size ( ) ! = 1 ) {
BOOST_ERROR ( " Bad test: " < < strTest ) ;
}
2012-04-17 23:57:06 +02:00
continue ;
}
string scriptSigString = test [ 0 ] . get_str ( ) ;
CScript scriptSig = ParseScript ( scriptSigString ) ;
string scriptPubKeyString = test [ 1 ] . get_str ( ) ;
CScript scriptPubKey = ParseScript ( scriptPubKeyString ) ;
2014-09-08 21:15:31 +02:00
unsigned int scriptflags = ParseScriptFlags ( test [ 2 ] . get_str ( ) ) ;
2012-04-17 23:57:06 +02:00
2014-09-20 03:13:04 +02:00
DoTest ( scriptPubKey , scriptSig , scriptflags , true , strTest ) ;
2012-04-17 23:57:06 +02:00
}
}
BOOST_AUTO_TEST_CASE ( script_invalid )
{
// Scripts that should evaluate as invalid
2013-09-10 21:18:09 +02:00
Array tests = read_json ( std : : string ( json_tests : : script_invalid , json_tests : : script_invalid + sizeof ( json_tests : : script_invalid ) ) ) ;
2012-04-17 23:57:06 +02:00
BOOST_FOREACH ( Value & tv , tests )
{
Array test = tv . get_array ( ) ;
2013-10-22 11:43:38 +02:00
string strTest = write_string ( tv , false ) ;
2014-09-20 00:20:53 +02:00
if ( test . size ( ) < 3 ) // Allow size > 3; extra stuff ignored (useful for comments)
2012-04-17 23:57:06 +02:00
{
2014-09-20 00:20:53 +02:00
if ( test . size ( ) ! = 1 ) {
BOOST_ERROR ( " Bad test: " < < strTest ) ;
}
2012-04-17 23:57:06 +02:00
continue ;
}
string scriptSigString = test [ 0 ] . get_str ( ) ;
CScript scriptSig = ParseScript ( scriptSigString ) ;
string scriptPubKeyString = test [ 1 ] . get_str ( ) ;
CScript scriptPubKey = ParseScript ( scriptPubKeyString ) ;
2014-09-08 21:15:31 +02:00
unsigned int scriptflags = ParseScriptFlags ( test [ 2 ] . get_str ( ) ) ;
2012-04-17 23:57:06 +02:00
2014-09-20 03:13:04 +02:00
DoTest ( scriptPubKey , scriptSig , scriptflags , false , strTest ) ;
2012-04-17 23:57:06 +02:00
}
}
2011-07-31 20:01:31 +02:00
BOOST_AUTO_TEST_CASE ( script_PushData )
{
// Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on
// the stack as the 1-75 opcodes do.
static const unsigned char direct [ ] = { 1 , 0x5a } ;
static const unsigned char pushdata1 [ ] = { OP_PUSHDATA1 , 1 , 0x5a } ;
static const unsigned char pushdata2 [ ] = { OP_PUSHDATA2 , 1 , 0 , 0x5a } ;
static const unsigned char pushdata4 [ ] = { OP_PUSHDATA4 , 1 , 0 , 0 , 0 , 0x5a } ;
vector < vector < unsigned char > > directStack ;
2014-07-18 18:47:10 +02:00
BOOST_CHECK ( EvalScript ( directStack , CScript ( & direct [ 0 ] , & direct [ sizeof ( direct ) ] ) , CTransaction ( ) , 0 , true ) ) ;
2011-07-31 20:01:31 +02:00
vector < vector < unsigned char > > pushdata1Stack ;
2014-07-18 18:47:10 +02:00
BOOST_CHECK ( EvalScript ( pushdata1Stack , CScript ( & pushdata1 [ 0 ] , & pushdata1 [ sizeof ( pushdata1 ) ] ) , CTransaction ( ) , 0 , true ) ) ;
2011-07-31 20:01:31 +02:00
BOOST_CHECK ( pushdata1Stack = = directStack ) ;
vector < vector < unsigned char > > pushdata2Stack ;
2014-07-18 18:47:10 +02:00
BOOST_CHECK ( EvalScript ( pushdata2Stack , CScript ( & pushdata2 [ 0 ] , & pushdata2 [ sizeof ( pushdata2 ) ] ) , CTransaction ( ) , 0 , true ) ) ;
2011-07-31 20:01:31 +02:00
BOOST_CHECK ( pushdata2Stack = = directStack ) ;
vector < vector < unsigned char > > pushdata4Stack ;
2014-07-18 18:47:10 +02:00
BOOST_CHECK ( EvalScript ( pushdata4Stack , CScript ( & pushdata4 [ 0 ] , & pushdata4 [ sizeof ( pushdata4 ) ] ) , CTransaction ( ) , 0 , true ) ) ;
2011-07-31 20:01:31 +02:00
BOOST_CHECK ( pushdata4Stack = = directStack ) ;
}
2011-08-27 00:41:22 +02:00
CScript
sign_multisig ( CScript scriptPubKey , std : : vector < CKey > keys , CTransaction transaction )
{
uint256 hash = SignatureHash ( scriptPubKey , transaction , 0 , SIGHASH_ALL ) ;
CScript result ;
//
// NOTE: CHECKMULTISIG has an unfortunate bug; it requires
// one extra item on the stack, before the signatures.
// Putting OP_0 on the stack is the workaround;
2012-10-05 19:22:21 +02:00
// fixing the bug would mean splitting the block chain (old
2011-08-27 00:41:22 +02:00
// clients would not accept new CHECKMULTISIG transactions,
// and vice-versa)
//
result < < OP_0 ;
2013-05-01 06:52:05 +02:00
BOOST_FOREACH ( const CKey & key , keys )
2011-08-27 00:41:22 +02:00
{
vector < unsigned char > vchSig ;
BOOST_CHECK ( key . Sign ( hash , vchSig ) ) ;
vchSig . push_back ( ( unsigned char ) SIGHASH_ALL ) ;
result < < vchSig ;
}
return result ;
}
CScript
2013-05-01 06:52:05 +02:00
sign_multisig ( CScript scriptPubKey , const CKey & key , CTransaction transaction )
2011-08-27 00:41:22 +02:00
{
std : : vector < CKey > keys ;
keys . push_back ( key ) ;
return sign_multisig ( scriptPubKey , keys , transaction ) ;
}
BOOST_AUTO_TEST_CASE ( script_CHECKMULTISIG12 )
{
CKey key1 , key2 , key3 ;
2012-02-20 18:32:33 +01:00
key1 . MakeNewKey ( true ) ;
key2 . MakeNewKey ( false ) ;
key3 . MakeNewKey ( true ) ;
2011-08-27 00:41:22 +02:00
CScript scriptPubKey12 ;
scriptPubKey12 < < OP_1 < < key1 . GetPubKey ( ) < < key2 . GetPubKey ( ) < < OP_2 < < OP_CHECKMULTISIG ;
2014-06-07 13:53:27 +02:00
CMutableTransaction txFrom12 ;
2011-08-27 00:41:22 +02:00
txFrom12 . vout . resize ( 1 ) ;
txFrom12 . vout [ 0 ] . scriptPubKey = scriptPubKey12 ;
2014-06-07 13:53:27 +02:00
CMutableTransaction txTo12 ;
2011-08-27 00:41:22 +02:00
txTo12 . vin . resize ( 1 ) ;
txTo12 . vout . resize ( 1 ) ;
txTo12 . vin [ 0 ] . prevout . n = 0 ;
txTo12 . vin [ 0 ] . prevout . hash = txFrom12 . GetHash ( ) ;
txTo12 . vout [ 0 ] . nValue = 1 ;
CScript goodsig1 = sign_multisig ( scriptPubKey12 , key1 , txTo12 ) ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( VerifyScript ( goodsig1 , scriptPubKey12 , txTo12 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
txTo12 . vout [ 0 ] . nValue = 2 ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( ! VerifyScript ( goodsig1 , scriptPubKey12 , txTo12 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
CScript goodsig2 = sign_multisig ( scriptPubKey12 , key2 , txTo12 ) ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( VerifyScript ( goodsig2 , scriptPubKey12 , txTo12 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
CScript badsig1 = sign_multisig ( scriptPubKey12 , key3 , txTo12 ) ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( ! VerifyScript ( badsig1 , scriptPubKey12 , txTo12 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
}
BOOST_AUTO_TEST_CASE ( script_CHECKMULTISIG23 )
{
CKey key1 , key2 , key3 , key4 ;
2012-02-20 18:32:33 +01:00
key1 . MakeNewKey ( true ) ;
key2 . MakeNewKey ( false ) ;
key3 . MakeNewKey ( true ) ;
key4 . MakeNewKey ( false ) ;
2011-08-27 00:41:22 +02:00
CScript scriptPubKey23 ;
scriptPubKey23 < < OP_2 < < key1 . GetPubKey ( ) < < key2 . GetPubKey ( ) < < key3 . GetPubKey ( ) < < OP_3 < < OP_CHECKMULTISIG ;
2014-06-07 13:53:27 +02:00
CMutableTransaction txFrom23 ;
2011-08-27 00:41:22 +02:00
txFrom23 . vout . resize ( 1 ) ;
txFrom23 . vout [ 0 ] . scriptPubKey = scriptPubKey23 ;
2014-06-07 13:53:27 +02:00
CMutableTransaction txTo23 ;
2011-08-27 00:41:22 +02:00
txTo23 . vin . resize ( 1 ) ;
txTo23 . vout . resize ( 1 ) ;
txTo23 . vin [ 0 ] . prevout . n = 0 ;
txTo23 . vin [ 0 ] . prevout . hash = txFrom23 . GetHash ( ) ;
txTo23 . vout [ 0 ] . nValue = 1 ;
std : : vector < CKey > keys ;
keys . push_back ( key1 ) ; keys . push_back ( key2 ) ;
CScript goodsig1 = sign_multisig ( scriptPubKey23 , keys , txTo23 ) ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( VerifyScript ( goodsig1 , scriptPubKey23 , txTo23 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
keys . clear ( ) ;
keys . push_back ( key1 ) ; keys . push_back ( key3 ) ;
CScript goodsig2 = sign_multisig ( scriptPubKey23 , keys , txTo23 ) ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( VerifyScript ( goodsig2 , scriptPubKey23 , txTo23 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
keys . clear ( ) ;
keys . push_back ( key2 ) ; keys . push_back ( key3 ) ;
CScript goodsig3 = sign_multisig ( scriptPubKey23 , keys , txTo23 ) ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( VerifyScript ( goodsig3 , scriptPubKey23 , txTo23 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
keys . clear ( ) ;
keys . push_back ( key2 ) ; keys . push_back ( key2 ) ; // Can't re-use sig
CScript badsig1 = sign_multisig ( scriptPubKey23 , keys , txTo23 ) ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( ! VerifyScript ( badsig1 , scriptPubKey23 , txTo23 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
keys . clear ( ) ;
keys . push_back ( key2 ) ; keys . push_back ( key1 ) ; // sigs must be in correct order
CScript badsig2 = sign_multisig ( scriptPubKey23 , keys , txTo23 ) ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( ! VerifyScript ( badsig2 , scriptPubKey23 , txTo23 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
keys . clear ( ) ;
keys . push_back ( key3 ) ; keys . push_back ( key2 ) ; // sigs must be in correct order
CScript badsig3 = sign_multisig ( scriptPubKey23 , keys , txTo23 ) ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( ! VerifyScript ( badsig3 , scriptPubKey23 , txTo23 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
keys . clear ( ) ;
keys . push_back ( key4 ) ; keys . push_back ( key2 ) ; // sigs must match pubkeys
CScript badsig4 = sign_multisig ( scriptPubKey23 , keys , txTo23 ) ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( ! VerifyScript ( badsig4 , scriptPubKey23 , txTo23 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
keys . clear ( ) ;
keys . push_back ( key1 ) ; keys . push_back ( key4 ) ; // sigs must match pubkeys
CScript badsig5 = sign_multisig ( scriptPubKey23 , keys , txTo23 ) ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( ! VerifyScript ( badsig5 , scriptPubKey23 , txTo23 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
keys . clear ( ) ; // Must have signatures
CScript badsig6 = sign_multisig ( scriptPubKey23 , keys , txTo23 ) ;
2014-07-18 17:48:00 +02:00
BOOST_CHECK ( ! VerifyScript ( badsig6 , scriptPubKey23 , txTo23 , 0 , flags ) ) ;
2011-08-27 00:41:22 +02:00
}
2012-05-31 22:01:16 +02:00
BOOST_AUTO_TEST_CASE ( script_combineSigs )
{
// Test the CombineSignatures function
CBasicKeyStore keystore ;
vector < CKey > keys ;
2013-05-01 06:52:05 +02:00
vector < CPubKey > pubkeys ;
2012-05-31 22:01:16 +02:00
for ( int i = 0 ; i < 3 ; i + + )
{
CKey key ;
key . MakeNewKey ( i % 2 = = 1 ) ;
keys . push_back ( key ) ;
2013-05-01 06:52:05 +02:00
pubkeys . push_back ( key . GetPubKey ( ) ) ;
2012-05-31 22:01:16 +02:00
keystore . AddKey ( key ) ;
}
2014-06-07 13:53:27 +02:00
CMutableTransaction txFrom ;
2012-05-31 22:01:16 +02:00
txFrom . vout . resize ( 1 ) ;
2014-09-11 19:15:29 +02:00
txFrom . vout [ 0 ] . scriptPubKey = GetScriptForDestination ( keys [ 0 ] . GetPubKey ( ) . GetID ( ) ) ;
2012-05-31 22:01:16 +02:00
CScript & scriptPubKey = txFrom . vout [ 0 ] . scriptPubKey ;
2014-06-07 13:53:27 +02:00
CMutableTransaction txTo ;
2012-05-31 22:01:16 +02:00
txTo . vin . resize ( 1 ) ;
txTo . vout . resize ( 1 ) ;
txTo . vin [ 0 ] . prevout . n = 0 ;
txTo . vin [ 0 ] . prevout . hash = txFrom . GetHash ( ) ;
CScript & scriptSig = txTo . vin [ 0 ] . scriptSig ;
txTo . vout [ 0 ] . nValue = 1 ;
CScript empty ;
CScript combined = CombineSignatures ( scriptPubKey , txTo , 0 , empty , empty ) ;
BOOST_CHECK ( combined . empty ( ) ) ;
// Single signature case:
SignSignature ( keystore , txFrom , txTo , 0 ) ; // changes scriptSig
combined = CombineSignatures ( scriptPubKey , txTo , 0 , scriptSig , empty ) ;
BOOST_CHECK ( combined = = scriptSig ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , empty , scriptSig ) ;
BOOST_CHECK ( combined = = scriptSig ) ;
CScript scriptSigCopy = scriptSig ;
// Signing again will give a different, valid signature:
SignSignature ( keystore , txFrom , txTo , 0 ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , scriptSigCopy , scriptSig ) ;
BOOST_CHECK ( combined = = scriptSigCopy | | combined = = scriptSig ) ;
// P2SH, single-signature case:
CScript pkSingle ; pkSingle < < keys [ 0 ] . GetPubKey ( ) < < OP_CHECKSIG ;
keystore . AddCScript ( pkSingle ) ;
2014-09-11 19:15:29 +02:00
scriptPubKey = GetScriptForDestination ( pkSingle . GetID ( ) ) ;
2012-05-31 22:01:16 +02:00
SignSignature ( keystore , txFrom , txTo , 0 ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , scriptSig , empty ) ;
BOOST_CHECK ( combined = = scriptSig ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , empty , scriptSig ) ;
BOOST_CHECK ( combined = = scriptSig ) ;
scriptSigCopy = scriptSig ;
SignSignature ( keystore , txFrom , txTo , 0 ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , scriptSigCopy , scriptSig ) ;
BOOST_CHECK ( combined = = scriptSigCopy | | combined = = scriptSig ) ;
// dummy scriptSigCopy with placeholder, should always choose non-placeholder:
scriptSigCopy = CScript ( ) < < OP_0 < < static_cast < vector < unsigned char > > ( pkSingle ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , scriptSigCopy , scriptSig ) ;
BOOST_CHECK ( combined = = scriptSig ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , scriptSig , scriptSigCopy ) ;
BOOST_CHECK ( combined = = scriptSig ) ;
// Hardest case: Multisig 2-of-3
2014-09-11 19:15:29 +02:00
scriptPubKey = GetScriptForMultisig ( 2 , pubkeys ) ;
2012-05-31 22:01:16 +02:00
keystore . AddCScript ( scriptPubKey ) ;
SignSignature ( keystore , txFrom , txTo , 0 ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , scriptSig , empty ) ;
BOOST_CHECK ( combined = = scriptSig ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , empty , scriptSig ) ;
BOOST_CHECK ( combined = = scriptSig ) ;
// A couple of partially-signed versions:
vector < unsigned char > sig1 ;
uint256 hash1 = SignatureHash ( scriptPubKey , txTo , 0 , SIGHASH_ALL ) ;
BOOST_CHECK ( keys [ 0 ] . Sign ( hash1 , sig1 ) ) ;
sig1 . push_back ( SIGHASH_ALL ) ;
vector < unsigned char > sig2 ;
uint256 hash2 = SignatureHash ( scriptPubKey , txTo , 0 , SIGHASH_NONE ) ;
BOOST_CHECK ( keys [ 1 ] . Sign ( hash2 , sig2 ) ) ;
sig2 . push_back ( SIGHASH_NONE ) ;
vector < unsigned char > sig3 ;
uint256 hash3 = SignatureHash ( scriptPubKey , txTo , 0 , SIGHASH_SINGLE ) ;
BOOST_CHECK ( keys [ 2 ] . Sign ( hash3 , sig3 ) ) ;
sig3 . push_back ( SIGHASH_SINGLE ) ;
// Not fussy about order (or even existence) of placeholders or signatures:
CScript partial1a = CScript ( ) < < OP_0 < < sig1 < < OP_0 ;
CScript partial1b = CScript ( ) < < OP_0 < < OP_0 < < sig1 ;
CScript partial2a = CScript ( ) < < OP_0 < < sig2 ;
CScript partial2b = CScript ( ) < < sig2 < < OP_0 ;
CScript partial3a = CScript ( ) < < sig3 ;
CScript partial3b = CScript ( ) < < OP_0 < < OP_0 < < sig3 ;
CScript partial3c = CScript ( ) < < OP_0 < < sig3 < < OP_0 ;
CScript complete12 = CScript ( ) < < OP_0 < < sig1 < < sig2 ;
CScript complete13 = CScript ( ) < < OP_0 < < sig1 < < sig3 ;
CScript complete23 = CScript ( ) < < OP_0 < < sig2 < < sig3 ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , partial1a , partial1b ) ;
BOOST_CHECK ( combined = = partial1a ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , partial1a , partial2a ) ;
BOOST_CHECK ( combined = = complete12 ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , partial2a , partial1a ) ;
BOOST_CHECK ( combined = = complete12 ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , partial1b , partial2b ) ;
BOOST_CHECK ( combined = = complete12 ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , partial3b , partial1b ) ;
BOOST_CHECK ( combined = = complete13 ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , partial2a , partial3a ) ;
BOOST_CHECK ( combined = = complete23 ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , partial3b , partial2b ) ;
BOOST_CHECK ( combined = = complete23 ) ;
combined = CombineSignatures ( scriptPubKey , txTo , 0 , partial3b , partial3a ) ;
BOOST_CHECK ( combined = = partial3c ) ;
}
2011-08-27 00:41:22 +02:00
2013-09-24 00:48:00 +02:00
BOOST_AUTO_TEST_CASE ( script_standard_push )
{
for ( int i = 0 ; i < 1000 ; i + + ) {
CScript script ;
script < < i ;
BOOST_CHECK_MESSAGE ( script . IsPushOnly ( ) , " Number " < < i < < " is not pure push. " ) ;
BOOST_CHECK_MESSAGE ( script . HasCanonicalPushes ( ) , " Number " < < i < < " push is not canonical. " ) ;
}
for ( int i = 0 ; i < 1000 ; i + + ) {
std : : vector < unsigned char > data ( i , ' \111 ' ) ;
CScript script ;
script < < data ;
BOOST_CHECK_MESSAGE ( script . IsPushOnly ( ) , " Length " < < i < < " is not pure push. " ) ;
BOOST_CHECK_MESSAGE ( script . HasCanonicalPushes ( ) , " Length " < < i < < " push is not canonical. " ) ;
}
}
2014-08-25 03:16:51 +02:00
BOOST_AUTO_TEST_CASE ( script_IsPushOnly_on_invalid_scripts )
{
// IsPushOnly returns false when given a script containing only pushes that
// are invalid due to truncation. IsPushOnly() is consensus critical
// because P2SH evaluation uses it, although this specific behavior should
// not be consensus critical as the P2SH evaluation would fail first due to
// the invalid push. Still, it doesn't hurt to test it explicitly.
static const unsigned char direct [ ] = { 1 } ;
BOOST_CHECK ( ! CScript ( direct , direct + sizeof ( direct ) ) . IsPushOnly ( ) ) ;
}
2011-07-31 20:01:31 +02:00
BOOST_AUTO_TEST_SUITE_END ( )