Merge pull request #3101 from codablock/pr_backports_v15_v16_1

Backport changes in TX verification/signing API
This commit is contained in:
UdjinM6 2019-09-22 23:44:41 +03:00 committed by GitHub
commit b12cd5fbd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 359 additions and 247 deletions

View File

@ -474,6 +474,18 @@ static bool findSighashFlags(int& flags, const std::string& flagStr)
return false;
}
static CAmount AmountFromValue(const UniValue& value)
{
if (!value.isNum() && !value.isStr())
throw std::runtime_error("Amount is not a number or string");
CAmount amount;
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
throw std::runtime_error("Invalid amount");
if (!MoneyRange(amount))
throw std::runtime_error("Amount out of range");
return amount;
}
static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
{
int nHashType = SIGHASH_ALL;
@ -548,6 +560,9 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
Coin newcoin;
newcoin.out.scriptPubKey = scriptPubKey;
newcoin.out.nValue = 0; // we don't know the actual output value
if (prevOut.exists("amount")) {
newcoin.out.nValue = AmountFromValue(prevOut["amount"]);
}
newcoin.nHeight = 1;
view.AddCoin(out, std::move(newcoin), true);
}
@ -577,17 +592,18 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
continue;
}
const CScript& prevPubKey = coin.out.scriptPubKey;
const CAmount& amount = coin.out.nValue;
txin.scriptSig.clear();
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size()))
SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata);
// ... and merge in other signatures:
for (const CTransaction& txv : txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i)))
for (const CTransaction& txv : txVariants)
sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i));
UpdateTransaction(mergedTx, i, sigdata);
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount)))
fComplete = false;
}

View File

@ -160,7 +160,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
std::vector<std::vector<unsigned char> > stack;
// convert the scriptSig into a stack, so we can inspect the redeemScript
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), 0))
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE))
return false;
if (stack.empty())
return false;

View File

@ -619,7 +619,8 @@ bool CPrivateSendClientSession::SignFinalTransaction(const CTransaction& finalTr
const CKeyStore& keystore = *vpwallets[0];
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SignFinalTransaction -- Signing my input %i\n", nMyInputIndex);
if (!SignSignature(keystore, prevPubKey, finalMutableTransaction, nMyInputIndex, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { // changes scriptSig
// TODO we're using amount=0 here but we should use the correct amount. This works because Dash ignores the amount while signing/verifying (only used in Bitcoin/Segwit)
if (!SignSignature(keystore, prevPubKey, finalMutableTransaction, nMyInputIndex, 0, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { // changes scriptSig
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SignFinalTransaction -- Unable to sign my own transaction!\n");
// not sure what to do here, it will timeout...?
}

View File

@ -605,7 +605,8 @@ bool CPrivateSendServer::IsInputScriptSigValid(const CTxIn& txin)
if (nTxInIndex >= 0) { //might have to do this one input at a time?
txNew.vin[nTxInIndex].scriptSig = txin.scriptSig;
LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::IsInputScriptSigValid -- verifying scriptSig %s\n", ScriptToAsmStr(txin.scriptSig).substr(0, 24));
if (!VerifyScript(txNew.vin[nTxInIndex].scriptSig, sigPubKey, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, MutableTransactionSignatureChecker(&txNew, nTxInIndex))) {
// TODO we're using amount=0 here but we should use the correct amount. This works because Dash ignores the amount while signing/verifying (only used in Bitcoin/Segwit)
if (!VerifyScript(txNew.vin[nTxInIndex].scriptSig, sigPubKey, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, MutableTransactionSignatureChecker(&txNew, nTxInIndex, 0))) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::IsInputScriptSigValid -- VerifyScript() failed on input %d\n", nTxInIndex);
return false;
}

View File

@ -611,7 +611,8 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
" \"txid\":\"id\", (string, required) The transaction id\n"
" \"vout\":n, (numeric, required) The output number\n"
" \"scriptPubKey\": \"hex\", (string, required) script key\n"
" \"redeemScript\": \"hex\" (string, required for P2SH) redeem script\n"
" \"redeemScript\": \"hex\", (string, required for P2SH) redeem script\n"
" \"amount\": value (numeric, required) The amount spent\n"
" }\n"
" ,...\n"
" ]\n"
@ -754,6 +755,9 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
Coin newcoin;
newcoin.out.scriptPubKey = scriptPubKey;
newcoin.out.nValue = 0;
if (prevOut.exists("amount")) {
newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount"));
}
newcoin.nHeight = 1;
view.AddCoin(out, std::move(newcoin), true);
}
@ -818,20 +822,24 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
continue;
}
const CScript& prevPubKey = coin.out.scriptPubKey;
const CAmount& amount = coin.out.nValue;
txin.scriptSig.clear();
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size()))
SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata);
// ... and merge in other signatures:
for (const CMutableTransaction& txv : txVariants) {
if (txv.vin.size() > i) {
txin.scriptSig = CombineSignatures(prevPubKey, txConst, i, txin.scriptSig, txv.vin[i].scriptSig);
sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
}
}
UpdateTransaction(mergedTx, i, sigdata);
ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i), &serror)) {
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
}
}

