mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 10:38:42 +01:00
BIP143: Signing logic
This commit is contained in:
parent
9757b57c25
commit
605e8473a7
@ -363,6 +363,18 @@ vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
|
||||
return ParseHexUV(o[strKey], strKey);
|
||||
}
|
||||
|
||||
static CAmount AmountFromValue(const UniValue& value)
|
||||
{
|
||||
if (!value.isNum() && !value.isStr())
|
||||
throw runtime_error("Amount is not a number or string");
|
||||
CAmount amount;
|
||||
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
|
||||
throw runtime_error("Invalid amount");
|
||||
if (!MoneyRange(amount))
|
||||
throw runtime_error("Amount out of range");
|
||||
return amount;
|
||||
}
|
||||
|
||||
static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
|
||||
{
|
||||
int nHashType = SIGHASH_ALL;
|
||||
@ -434,7 +446,10 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
|
||||
if ((unsigned int)nOut >= coins->vout.size())
|
||||
coins->vout.resize(nOut+1);
|
||||
coins->vout[nOut].scriptPubKey = scriptPubKey;
|
||||
coins->vout[nOut].nValue = 0; // we don't know the actual output value
|
||||
coins->vout[nOut].nValue = 0;
|
||||
if (prevOut.exists("amount")) {
|
||||
coins->vout[nOut].nValue = AmountFromValue(prevOut["amount"]);
|
||||
}
|
||||
}
|
||||
|
||||
// if redeemScript given and private keys given,
|
||||
@ -464,15 +479,16 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
|
||||
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
|
||||
const CAmount& amount = coins->vout[txin.prevout.n].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:
|
||||
BOOST_FOREACH(const CTransaction& txv, txVariants) {
|
||||
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, amount, txin.scriptSig, txv.vin[i].scriptSig);
|
||||
}
|
||||
BOOST_FOREACH(const CTransaction& txv, txVariants)
|
||||
sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i));
|
||||
UpdateTransaction(mergedTx, i, sigdata);
|
||||
|
||||
if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx.wit.vtxinwit.size() > i ? &mergedTx.wit.vtxinwit[i].scriptWitness : NULL, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount)))
|
||||
fComplete = false;
|
||||
}
|
||||
|
@ -592,7 +592,8 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
|
||||
" \"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"
|
||||
@ -735,7 +736,10 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
|
||||
if ((unsigned int)nOut >= coins->vout.size())
|
||||
coins->vout.resize(nOut+1);
|
||||
coins->vout[nOut].scriptPubKey = scriptPubKey;
|
||||
coins->vout[nOut].nValue = 0; // we don't know the actual output value
|
||||
coins->vout[nOut].nValue = 0;
|
||||
if (prevOut.exists("amount")) {
|
||||
coins->vout[nOut].nValue = AmountFromValue(find_value(prevOut, "amount"));
|
||||
}
|
||||
}
|
||||
|
||||
// if redeemScript given and not using the local wallet (private keys
|
||||
@ -801,15 +805,18 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
|
||||
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
|
||||
const CAmount& amount = coins->vout[txin.prevout.n].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:
|
||||
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
|
||||
txin.scriptSig = CombineSignatures(prevPubKey, txConst, i, amount, 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, mergedTx.wit.vtxinwit.size() > i ? &mergedTx.wit.vtxinwit[i].scriptWitness : NULL, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
|
||||
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
|
||||
|
@ -57,6 +57,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
||||
return ISMINE_SPENDABLE;
|
||||
break;
|
||||
case TX_PUBKEYHASH:
|
||||
case TX_WITNESS_V0_KEYHASH:
|
||||
keyID = CKeyID(uint160(vSolutions[0]));
|
||||
if (keystore.HaveKey(keyID))
|
||||
return ISMINE_SPENDABLE;
|
||||
@ -72,6 +73,20 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TX_WITNESS_V0_SCRIPTHASH:
|
||||
{
|
||||
uint160 hash;
|
||||
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin());
|
||||
CScriptID scriptID = CScriptID(hash);
|
||||
CScript subscript;
|
||||
if (keystore.GetCScript(scriptID, subscript)) {
|
||||
isminetype ret = IsMine(keystore, subscript);
|
||||
if (ret == ISMINE_SPENDABLE)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TX_MULTISIG:
|
||||
{
|
||||
// Only consider transactions "mine" if we own ALL the
|
||||
@ -88,8 +103,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;
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
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
|
||||
* 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();
|
||||
|
||||
vector<valtype> vSolutions;
|
||||
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
|
||||
@ -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);
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
// Test solution
|
||||
return VerifyScript(scriptSig, fromPubKey, NULL, 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 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, 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;
|
||||
sigdata.scriptWitness.stack.clear();
|
||||
|
||||
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 (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;
|
||||
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 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, 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
|
||||
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
|
||||
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
|
||||
}
|
||||
// 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;
|
||||
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 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.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_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
|
||||
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');
|
||||
|
@ -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. */
|
||||
@ -41,7 +41,14 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
|
||||
public:
|
||||
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);
|
||||
const BaseSignatureChecker& Checker() const { return checker; }
|
||||
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
|
||||
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const;
|
||||
};
|
||||
|
||||
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 signatyres. */
|
||||
@ -49,20 +56,29 @@ class DummySignatureCreator : public BaseSignatureCreator {
|
||||
public:
|
||||
DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
|
||||
const BaseSignatureChecker& Checker() const;
|
||||
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
|
||||
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const;
|
||||
};
|
||||
|
||||
struct SignatureData {
|
||||
CScript scriptSig;
|
||||
CScriptWitness scriptWitness;
|
||||
|
||||
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 CAmount& amount, 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
|
||||
|
@ -31,6 +31,8 @@ const char* GetTxnOutputType(txnouttype t)
|
||||
case TX_SCRIPTHASH: return "scripthash";
|
||||
case TX_MULTISIG: return "multisig";
|
||||
case TX_NULL_DATA: return "nulldata";
|
||||
case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
|
||||
case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -66,6 +68,22 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
||||
return true;
|
||||
}
|
||||
|
||||
int witnessversion;
|
||||
std::vector<unsigned char> witnessprogram;
|
||||
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
|
||||
if (witnessversion == 0 && witnessprogram.size() == 20) {
|
||||
typeRet = TX_WITNESS_V0_KEYHASH;
|
||||
vSolutionsRet.push_back(witnessprogram);
|
||||
return true;
|
||||
}
|
||||
if (witnessversion == 0 && witnessprogram.size() == 32) {
|
||||
typeRet = TX_WITNESS_V0_SCRIPTHASH;
|
||||
vSolutionsRet.push_back(witnessprogram);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Provably prunable, data-carrying output
|
||||
//
|
||||
// So long as script passes the IsUnspendable() test and all but the first
|
||||
@ -282,3 +300,26 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
|
||||
script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
|
||||
return script;
|
||||
}
|
||||
|
||||
CScript GetScriptForWitness(const CScript& redeemscript)
|
||||
{
|
||||
CScript ret;
|
||||
|
||||
txnouttype typ;
|
||||
std::vector<std::vector<unsigned char> > vSolutions;
|
||||
if (Solver(redeemscript, typ, vSolutions)) {
|
||||
if (typ == TX_PUBKEY) {
|
||||
unsigned char h160[20];
|
||||
CHash160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160);
|
||||
ret << OP_0 << std::vector<unsigned char>(&h160[0], &h160[20]);
|
||||
return ret;
|
||||
} else if (typ == TX_PUBKEYHASH) {
|
||||
ret << OP_0 << vSolutions[0];
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
uint256 hash;
|
||||
CSHA256().Write(&redeemscript[0], redeemscript.size()).Finalize(hash.begin());
|
||||
ret << OP_0 << ToByteVector(hash);
|
||||
return ret;
|
||||
}
|
||||
|
@ -51,6 +51,8 @@ enum txnouttype
|
||||
TX_SCRIPTHASH,
|
||||
TX_MULTISIG,
|
||||
TX_NULL_DATA,
|
||||
TX_WITNESS_V0_SCRIPTHASH,
|
||||
TX_WITNESS_V0_KEYHASH,
|
||||
};
|
||||
|
||||
class CNoDestination {
|
||||
@ -77,5 +79,6 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::
|
||||
CScript GetScriptForDestination(const CTxDestination& dest);
|
||||
CScript GetScriptForRawPubKey(const CPubKey& pubkey);
|
||||
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
|
||||
CScript GetScriptForWitness(const CScript& redeemscript);
|
||||
|
||||
#endif // BITCOIN_SCRIPT_STANDARD_H
|
||||
|
@ -148,7 +148,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(tx, i);
|
||||
}
|
||||
@ -168,7 +168,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++)
|
||||
|
@ -303,7 +303,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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "core_io.h"
|
||||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
#include "main.h"
|
||||
@ -102,7 +103,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:
|
||||
@ -197,7 +198,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));
|
||||
}
|
||||
}
|
||||
@ -326,9 +327,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:
|
||||
|
@ -152,16 +152,16 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, co
|
||||
flags |= SCRIPT_VERIFY_WITNESS;
|
||||
}
|
||||
ScriptError err;
|
||||
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey));
|
||||
CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
|
||||
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit);
|
||||
CMutableTransaction tx2 = tx;
|
||||
static const CAmount amountZero = 0;
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, NULL, flags, MutableTransactionSignatureChecker(&tx, 0, amountZero), &err) == expect, message);
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, NULL, 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);
|
||||
stream << tx2;
|
||||
if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
|
||||
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), amountZero, (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect, message);
|
||||
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), txCredit.vout[0].nValue, (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect, message);
|
||||
} else {
|
||||
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), 0, (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect, message);
|
||||
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(begin_ptr(scriptPubKey), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect,message);
|
||||
@ -896,7 +896,7 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
|
||||
BOOST_AUTO_TEST_CASE(script_combineSigs)
|
||||
{
|
||||
// Test the CombineSignatures function
|
||||
CAmount amount;
|
||||
CAmount amount = 0;
|
||||
CBasicKeyStore keystore;
|
||||
vector<CKey> keys;
|
||||
vector<CPubKey> pubkeys;
|
||||
@ -914,50 +914,50 @@ 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, amount, 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, amount, scriptSig, empty);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, amount, 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, amount, 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, amount, scriptSig, empty);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, amount, 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, amount, 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 << vector<unsigned char>(pkSingle.begin(), pkSingle.end());
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSigCopy, scriptSig);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, amount, scriptSig, scriptSigCopy);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
scriptSigCopy = CScript() << OP_0 << std::vector<unsigned char>(pkSingle.begin(), pkSingle.end());
|
||||
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, amount, scriptSig, empty);
|
||||
BOOST_CHECK(combined == scriptSig);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, amount, 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:
|
||||
vector<unsigned char> sig1;
|
||||
@ -985,22 +985,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, amount, partial1a, partial1b);
|
||||
BOOST_CHECK(combined == partial1a);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial1a, partial2a);
|
||||
BOOST_CHECK(combined == complete12);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial2a, partial1a);
|
||||
BOOST_CHECK(combined == complete12);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial1b, partial2b);
|
||||
BOOST_CHECK(combined == complete12);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial3b, partial1b);
|
||||
BOOST_CHECK(combined == complete13);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial2a, partial3a);
|
||||
BOOST_CHECK(combined == complete23);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, amount, partial3b, partial2b);
|
||||
BOOST_CHECK(combined == complete23);
|
||||
combined = CombineSignatures(scriptPubKey, txTo, 0, amount, 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)
|
||||
|
@ -2334,17 +2334,20 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
|
||||
{
|
||||
bool signSuccess;
|
||||
const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
|
||||
CScript& scriptSigRes = txNew.vin[nIn].scriptSig;
|
||||
SignatureData sigdata;
|
||||
if (sign)
|
||||
signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, scriptSigRes);
|
||||
signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata);
|
||||
else
|
||||
signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, scriptSigRes);
|
||||
signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata);
|
||||
|
||||
if (!signSuccess)
|
||||
{
|
||||
strFailReason = _("Signing transaction failed");
|
||||
return false;
|
||||
} else {
|
||||
UpdateTransaction(txNew, nIn, sigdata);
|
||||
}
|
||||
|
||||
nIn++;
|
||||
}
|
||||
|
||||
@ -2354,6 +2357,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
|
||||
if (!sign) {
|
||||
BOOST_FOREACH (CTxIn& vin, txNew.vin)
|
||||
vin.scriptSig = CScript();
|
||||
txNew.wit.SetNull();
|
||||
}
|
||||
|
||||
// Embed the constructed transaction data in wtxNew.
|
||||
|
Loading…
Reference in New Issue
Block a user