@ -20,29 +20,29 @@ typedef std::vector<unsigned char> valtype;
@@ -20,29 +20,29 @@ typedef std::vector<unsigned char> valtype;
TransactionSignatureCreator : : TransactionSignatureCreator ( const CKeyStore * keystoreIn , const CTransaction * txToIn , unsigned int nInIn , const CAmount & amountIn , int nHashTypeIn ) : BaseSignatureCreator ( keystoreIn ) , txTo ( txToIn ) , nIn ( nInIn ) , nHashType ( nHashTypeIn ) , amount ( amountIn ) , checker ( txTo , nIn , amountIn ) { }
bool TransactionSignatureCreator : : CreateSig ( std : : vector < unsigned char > & vchSig , const CKeyID & address , const CScript & scriptCode ) const
bool TransactionSignatureCreator : : CreateSig ( std : : vector < unsigned char > & vchSig , const CKeyID & address , const CScript & scriptCode , SigVersion sigversion ) const
{
CKey key ;
if ( ! keystore - > GetKey ( address , key ) )
return false ;
uint256 hash = SignatureHash ( scriptCode , * txTo , nIn , nHashType , amount , SIGVERSION_BASE ) ;
uint256 hash = SignatureHash ( scriptCode , * txTo , nIn , nHashType , amount , sigversion ) ;
if ( ! key . Sign ( hash , vchSig ) )
return false ;
vchSig . push_back ( ( unsigned char ) nHashType ) ;
return true ;
}
static bool Sign1 ( const CKeyID & address , const BaseSignatureCreator & creator , const CScript & scriptCode , CScript & scriptSigRet )
static bool Sign1 ( const CKeyID & address , const BaseSignatureCreator & creator , const CScript & scriptCode , std : : vector < valtype > & ret , SigVersion sigversion )
{
vector < unsigned char > vchSig ;
if ( ! creator . CreateSig ( vchSig , address , scriptCode ) )
if ( ! creator . CreateSig ( vchSig , address , scriptCode , sigversion ) )
return false ;
scriptSigRet < < vchSig ;
ret . push_back ( vchSig ) ;
return true ;
}
static bool SignN ( const vector < valtype > & multisigdata , const BaseSignatureCreator & creator , const CScript & scriptCode , CScript & scriptSigRet )
static bool SignN ( const vector < valtype > & multisigdata , const BaseSignatureCreator & creator , const CScript & scriptCode , std : : vector < valtype > & ret , SigVersion sigversion )
{
int nSigned = 0 ;
int nRequired = multisigdata . front ( ) [ 0 ] ;
@ -50,7 +50,7 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
@@ -50,7 +50,7 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
{
const valtype & pubkey = multisigdata [ i ] ;
CKeyID keyID = CPubKey ( pubkey ) . GetID ( ) ;
if ( Sign1 ( keyID , creator , scriptCode , scriptSigRet ) )
if ( Sign1 ( keyID , creator , scriptCode , ret , sigversion ) )
+ + nSigned ;
}
return nSigned = = nRequired ;
@ -63,9 +63,11 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
@@ -63,9 +63,11 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
* Returns false if scriptPubKey could not be completely satisfied .
*/
static bool SignStep ( const BaseSignatureCreator & creator , const CScript & scriptPubKey ,
CScript & sc riptSigR et, txnouttype & whichTypeRet )
std : : vector < valtype > & ret , txnouttype & whichTypeRet , SigVersion sigversion )
{
scriptSigRet . clear ( ) ;
CScript scriptRet ;
uint160 h160 ;
ret . clear ( ) ;
vector < valtype > vSolutions ;
if ( ! Solver ( scriptPubKey , whichTypeRet , vSolutions ) )
@ -79,62 +81,142 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
@@ -79,62 +81,142 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
return false ;
case TX_PUBKEY :
keyID = CPubKey ( vSolutions [ 0 ] ) . GetID ( ) ;
return Sign1 ( keyID , creator , scriptPubKey , scriptSigRet ) ;
return Sign1 ( keyID , creator , scriptPubKey , ret , sigversion ) ;
case TX_PUBKEYHASH :
keyID = CKeyID ( uint160 ( vSolutions [ 0 ] ) ) ;
if ( ! Sign1 ( keyID , creator , scriptPubKey , scriptSigRet ) )
if ( ! Sign1 ( keyID , creator , scriptPubKey , ret , sigversion ) )
return false ;
else
{
CPubKey vch ;
creator . KeyStore ( ) . GetPubKey ( keyID , vch ) ;
scriptSigRet < < ToByteVector ( vch ) ;
ret . push_back ( ToByteVector ( vch ) ) ;
}
return true ;
case TX_SCRIPTHASH :
return creator . KeyStore ( ) . GetCScript ( uint160 ( vSolutions [ 0 ] ) , scriptSigRet ) ;
if ( creator . KeyStore ( ) . GetCScript ( uint160 ( vSolutions [ 0 ] ) , scriptRet ) ) {
ret . push_back ( std : : vector < unsigned char > ( scriptRet . begin ( ) , scriptRet . end ( ) ) ) ;
return true ;
}
return false ;
case TX_MULTISIG :
scriptSigRet < < OP_0 ; // workaround CHECKMULTISIG bug
return ( SignN ( vSolutions , creator , scriptPubKey , scriptSigRet ) ) ;
ret . push_back ( valtype ( ) ) ; // workaround CHECKMULTISIG bug
return ( SignN ( vSolutions , creator , scriptPubKey , ret , sigversion ) ) ;
case TX_WITNESS_V0_KEYHASH :
ret . push_back ( vSolutions [ 0 ] ) ;
return true ;
case TX_WITNESS_V0_SCRIPTHASH :
CRIPEMD160 ( ) . Write ( & vSolutions [ 0 ] [ 0 ] , vSolutions [ 0 ] . size ( ) ) . Finalize ( h160 . begin ( ) ) ;
if ( creator . KeyStore ( ) . GetCScript ( h160 , scriptRet ) ) {
ret . push_back ( std : : vector < unsigned char > ( scriptRet . begin ( ) , scriptRet . end ( ) ) ) ;
return true ;
}
return false ;
default :
return false ;
}
}
static CScript PushAll ( const vector < valtype > & values )
{
CScript result ;
BOOST_FOREACH ( const valtype & v , values ) {
if ( v . size ( ) = = 0 ) {
result < < OP_0 ;
} else if ( v . size ( ) = = 1 & & v [ 0 ] > = 1 & & v [ 0 ] < = 16 ) {
result < < CScript : : EncodeOP_N ( v [ 0 ] ) ;
} else {
result < < v ;
}
}
return result ;
}
bool ProduceSignature ( const BaseSignatureCreator & creator , const CScript & fromPubKey , CScript & scriptSig )
bool ProduceSignature ( const BaseSignatureCreator & creator , const CScript & fromPubKey , SignatureData & sigdata )
{
CScript script = fromPubKey ;
bool solved = true ;
std : : vector < valtype > result ;
txnouttype whichType ;
if ( ! SignStep ( creator , fromPubKey , scriptSig , whichType ) )
return false ;
solved = SignStep ( creator , script , result , whichType , SIGVERSION_BASE ) ;
bool P2SH = false ;
CScript subscript ;
sigdata . scriptWitness . stack . clear ( ) ;
if ( whichType = = TX_SCRIPTHASH )
if ( solved & & whichType = = TX_SCRIPTHASH )
{
// Solver returns the subscript that need to be evaluated;
// Solver returns the subscript that needs to be evaluated;
// the final scriptSig is the signatures from that
// and then the serialized subscript:
CScript subscript = scriptSig ;
script = subscript = CScript ( result [ 0 ] . begin ( ) , result [ 0 ] . end ( ) ) ;
solved = solved & & SignStep ( creator , script , result , whichType , SIGVERSION_BASE ) & & whichType ! = TX_SCRIPTHASH ;
P2SH = true ;
}
if ( solved & & whichType = = TX_WITNESS_V0_KEYHASH )
{
CScript witnessscript ;
witnessscript < < OP_DUP < < OP_HASH160 < < ToByteVector ( result [ 0 ] ) < < OP_EQUALVERIFY < < OP_CHECKSIG ;
txnouttype subType ;
solved = solved & & SignStep ( creator , witnessscript , result , subType , SIGVERSION_WITNESS_V0 ) ;
sigdata . scriptWitness . stack = result ;
result . clear ( ) ;
}
else if ( solved & & whichType = = TX_WITNESS_V0_SCRIPTHASH )
{
CScript witnessscript ( result [ 0 ] . begin ( ) , result [ 0 ] . end ( ) ) ;
txnouttype subType ;
bool fSolved =
SignStep ( creator , subscript , scriptSig , subType ) & & subType ! = TX_SCRIPTHASH ;
// Append serialized subscript whether or not it is completely signed:
scriptSig < < valtype ( subscript . begin ( ) , subscript . end ( ) ) ;
if ( ! fSolved ) return false ;
solved = solved & & SignStep ( creator , witnessscript , result , subType , SIGVERSION_WITNESS_V0 ) & & subType ! = TX_SCRIPTHASH & & subType ! = TX_WITNESS_V0_SCRIPTHASH & & subType ! = TX_WITNESS_V0_KEYHASH ;
result . push_back ( std : : vector < unsigned char > ( witnessscript . begin ( ) , witnessscript . end ( ) ) ) ;
sigdata . scriptWitness . stack = result ;
result . clear ( ) ;
}
if ( P2SH ) {
result . push_back ( std : : vector < unsigned char > ( subscript . begin ( ) , subscript . end ( ) ) ) ;
}
sigdata . scriptSig = PushAll ( result ) ;
// Test solution
return VerifyScript ( scriptSig , fromPubKey , NULL , STANDARD_SCRIPT_VERIFY_FLAGS , creator . Checker ( ) ) ;
return solved & & VerifyScript ( sigdata . scriptSig , fromPubKey , & sigdata . scriptWitness , STANDARD_SCRIPT_VERIFY_FLAGS , creator . Checker ( ) ) ;
}
SignatureData DataFromTransaction ( const CMutableTransaction & tx , unsigned int nIn )
{
SignatureData data ;
assert ( tx . vin . size ( ) > nIn ) ;
data . scriptSig = tx . vin [ nIn ] . scriptSig ;
if ( tx . wit . vtxinwit . size ( ) > nIn ) {
data . scriptWitness = tx . wit . vtxinwit [ nIn ] . scriptWitness ;
}
return data ;
}
void UpdateTransaction ( CMutableTransaction & tx , unsigned int nIn , const SignatureData & data )
{
assert ( tx . vin . size ( ) > nIn ) ;
tx . vin [ nIn ] . scriptSig = data . scriptSig ;
if ( ! data . scriptWitness . IsNull ( ) | | tx . wit . vtxinwit . size ( ) > nIn ) {
tx . wit . vtxinwit . resize ( tx . vin . size ( ) ) ;
tx . wit . vtxinwit [ nIn ] . scriptWitness = data . scriptWitness ;
}
}
bool SignSignature ( const CKeyStore & keystore , const CScript & fromPubKey , CMutableTransaction & txTo , unsigned int nIn , int nHashType )
bool SignSignature ( const CKeyStore & keystore , const CScript & fromPubKey , CMutableTransaction & txTo , unsigned int nIn , const CAmount & amount , int nHashType )
{
assert ( nIn < txTo . vin . size ( ) ) ;
CTxIn & txin = txTo . vin [ nIn ] ;
CTransaction txToConst ( txTo ) ;
TransactionSignatureCreator creator ( & keystore , & txToConst , nIn , nHashType ) ;
TransactionSignatureCreator creator ( & keystore , & txToConst , nIn , amount , nHashType ) ;
return ProduceSignature ( creator , fromPubKey , txin . scriptSig ) ;
SignatureData sigdata ;
bool ret = ProduceSignature ( creator , fromPubKey , sigdata ) ;
UpdateTransaction ( txTo , nIn , sigdata ) ;
return ret ;
}
bool SignSignature ( const CKeyStore & keystore , const CTransaction & txFrom , CMutableTransaction & txTo , unsigned int nIn , int nHashType )
@ -144,20 +226,12 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutab
@@ -144,20 +226,12 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutab
assert ( txin . prevout . n < txFrom . vout . size ( ) ) ;
const CTxOut & txout = txFrom . vout [ txin . prevout . n ] ;
return SignSignature ( keystore , txout . scriptPubKey , txTo , nIn , nHashType ) ;
return SignSignature ( keystore , txout . scriptPubKey , txTo , nIn , txout . nValue , nHashType ) ;
}
static CScript PushAll ( const vector < valtype > & values )
{
CScript result ;
BOOST_FOREACH ( const valtype & v , values )
result < < v ;
return result ;
}
static CScript CombineMultisig ( const CScript & scriptPubKey , const BaseSignatureChecker & checker ,
static vector < valtype > CombineMultisig ( const CScript & scriptPubKey , const BaseSignatureChecker & checker ,
const vector < valtype > & vSolutions ,
const vector < valtype > & sigs1 , const vector < valtype > & sigs2 )
const vector < valtype > & sigs1 , const vector < valtype > & sigs2 , SigVersion sigversion )
{
// Combine all the signatures we've got:
set < valtype > allsigs ;
@ -185,7 +259,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
@@ -185,7 +259,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
if ( sigs . count ( pubkey ) )
continue ; // Already got a sig for this pubkey
if ( checker . CheckSig ( sig , pubkey , scriptPubKey , SIGVERSION_BASE ) )
if ( checker . CheckSig ( sig , pubkey , scriptPubKey , sigversion ) )
{
sigs [ pubkey ] = sig ;
break ;
@ -194,87 +268,126 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
@@ -194,87 +268,126 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
}
// Now build a merged CScript:
unsigned int nSigsHave = 0 ;
CScript result ; result < < OP_0 ; // pop-one-too-many workaround
std : : vector < valtype > result ; result . push_back ( valtype ( ) ) ; // pop-one-too-many workaround
for ( unsigned int i = 0 ; i < nPubKeys & & nSigsHave < nSigsRequired ; i + + )
{
if ( sigs . count ( vSolutions [ i + 1 ] ) )
{
result < < sigs [ vSolutions [ i + 1 ] ] ;
result . push_back ( sigs [ vSolutions [ i + 1 ] ] ) ;
+ + nSigsHave ;
}
}
// Fill any missing with OP_0:
for ( unsigned int i = nSigsHave ; i < nSigsRequired ; i + + )
result < < OP_0 ;
result . push_back ( valtype ( ) ) ;
return result ;
}
namespace
{
struct Stacks
{
std : : vector < valtype > script ;
std : : vector < valtype > witness ;
Stacks ( ) { }
explicit Stacks ( const std : : vector < valtype > & scriptSigStack_ ) : script ( scriptSigStack_ ) , witness ( ) { }
explicit Stacks ( const SignatureData & data ) : witness ( data . scriptWitness . stack ) {
EvalScript ( script , data . scriptSig , SCRIPT_VERIFY_STRICTENC , BaseSignatureChecker ( ) , SIGVERSION_BASE ) ;
}
SignatureData Output ( ) const {
SignatureData result ;
result . scriptSig = PushAll ( script ) ;
result . scriptWitness . stack = witness ;
return result ;
}
} ;
}
static CScript CombineSignatures ( const CScript & scriptPubKey , const BaseSignatureChecker & checker ,
static Stacks CombineSignatures ( const CScript & scriptPubKey , const BaseSignatureChecker & checker ,
const txnouttype txType , const vector < valtype > & vSolutions ,
vector < valtype > & sigs1 , vector < valtype > & sigs2 )
Stacks sigs1 , Stacks sigs2 , SigVersion sigversion )
{
switch ( txType )
{
case TX_NONSTANDARD :
case TX_NULL_DATA :
// Don't know anything about this, assume bigger one is correct:
if ( sigs1 . size ( ) > = sigs2 . size ( ) )
return PushAll ( sigs1 ) ;
return PushAll ( sigs2 ) ;
if ( sigs1 . script . s ize ( ) > = sigs2 . script . size ( ) )
return sigs1 ;
return sigs2 ;
case TX_PUBKEY :
case TX_PUBKEYHASH :
// Signatures are bigger than placeholders or empty scripts:
if ( sigs1 . empty ( ) | | sigs1 [ 0 ] . empty ( ) )
return PushAll ( sigs2 ) ;
return PushAll ( sigs1 ) ;
if ( sigs1 . script . empty ( ) | | sigs1 . script [ 0 ] . empty ( ) )
return sigs2 ;
return sigs1 ;
case TX_WITNESS_V0_KEYHASH :
// Signatures are bigger than placeholders or empty scripts:
if ( sigs1 . witness . empty ( ) | | sigs1 . witness [ 0 ] . empty ( ) )
return sigs2 ;
return sigs1 ;
case TX_SCRIPTHASH :
if ( sigs1 . empty ( ) | | sigs1 . back ( ) . empty ( ) )
return PushAll ( sigs2 ) ;
else if ( sigs2 . empty ( ) | | sigs2 . back ( ) . empty ( ) )
return PushAll ( sigs1 ) ;
if ( sigs1 . script . empty ( ) | | sigs1 . script . back ( ) . empty ( ) )
return sigs2 ;
else if ( sigs2 . script . empty ( ) | | sigs2 . script . back ( ) . empty ( ) )
return sigs1 ;
else
{
// Recur to combine:
valtype spk = sigs1 . back ( ) ;
valtype spk = sigs1 . script . back ( ) ;
CScript pubKey2 ( spk . begin ( ) , spk . end ( ) ) ;
txnouttype txType2 ;
vector < vector < unsigned char > > vSolutions2 ;
Solver ( pubKey2 , txType2 , vSolutions2 ) ;
sigs1 . pop_back ( ) ;
sigs2 . pop_back ( ) ;
CScript result = CombineSignatures ( pubKey2 , checker , txType2 , vSolutions2 , sigs1 , sigs2 ) ;
result < < spk ;
sigs1 . script . pop_back ( ) ;
sigs2 . script . pop_back ( ) ;
Stacks result = CombineSignatures ( pubKey2 , checker , txType2 , vSolutions2 , sigs1 , sigs2 , sigversion ) ;
result . script . push_back ( spk ) ;
return result ;
}
case TX_MULTISIG :
return CombineMultisig ( scriptPubKey , checker , vSolutions , sigs1 , sigs2 ) ;
return Stacks ( CombineMultisig ( scriptPubKey , checker , vSolutions , sigs1 . script , sigs2 . script , sigversion ) ) ;
case TX_WITNESS_V0_SCRIPTHASH :
if ( sigs1 . witness . empty ( ) | | sigs1 . witness . back ( ) . empty ( ) )
return sigs2 ;
else if ( sigs2 . witness . empty ( ) | | sigs2 . witness . back ( ) . empty ( ) )
return sigs1 ;
else
{
// Recur to combine:
CScript pubKey2 ( sigs1 . witness . back ( ) . begin ( ) , sigs1 . witness . back ( ) . end ( ) ) ;
txnouttype txType2 ;
vector < valtype > vSolutions2 ;
Solver ( pubKey2 , txType2 , vSolutions2 ) ;
sigs1 . witness . pop_back ( ) ;
sigs1 . script = sigs1 . witness ;
sigs1 . witness . clear ( ) ;
sigs2 . witness . pop_back ( ) ;
sigs2 . script = sigs2 . witness ;
sigs2 . witness . clear ( ) ;
Stacks result = CombineSignatures ( pubKey2 , checker , txType2 , vSolutions2 , sigs1 , sigs2 , SIGVERSION_WITNESS_V0 ) ;
result . witness = result . script ;
result . script . clear ( ) ;
result . witness . push_back ( valtype ( pubKey2 . begin ( ) , pubKey2 . end ( ) ) ) ;
return result ;
}
default :
return Stacks ( ) ;
}
return CScript ( ) ;
}
CScript CombineSignatures ( const CScript & scriptPubKey , const CTransaction & txTo , unsigned int nIn , const CAmount & amount ,
const CScript & scriptSig1 , const CScript & scriptSig2 )
{
TransactionSignatureChecker checker ( & txTo , nIn , amount ) ;
return CombineSignatures ( scriptPubKey , checker , scriptSig1 , scriptSig2 ) ;
}
CScript CombineSignatures ( const CScript & scriptPubKey , const BaseSignatureChecker & checker ,
const CScript & scriptSig1 , const CScript & scriptSig2 )
SignatureData CombineSignatures ( const CScript & scriptPubKey , const BaseSignatureChecker & checker ,
const SignatureData & scriptSig1 , const SignatureData & scriptSig2 )
{
txnouttype txType ;
vector < vector < unsigned char > > vSolutions ;
Solver ( scriptPubKey , txType , vSolutions ) ;
vector < valtype > stack1 ;
EvalScript ( stack1 , scriptSig1 , SCRIPT_VERIFY_STRICTENC , BaseSignatureChecker ( ) , SIGVERSION_BASE ) ;
vector < valtype > stack2 ;
EvalScript ( stack2 , scriptSig2 , SCRIPT_VERIFY_STRICTENC , BaseSignatureChecker ( ) , SIGVERSION_BASE ) ;
return CombineSignatures ( scriptPubKey , checker , txType , vSolutions , stack1 , stack2 ) ;
return CombineSignatures ( scriptPubKey , checker , txType , vSolutions , Stacks ( scriptSig1 ) , Stacks ( scriptSig2 ) , SIGVERSION_BASE ) . Output ( ) ;
}
namespace {
@ -297,7 +410,7 @@ const BaseSignatureChecker& DummySignatureCreator::Checker() const
@@ -297,7 +410,7 @@ const BaseSignatureChecker& DummySignatureCreator::Checker() const
return dummyChecker ;
}
bool DummySignatureCreator : : CreateSig ( std : : vector < unsigned char > & vchSig , const CKeyID & keyid , const CScript & scriptCode ) const
bool DummySignatureCreator : : CreateSig ( std : : vector < unsigned char > & vchSig , const CKeyID & keyid , const CScript & scriptCode , SigVersion sigversion ) const
{
// Create a dummy signature that is a valid DER-encoding
vchSig . assign ( 72 , ' \000 ' ) ;