View File

@ -95,7 +95,8 @@ int dashconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int
set_error(err, dashconsensus_ERR_OK);
PrecomputedTransactionData txdata(tx);
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn, txdata), nullptr);
CAmount am(0);
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn, am, txdata), nullptr);
} catch (const std::exception&) {
return set_error(err, dashconsensus_ERR_TX_DESERIALIZE); // Error deserializing
}

View File

@ -6,6 +6,8 @@
#ifndef BITCOIN_BITCOINCONSENSUS_H
#define BITCOIN_BITCOINCONSENSUS_H
#include <stdint.h>
#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H)
#include "config/dash-config.h"
#if defined(_WIN32)

View File

@ -227,7 +227,7 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
return true;
}
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
{
static const CScriptNum bnZero(0);
static const CScriptNum bnOne(1);
@ -867,13 +867,15 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
CScript scriptCode(pbegincodehash, pend);
// Drop the signature, since there's no way for a signature to sign itself
scriptCode.FindAndDelete(CScript(vchSig));
if (sigversion == SIGVERSION_BASE) {
scriptCode.FindAndDelete(CScript(vchSig));
}
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
//serror is set
return false;
}
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode);
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size())
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
@ -929,7 +931,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
for (int k = 0; k < nSigsCount; k++)
{
valtype& vchSig = stacktop(-isig-k);
scriptCode.FindAndDelete(CScript(vchSig));
if (sigversion == SIGVERSION_BASE) {
scriptCode.FindAndDelete(CScript(vchSig));
}
}
bool fSuccess = true;
@ -947,7 +951,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
}
// Check signature
bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode);
bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
if (fOk) {
isig++;
@ -1150,7 +1154,7 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
hashOutputs = GetOutputsHash(txTo);
}
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const PrecomputedTransactionData* cache)
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
if (nIn >= txTo.vin.size()) {
@ -1180,7 +1184,7 @@ bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned cha
return pubkey.Verify(sighash, vchSig);
}
bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
@ -1193,7 +1197,7 @@ bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vch
int nHashType = vchSig.back();
vchSig.pop_back();
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, this->txdata);
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
if (!VerifySignature(vchSig, pubkey, sighash))
return false;
@ -1292,12 +1296,12 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
}
std::vector<std::vector<unsigned char> > stack, stackCopy;
if (!EvalScript(stack, scriptSig, flags, checker, serror))
if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror))
// serror is set
return false;
if (flags & SCRIPT_VERIFY_P2SH)
stackCopy = stack;
if (!EvalScript(stack, scriptPubKey, flags, checker, serror))
if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_BASE, serror))
// serror is set
return false;
if (stack.empty())
@ -1324,7 +1328,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
popstack(stack);
if (!EvalScript(stack, pubKey2, flags, checker, serror))
if (!EvalScript(stack, pubKey2, flags, checker, SIGVERSION_BASE, serror))
// serror is set
return false;
if (stack.empty())

View File

@ -101,12 +101,17 @@ struct PrecomputedTransactionData
PrecomputedTransactionData(const CTransaction& tx);
};
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const PrecomputedTransactionData* cache = nullptr);
enum SigVersion
{
SIGVERSION_BASE = 0,
};
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
class BaseSignatureChecker
{
public:
virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
return false;
}
@ -129,15 +134,16 @@ class TransactionSignatureChecker : public BaseSignatureChecker
private:
const CTransaction* txTo;
unsigned int nIn;
const CAmount amount;
const PrecomputedTransactionData* txdata;
protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn), txdata(nullptr) {}
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), txdata(&txdataIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const override;
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
bool CheckLockTime(const CScriptNum& nLockTime) const override;
bool CheckSequence(const CScriptNum& nSequence) const override;
};
@ -148,10 +154,10 @@ private:
const CTransaction txTo;
public:
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn) : TransactionSignatureChecker(&txTo, nInIn), txTo(*txToIn) {}
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
};
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = nullptr);
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = nullptr);
#endif // BITCOIN_SCRIPT_INTERPRETER_H

View File

@ -85,8 +85,8 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
if (keystore.HaveWatchOnly(scriptPubKey)) {
// TODO: This could be optimized some by doing some work after the above solver
CScript scriptSig;
return ProduceSignature(DummySignatureCreator(&keystore), scriptPubKey, scriptSig) ? ISMINE_WATCH_SOLVABLE : ISMINE_WATCH_UNSOLVABLE;
SignatureData sigs;
return ProduceSignature(DummySignatureCreator(&keystore), scriptPubKey, sigs) ? ISMINE_WATCH_SOLVABLE : ISMINE_WATCH_UNSOLVABLE;
}
return ISMINE_NO;
}

View File

@ -46,7 +46,7 @@ private:
bool store;
public:
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, PrecomputedTransactionData& txdataIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn, txdataIn), store(storeIn) {}
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, PrecomputedTransactionData& txdataIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {}
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const override;
};

View File

@ -15,31 +15,31 @@
typedef std::vector<unsigned char> valtype;
TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn) {}
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);
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)
{
std::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 std::vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
static bool SignN(const std::vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
{
int nSigned = 0;
int nRequired = multisigdata.front()[0];
@ -47,7 +47,7 @@ static bool SignN(const std::vector<valtype>& multisigdata, const BaseSignatureC
{
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;
@ -60,9 +60,11 @@ static bool SignN(const std::vector<valtype>& multisigdata, const BaseSignatureC
* Returns false if scriptPubKey could not be completely satisfied.
*/
static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,
CScript& scriptSigRet, txnouttype& whichTypeRet)
std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion)
{
scriptSigRet.clear();
CScript scriptRet;
uint160 h160;
ret.clear();
std::vector<valtype> vSolutions;
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
@ -76,62 +78,103 @@ 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);
case TX_MULTISIG:
scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
return (SignN(vSolutions, creator, scriptPubKey, scriptSigRet));
}
return false;
}
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, CScript& scriptSig)
{
txnouttype whichType;
if (!SignStep(creator, fromPubKey, scriptSig, whichType))
if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) {
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
return true;
}
return false;
if (whichType == TX_SCRIPTHASH)
{
// Solver returns the subscript that need to be evaluated;
// the final scriptSig is the signatures from that
// and then the serialized subscript:
CScript subscript = scriptSig;
case TX_MULTISIG:
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
return (SignN(vSolutions, creator, scriptPubKey, ret, sigversion));
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;
default:
return false;
}
// Test solution
return VerifyScript(scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
}
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
static CScript PushAll(const std::vector<valtype>& values)
{
CScript result;
for(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, SignatureData& sigdata)
{
CScript script = fromPubKey;
bool solved = true;
std::vector<valtype> result;
txnouttype whichType;
solved = SignStep(creator, script, result, whichType, SIGVERSION_BASE);
bool P2SH = false;
CScript subscript;
if (solved && whichType == TX_SCRIPTHASH)
{
// Solver returns the subscript that needs to be evaluated;
// the final scriptSig is the signatures from that
// and then the serialized subscript:
script = subscript = CScript(result[0].begin(), result[0].end());
solved = solved && SignStep(creator, script, result, whichType, SIGVERSION_BASE) && whichType != TX_SCRIPTHASH;
P2SH = true;
}
if (P2SH) {
result.push_back(std::vector<unsigned char>(subscript.begin(), subscript.end()));
}
sigdata.scriptSig = PushAll(result);
// Test solution
return solved && VerifyScript(sigdata.scriptSig, fromPubKey, 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;
return data;
}
void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data)
{
assert(tx.vin.size() > nIn);
tx.vin[nIn].scriptSig = data.scriptSig;
}
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)
@ -141,20 +184,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 std::vector<valtype>& values)
{
CScript result;
for (const valtype& v : values)
result << v;
return result;
}
static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
static std::vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const std::vector<valtype>& vSolutions,
const std::vector<valtype>& sigs1, const std::vector<valtype>& sigs2)
const std::vector<valtype>& sigs1, const std::vector<valtype>& sigs2, SigVersion sigversion)
{
// Combine all the signatures we've got:
std::set<valtype> allsigs;
@ -182,7 +217,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))
if (checker.CheckSig(sig, pubkey, scriptPubKey, sigversion))
{
sigs[pubkey] = sig;
break;
@ -191,87 +226,95 @@ 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;
}
static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
namespace
{
struct Stacks
{
std::vector<valtype> script;
Stacks() {}
explicit Stacks(const std::vector<valtype>& scriptSigStack_) : script(scriptSigStack_) {}
explicit Stacks(const SignatureData& data) {
EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE);
}
SignatureData Output() const {
SignatureData result;
result.scriptSig = PushAll(script);
return result;
}
};
}
static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const txnouttype txType, const std::vector<valtype>& vSolutions,
std::vector<valtype>& sigs1, std::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.size() >= 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_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;
std::vector<std::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));
default:
return Stacks();
}
return CScript();
}
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
const CScript& scriptSig1, const CScript& scriptSig2)
{
TransactionSignatureChecker checker(&txTo, nIn);
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;
std::vector<std::vector<unsigned char> > vSolutions;
Solver(scriptPubKey, txType, vSolutions);
std::vector<valtype> stack1;
EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
std::vector<valtype> stack2;
EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output();
}
namespace {
@ -281,7 +324,7 @@ class DummySignatureChecker : public BaseSignatureChecker
public:
DummySignatureChecker() {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const override
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
{
return true;
}
@ -294,7 +337,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');

View File

@ -27,7 +27,7 @@ public:
virtual const BaseSignatureChecker& Checker() const =0;
/** Create a singular (non-script) signature. */
virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const =0;
virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0;
};
/** A signature creator for transactions. */
@ -35,12 +35,20 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
const CTransaction* txTo;
unsigned int nIn;
int nHashType;
CAmount amount;
const TransactionSignatureChecker checker;
public:
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn=SIGHASH_ALL);
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);
const BaseSignatureChecker& Checker() const override{ return checker; }
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const override;
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
};
class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
CTransaction tx;
public:
MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {}
};
/** A signature creator that just produces 72-byte empty signatures. */
@ -48,20 +56,28 @@ class DummySignatureCreator : public BaseSignatureCreator {
public:
DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
const BaseSignatureChecker& Checker() const override;
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const override;
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
};
struct SignatureData {
CScript scriptSig;
SignatureData() {}
explicit SignatureData(const CScript& script) : scriptSig(script) {}
};
/** Produce a script signature using a generic signature creator. */
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig);
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata);
/** Produce a script signature for a transaction. */
bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType);
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */
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);
/** Combine two script signatures on transactions. */
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
/** Extract signature data from a transaction, and insert it. */
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn);
void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data);
#endif // BITCOIN_SCRIPT_SIGN_H

View File

@ -166,7 +166,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
SignSignature(keystore, *txPrev, tx, 0);
SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL);
AddOrphanTx(MakeTransactionRef(tx), i);
}
@ -186,7 +186,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
tx.vin[j].prevout.n = j;
tx.vin[j].prevout.hash = txPrev->GetHash();
}
SignSignature(keystore, *txPrev, tx, 0);
SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL);
// Re-use same signature for other inputs
// (they don't have to be valid for this test)
for (unsigned int j = 1; j < tx.vin.size(); j++)

View File

@ -86,7 +86,7 @@ static void SignTransaction(CMutableTransaction& tx, const CKey& coinbaseKey)
CTransactionRef txFrom;
uint256 hashBlock;
BOOST_ASSERT(GetTransaction(tx.vin[i].prevout.hash, txFrom, Params().GetConsensus(), hashBlock));
BOOST_ASSERT(SignSignature(tempKeystore, *txFrom, tx, i));
BOOST_ASSERT(SignSignature(tempKeystore, *txFrom, tx, i, SIGHASH_ALL));
}
}
@ -231,7 +231,8 @@ static bool CheckTransactionSignature(const CMutableTransaction& tx)
uint256 hashBlock;
BOOST_ASSERT(GetTransaction(txin.prevout.hash, txFrom, Params().GetConsensus(), hashBlock));
if (!VerifyScript(txin.scriptSig, txFrom->vout[txin.prevout.n].scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&tx, i))) {
CAmount amount = txFrom->vout[txin.prevout.n].nValue;
if (!VerifyScript(txin.scriptSig, txFrom->vout[txin.prevout.n].scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&tx, i, amount))) {
return false;
}
}

View File

@ -23,7 +23,7 @@ BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
CScript
sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction, int whichIn)
{
uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL);
uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SIGVERSION_BASE);
CScript result;
result << OP_0; // CHECKMULTISIG bug workaround
@ -43,6 +43,7 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
ScriptError err;
CKey key[4];
CAmount amount = 0;
for (int i = 0; i < 4; i++)
key[i].MakeNewKey(true);
@ -78,20 +79,20 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys.assign(1,key[0]);
keys.push_back(key[1]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err));
BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
for (int i = 0; i < 4; i++)
{
keys.assign(1,key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err), strprintf("a&b 1: %d", i));
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 1: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
keys.assign(1,key[1]);
keys.push_back(key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err), strprintf("a&b 2: %d", i));
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 2: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
@ -102,18 +103,18 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
s = sign_multisig(a_or_b, keys, txTo[1], 0);
if (i == 0 || i == 1)
{
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
else
{
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
}
s.clear();
s << OP_0 << OP_1;
BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err));
BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
@ -125,12 +126,12 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
s = sign_multisig(escrow, keys, txTo[2], 0);
if (i < j && i < 3 && j < 3)
{
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0), &err), strprintf("escrow 1: %d %d", i, j));
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 1: %d %d", i, j));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
else
{
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0), &err), strprintf("escrow 2: %d %d", i, j));
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 2: %d %d", i, j));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
}
@ -299,7 +300,7 @@ BOOST_AUTO_TEST_CASE(multisig_Sign)
for (int i = 0; i < 3; i++)
{
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i));
}
}

View File

@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "consensus/tx_verify.h"
#include "core_io.h"
#include "key.h"
#include "keystore.h"
#include "validation.h"
@ -41,7 +42,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
txTo.vin[0].scriptSig = scriptSig;
txTo.vout[0].nValue = 1;
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &err);
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), &err);
}
@ -101,7 +102,7 @@ BOOST_AUTO_TEST_CASE(sign)
}
for (int i = 0; i < 8; i++)
{
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i));
}
// All of the above should be OK, and the txTos have valid signatures
// Check to make sure signature verification fails if we use the wrong ScriptSig:
@ -199,7 +200,7 @@ BOOST_AUTO_TEST_CASE(set)
}
for (int i = 0; i < 4; i++)
{
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i));
BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i));
}
}
@ -328,9 +329,9 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vin[i].prevout.n = i;
txTo.vin[i].prevout.hash = txFrom.GetHash();
}
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1, SIGHASH_ALL));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2, SIGHASH_ALL));
// SignSignature doesn't know how to sign these. We're
// not testing validating signatures, so just create
// dummy signatures that DO include the correct P2SH scripts:

View File

@ -146,9 +146,10 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, co
{
bool expect = (scriptError == SCRIPT_ERR_OK);
ScriptError err;
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey));
CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit);
CMutableTransaction tx2 = tx;
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0), &err) == expect, message);
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message);
BOOST_CHECK_MESSAGE(err == scriptError, std::string(FormatScriptError(err)) + " where " + std::string(FormatScriptError((ScriptError_t)scriptError)) + " expected: " + message);
#if defined(HAVE_CONSENSUS_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
@ -307,7 +308,7 @@ public:
TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32)
{
uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType);
uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType, 0, SIGVERSION_BASE);
std::vector<unsigned char> vchSig, r, s;
uint32_t iter = 0;
do {
@ -734,21 +735,21 @@ BOOST_AUTO_TEST_CASE(script_PushData)
ScriptError err;
std::vector<std::vector<unsigned char> > directStack;
BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err));
BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
std::vector<std::vector<unsigned char> > pushdata1Stack;
BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err));
BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err));
BOOST_CHECK(pushdata1Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
std::vector<std::vector<unsigned char> > pushdata2Stack;
BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err));
BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err));
BOOST_CHECK(pushdata2Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
std::vector<std::vector<unsigned char> > pushdata4Stack;
BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err));
BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err));
BOOST_CHECK(pushdata4Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
@ -756,7 +757,7 @@ BOOST_AUTO_TEST_CASE(script_PushData)
CScript
sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction)
{
uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL);
uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SIGVERSION_BASE);
CScript result;
//
@ -800,18 +801,18 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
txTo12.vout[0].nValue = 2;
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
@ -833,60 +834,61 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
std::vector<CKey> keys;
keys.push_back(key1); keys.push_back(key2);
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear();
keys.push_back(key1); keys.push_back(key3);
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear();
keys.push_back(key2); keys.push_back(key3);
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear();
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear();
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear();
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear();
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear();
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); // Must have signatures
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
}
BOOST_AUTO_TEST_CASE(script_combineSigs)
{
// Test the CombineSignatures function
CAmount amount;
CBasicKeyStore keystore;
std::vector<CKey> keys;
std::vector<CPubKey> pubkeys;
@ -904,62 +906,62 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
CScript& scriptSig = txTo.vin[0].scriptSig;
CScript empty;
CScript combined = CombineSignatures(scriptPubKey, txTo, 0, empty, empty);
BOOST_CHECK(combined.empty());
SignatureData empty;
SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty);
BOOST_CHECK(combined.scriptSig.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);
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); // changes scriptSig
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
BOOST_CHECK(combined.scriptSig == scriptSig);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
BOOST_CHECK(combined.scriptSig == 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);
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
// P2SH, single-signature case:
CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;
keystore.AddCScript(pkSingle);
scriptPubKey = GetScriptForDestination(CScriptID(pkSingle));
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);
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
BOOST_CHECK(combined.scriptSig == scriptSig);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
BOOST_CHECK(combined.scriptSig == scriptSig);
scriptSigCopy = scriptSig;
SignSignature(keystore, txFrom, txTo, 0);
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig);
BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig);
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
// dummy scriptSigCopy with placeholder, should always choose non-placeholder:
scriptSigCopy = CScript() << OP_0 << std::vector<unsigned char>(pkSingle.begin(), pkSingle.end());
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig);
BOOST_CHECK(combined == scriptSig);
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, scriptSigCopy);
BOOST_CHECK(combined == scriptSig);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
BOOST_CHECK(combined.scriptSig == scriptSig);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy));
BOOST_CHECK(combined.scriptSig == scriptSig);
// Hardest case: Multisig 2-of-3
scriptPubKey = GetScriptForMultisig(2, pubkeys);
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);
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
BOOST_CHECK(combined.scriptSig == scriptSig);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
BOOST_CHECK(combined.scriptSig == scriptSig);
// A couple of partially-signed versions:
std::vector<unsigned char> sig1;
uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL);
uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, SIGVERSION_BASE);
BOOST_CHECK(keys[0].Sign(hash1, sig1));
sig1.push_back(SIGHASH_ALL);
std::vector<unsigned char> sig2;
uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE);
uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SIGVERSION_BASE);
BOOST_CHECK(keys[1].Sign(hash2, sig2));
sig2.push_back(SIGHASH_NONE);
std::vector<unsigned char> sig3;
uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE);
uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SIGVERSION_BASE);
BOOST_CHECK(keys[2].Sign(hash3, sig3));
sig3.push_back(SIGHASH_SINGLE);
@ -975,22 +977,22 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
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);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b));
BOOST_CHECK(combined.scriptSig == partial1a);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a));
BOOST_CHECK(combined.scriptSig == complete12);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a));
BOOST_CHECK(combined.scriptSig == complete12);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b));
BOOST_CHECK(combined.scriptSig == complete12);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b));
BOOST_CHECK(combined.scriptSig == complete13);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a));
BOOST_CHECK(combined.scriptSig == complete23);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b));
BOOST_CHECK(combined.scriptSig == complete23);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a));
BOOST_CHECK(combined.scriptSig == partial3c);
}
BOOST_AUTO_TEST_CASE(script_standard_push)

View File

@ -140,7 +140,7 @@ BOOST_AUTO_TEST_CASE(sighash_test)
uint256 sh, sho;
sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType);
sh = SignatureHash(scriptCode, txTo, nIn, nHashType);
sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, SIGVERSION_BASE);
#if defined(PRINT_SIGHASH_JSON)
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << txTo;
@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
continue;
}
sh = SignatureHash(scriptCode, *tx, nIn, nHashType);
sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, SIGVERSION_BASE);
BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest);
}
}

View File

@ -149,9 +149,10 @@ BOOST_AUTO_TEST_CASE(tx_valid)
break;
}
CAmount amount = 0;
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
verify_flags, TransactionSignatureChecker(&tx, i, txdata), &err),
verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err),
strTest);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
@ -226,8 +227,9 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
}
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
CAmount amount = 0;
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
verify_flags, TransactionSignatureChecker(&tx, i, txdata), &err);
verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err);
}
BOOST_CHECK_MESSAGE(!fValid, strTest);
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));

View File

@ -55,7 +55,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
// Sign:
std::vector<unsigned char> vchSig;
uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL);
uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, 0, SIGVERSION_BASE);
BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
vchSig.push_back((unsigned char)SIGHASH_ALL);
spends[i].vin[0].scriptSig << vchSig;
@ -179,7 +179,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
// Sign, with a non-DER signature
{
std::vector<unsigned char> vchSig;
uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, SIGHASH_ALL);
uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, SIGHASH_ALL, 0, SIGVERSION_BASE);
BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
vchSig.push_back((unsigned char) 0); // padding byte makes this non-DER
vchSig.push_back((unsigned char)SIGHASH_ALL);
@ -251,7 +251,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
// Sign
std::vector<unsigned char> vchSig;
uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL);
uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL, 0, SIGVERSION_BASE);
BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
vchSig.push_back((unsigned char)SIGHASH_ALL);
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
@ -279,7 +279,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
// Sign
std::vector<unsigned char> vchSig;
uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL);
uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL, 0, SIGVERSION_BASE);
BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
vchSig.push_back((unsigned char)SIGHASH_ALL);
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101;

View File

@ -1234,7 +1234,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
PrecomputedTransactionData txdata(*ptxTo);
return VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, txdata, cacheStore), &error);
return VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, txdata, cacheStore), &error);
}
int GetSpendHeight(const CCoinsViewCache& inputs)

View File

@ -367,6 +367,7 @@ class CScriptCheck
{
private:
CScript scriptPubKey;
CAmount amount;
const CTransaction *ptxTo;
unsigned int nIn;
unsigned int nFlags;
@ -375,9 +376,9 @@ private:
PrecomputedTransactionData *txdata;
public:
CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
CScriptCheck(const CScript& scriptPubKeyIn, const CAmount amountIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
scriptPubKey(scriptPubKeyIn),
scriptPubKey(scriptPubKeyIn), amount(amountIn),
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
bool operator()();
@ -385,6 +386,7 @@ public:
void swap(CScriptCheck &check) {
scriptPubKey.swap(check.scriptPubKey);
std::swap(ptxTo, check.ptxTo);
std::swap(amount, check.amount);
std::swap(nIn, check.nIn);
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);

View File

@ -3545,7 +3545,7 @@ bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std
txCollateral.vout.push_back(CTxOut(0, CScript() << OP_RETURN));
}
if (!SignSignature(*this, txdsinCollateral.prevPubKey, txCollateral, 0)) {
if (!SignSignature(*this, txdsinCollateral.prevPubKey, txCollateral, 0, nValue, SIGHASH_ALL)) {
strReason = "Unable to sign collateral transaction!";
return false;
}
@ -3855,12 +3855,15 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
for (const auto& txdsin : vecTxDSInTmp)
{
const CScript& scriptPubKey = txdsin.prevPubKey;
CScript& scriptSigRes = txNew.vin[nIn].scriptSig;
if (!ProduceSignature(DummySignatureCreator(this), scriptPubKey, scriptSigRes))
SignatureData sigdata;
if (!ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata))
{
strFailReason = _("Signing transaction failed");
return false;
} else {
UpdateTransaction(txNew, nIn, sigdata);
}
nIn++;
}
@ -3963,12 +3966,14 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
for(const auto& txdsin : vecTxDSInTmp)
{
const CScript& scriptPubKey = txdsin.prevPubKey;
CScript& scriptSigRes = txNew.vin[nIn].scriptSig;
SignatureData sigdata;
if (!ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, scriptSigRes))
if (!ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, sigdata))
{
strFailReason = _("Signing transaction failed");
return false;
} else {
UpdateTransaction(txNew, nIn, sigdata);
}
nIn++;