Separate script/sign
This commit is contained in:
parent
9294a4bbe7
commit
e088d65acb
12 changed files with 294 additions and 263 deletions
|
@ -101,6 +101,7 @@ BITCOIN_CORE_H = \
|
||||||
script/interpreter.h \
|
script/interpreter.h \
|
||||||
script/compressor.h \
|
script/compressor.h \
|
||||||
script/script.h \
|
script/script.h \
|
||||||
|
script/sign.h \
|
||||||
script/standard.h \
|
script/standard.h \
|
||||||
scriptutils.h \
|
scriptutils.h \
|
||||||
serialize.h \
|
serialize.h \
|
||||||
|
@ -213,6 +214,7 @@ libbitcoin_common_a_SOURCES = \
|
||||||
script/interpreter.cpp \
|
script/interpreter.cpp \
|
||||||
script/compressor.cpp \
|
script/compressor.cpp \
|
||||||
script/script.cpp \
|
script/script.cpp \
|
||||||
|
script/sign.cpp \
|
||||||
script/standard.cpp \
|
script/standard.cpp \
|
||||||
scriptutils.cpp \
|
scriptutils.cpp \
|
||||||
$(BITCOIN_CORE_H)
|
$(BITCOIN_CORE_H)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "main.h" // for MAX_BLOCK_SIZE
|
#include "main.h" // for MAX_BLOCK_SIZE
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "scriptutils.h"
|
#include "script/sign.h"
|
||||||
#include "ui_interface.h" // for _(...)
|
#include "ui_interface.h" // for _(...)
|
||||||
#include "univalue/univalue.h"
|
#include "univalue/univalue.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "rpcserver.h"
|
#include "rpcserver.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "script/standard.h"
|
#include "script/standard.h"
|
||||||
|
#include "script/sign.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
#include "wallet.h"
|
#include "wallet.h"
|
||||||
|
|
260
src/script/sign.cpp
Normal file
260
src/script/sign.cpp
Normal file
|
@ -0,0 +1,260 @@
|
||||||
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
|
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "script/sign.h"
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
|
#include "key.h"
|
||||||
|
#include "keystore.h"
|
||||||
|
#include "script/standard.h"
|
||||||
|
#include "uint256.h"
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
typedef vector<unsigned char> valtype;
|
||||||
|
|
||||||
|
bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
|
||||||
|
{
|
||||||
|
CKey key;
|
||||||
|
if (!keystore.GetKey(address, key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
vector<unsigned char> vchSig;
|
||||||
|
if (!key.Sign(hash, vchSig))
|
||||||
|
return false;
|
||||||
|
vchSig.push_back((unsigned char)nHashType);
|
||||||
|
scriptSigRet << vchSig;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
|
||||||
|
{
|
||||||
|
int nSigned = 0;
|
||||||
|
int nRequired = multisigdata.front()[0];
|
||||||
|
for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
|
||||||
|
{
|
||||||
|
const valtype& pubkey = multisigdata[i];
|
||||||
|
CKeyID keyID = CPubKey(pubkey).GetID();
|
||||||
|
if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
||||||
|
++nSigned;
|
||||||
|
}
|
||||||
|
return nSigned==nRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
|
||||||
|
// Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
|
||||||
|
// unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
|
||||||
|
// Returns false if scriptPubKey could not be completely satisfied.
|
||||||
|
//
|
||||||
|
bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType,
|
||||||
|
CScript& scriptSigRet, txnouttype& whichTypeRet)
|
||||||
|
{
|
||||||
|
scriptSigRet.clear();
|
||||||
|
|
||||||
|
vector<valtype> vSolutions;
|
||||||
|
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CKeyID keyID;
|
||||||
|
switch (whichTypeRet)
|
||||||
|
{
|
||||||
|
case TX_NONSTANDARD:
|
||||||
|
case TX_NULL_DATA:
|
||||||
|
return false;
|
||||||
|
case TX_PUBKEY:
|
||||||
|
keyID = CPubKey(vSolutions[0]).GetID();
|
||||||
|
return Sign1(keyID, keystore, hash, nHashType, scriptSigRet);
|
||||||
|
case TX_PUBKEYHASH:
|
||||||
|
keyID = CKeyID(uint160(vSolutions[0]));
|
||||||
|
if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CPubKey vch;
|
||||||
|
keystore.GetPubKey(keyID, vch);
|
||||||
|
scriptSigRet << vch;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case TX_SCRIPTHASH:
|
||||||
|
return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet);
|
||||||
|
|
||||||
|
case TX_MULTISIG:
|
||||||
|
scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
|
||||||
|
return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
||||||
|
{
|
||||||
|
assert(nIn < txTo.vin.size());
|
||||||
|
CTxIn& txin = txTo.vin[nIn];
|
||||||
|
|
||||||
|
// Leave out the signature from the hash, since a signature can't sign itself.
|
||||||
|
// The checksig op will also drop the signatures from its hash.
|
||||||
|
uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType);
|
||||||
|
|
||||||
|
txnouttype whichType;
|
||||||
|
if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType))
|
||||||
|
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 = txin.scriptSig;
|
||||||
|
|
||||||
|
// Recompute txn hash using subscript in place of scriptPubKey:
|
||||||
|
uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType);
|
||||||
|
|
||||||
|
txnouttype subType;
|
||||||
|
bool fSolved =
|
||||||
|
Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH;
|
||||||
|
// Append serialized subscript whether or not it is completely signed:
|
||||||
|
txin.scriptSig << static_cast<valtype>(subscript);
|
||||||
|
if (!fSolved) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test solution
|
||||||
|
return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
||||||
|
{
|
||||||
|
assert(nIn < txTo.vin.size());
|
||||||
|
CTxIn& txin = txTo.vin[nIn];
|
||||||
|
assert(txin.prevout.n < txFrom.vout.size());
|
||||||
|
const CTxOut& txout = txFrom.vout[txin.prevout.n];
|
||||||
|
|
||||||
|
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CScript PushAll(const vector<valtype>& values)
|
||||||
|
{
|
||||||
|
CScript result;
|
||||||
|
BOOST_FOREACH(const valtype& v, values)
|
||||||
|
result << v;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn,
|
||||||
|
const vector<valtype>& vSolutions,
|
||||||
|
vector<valtype>& sigs1, vector<valtype>& sigs2)
|
||||||
|
{
|
||||||
|
// Combine all the signatures we've got:
|
||||||
|
set<valtype> allsigs;
|
||||||
|
BOOST_FOREACH(const valtype& v, sigs1)
|
||||||
|
{
|
||||||
|
if (!v.empty())
|
||||||
|
allsigs.insert(v);
|
||||||
|
}
|
||||||
|
BOOST_FOREACH(const valtype& v, sigs2)
|
||||||
|
{
|
||||||
|
if (!v.empty())
|
||||||
|
allsigs.insert(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a map of pubkey -> signature by matching sigs to pubkeys:
|
||||||
|
assert(vSolutions.size() > 1);
|
||||||
|
unsigned int nSigsRequired = vSolutions.front()[0];
|
||||||
|
unsigned int nPubKeys = vSolutions.size()-2;
|
||||||
|
map<valtype, valtype> sigs;
|
||||||
|
BOOST_FOREACH(const valtype& sig, allsigs)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < nPubKeys; i++)
|
||||||
|
{
|
||||||
|
const valtype& pubkey = vSolutions[i+1];
|
||||||
|
if (sigs.count(pubkey))
|
||||||
|
continue; // Already got a sig for this pubkey
|
||||||
|
|
||||||
|
if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0, 0))
|
||||||
|
{
|
||||||
|
sigs[pubkey] = sig;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now build a merged CScript:
|
||||||
|
unsigned int nSigsHave = 0;
|
||||||
|
CScript result; result << OP_0; // 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]];
|
||||||
|
++nSigsHave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fill any missing with OP_0:
|
||||||
|
for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
|
||||||
|
result << OP_0;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||||
|
const txnouttype txType, const vector<valtype>& vSolutions,
|
||||||
|
vector<valtype>& sigs1, vector<valtype>& sigs2)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
case TX_SCRIPTHASH:
|
||||||
|
if (sigs1.empty() || sigs1.back().empty())
|
||||||
|
return PushAll(sigs2);
|
||||||
|
else if (sigs2.empty() || sigs2.back().empty())
|
||||||
|
return PushAll(sigs1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Recur to combine:
|
||||||
|
valtype spk = sigs1.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, txTo, nIn, txType2, vSolutions2, sigs1, sigs2);
|
||||||
|
result << spk;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
case TX_MULTISIG:
|
||||||
|
return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||||
|
const CScript& scriptSig1, const CScript& scriptSig2)
|
||||||
|
{
|
||||||
|
txnouttype txType;
|
||||||
|
vector<vector<unsigned char> > vSolutions;
|
||||||
|
Solver(scriptPubKey, txType, vSolutions);
|
||||||
|
|
||||||
|
vector<valtype> stack1;
|
||||||
|
EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
|
||||||
|
vector<valtype> stack2;
|
||||||
|
EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
|
||||||
|
|
||||||
|
return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
|
||||||
|
}
|
23
src/script/sign.h
Normal file
23
src/script/sign.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
|
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef H_BITCOIN_SCRIPT_SIGN
|
||||||
|
#define H_BITCOIN_SCRIPT_SIGN
|
||||||
|
|
||||||
|
#include "script/interpreter.h"
|
||||||
|
|
||||||
|
class CKeyStore;
|
||||||
|
class CScript;
|
||||||
|
class CTransaction;
|
||||||
|
struct CMutableTransaction;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
|
||||||
|
// combine them intelligently and return the result.
|
||||||
|
CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
|
||||||
|
|
||||||
|
#endif
|
|
@ -5,11 +5,9 @@
|
||||||
|
|
||||||
#include "scriptutils.h"
|
#include "scriptutils.h"
|
||||||
|
|
||||||
#include "core.h"
|
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "uint256.h"
|
#include "script/standard.h"
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
|
@ -17,80 +15,6 @@ using namespace std;
|
||||||
|
|
||||||
typedef vector<unsigned char> valtype;
|
typedef vector<unsigned char> valtype;
|
||||||
|
|
||||||
bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
|
|
||||||
{
|
|
||||||
CKey key;
|
|
||||||
if (!keystore.GetKey(address, key))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
vector<unsigned char> vchSig;
|
|
||||||
if (!key.Sign(hash, vchSig))
|
|
||||||
return false;
|
|
||||||
vchSig.push_back((unsigned char)nHashType);
|
|
||||||
scriptSigRet << vchSig;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
|
|
||||||
{
|
|
||||||
int nSigned = 0;
|
|
||||||
int nRequired = multisigdata.front()[0];
|
|
||||||
for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
|
|
||||||
{
|
|
||||||
const valtype& pubkey = multisigdata[i];
|
|
||||||
CKeyID keyID = CPubKey(pubkey).GetID();
|
|
||||||
if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
|
||||||
++nSigned;
|
|
||||||
}
|
|
||||||
return nSigned==nRequired;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
|
|
||||||
// Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
|
|
||||||
// unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
|
|
||||||
// Returns false if scriptPubKey could not be completely satisfied.
|
|
||||||
//
|
|
||||||
bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType,
|
|
||||||
CScript& scriptSigRet, txnouttype& whichTypeRet)
|
|
||||||
{
|
|
||||||
scriptSigRet.clear();
|
|
||||||
|
|
||||||
vector<valtype> vSolutions;
|
|
||||||
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
CKeyID keyID;
|
|
||||||
switch (whichTypeRet)
|
|
||||||
{
|
|
||||||
case TX_NONSTANDARD:
|
|
||||||
case TX_NULL_DATA:
|
|
||||||
return false;
|
|
||||||
case TX_PUBKEY:
|
|
||||||
keyID = CPubKey(vSolutions[0]).GetID();
|
|
||||||
return Sign1(keyID, keystore, hash, nHashType, scriptSigRet);
|
|
||||||
case TX_PUBKEYHASH:
|
|
||||||
keyID = CKeyID(uint160(vSolutions[0]));
|
|
||||||
if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CPubKey vch;
|
|
||||||
keystore.GetPubKey(keyID, vch);
|
|
||||||
scriptSigRet << vch;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
case TX_SCRIPTHASH:
|
|
||||||
return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet);
|
|
||||||
|
|
||||||
case TX_MULTISIG:
|
|
||||||
scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
|
|
||||||
return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet));
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
|
unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
|
||||||
{
|
{
|
||||||
unsigned int nResult = 0;
|
unsigned int nResult = 0;
|
||||||
|
@ -201,171 +125,3 @@ public:
|
||||||
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys) {
|
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys) {
|
||||||
CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey);
|
CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
|
||||||
{
|
|
||||||
assert(nIn < txTo.vin.size());
|
|
||||||
CTxIn& txin = txTo.vin[nIn];
|
|
||||||
|
|
||||||
// Leave out the signature from the hash, since a signature can't sign itself.
|
|
||||||
// The checksig op will also drop the signatures from its hash.
|
|
||||||
uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType);
|
|
||||||
|
|
||||||
txnouttype whichType;
|
|
||||||
if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType))
|
|
||||||
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 = txin.scriptSig;
|
|
||||||
|
|
||||||
// Recompute txn hash using subscript in place of scriptPubKey:
|
|
||||||
uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType);
|
|
||||||
|
|
||||||
txnouttype subType;
|
|
||||||
bool fSolved =
|
|
||||||
Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH;
|
|
||||||
// Append serialized subscript whether or not it is completely signed:
|
|
||||||
txin.scriptSig << static_cast<valtype>(subscript);
|
|
||||||
if (!fSolved) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test solution
|
|
||||||
return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
|
||||||
{
|
|
||||||
assert(nIn < txTo.vin.size());
|
|
||||||
CTxIn& txin = txTo.vin[nIn];
|
|
||||||
assert(txin.prevout.n < txFrom.vout.size());
|
|
||||||
const CTxOut& txout = txFrom.vout[txin.prevout.n];
|
|
||||||
|
|
||||||
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CScript PushAll(const vector<valtype>& values)
|
|
||||||
{
|
|
||||||
CScript result;
|
|
||||||
BOOST_FOREACH(const valtype& v, values)
|
|
||||||
result << v;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn,
|
|
||||||
const vector<valtype>& vSolutions,
|
|
||||||
vector<valtype>& sigs1, vector<valtype>& sigs2)
|
|
||||||
{
|
|
||||||
// Combine all the signatures we've got:
|
|
||||||
set<valtype> allsigs;
|
|
||||||
BOOST_FOREACH(const valtype& v, sigs1)
|
|
||||||
{
|
|
||||||
if (!v.empty())
|
|
||||||
allsigs.insert(v);
|
|
||||||
}
|
|
||||||
BOOST_FOREACH(const valtype& v, sigs2)
|
|
||||||
{
|
|
||||||
if (!v.empty())
|
|
||||||
allsigs.insert(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build a map of pubkey -> signature by matching sigs to pubkeys:
|
|
||||||
assert(vSolutions.size() > 1);
|
|
||||||
unsigned int nSigsRequired = vSolutions.front()[0];
|
|
||||||
unsigned int nPubKeys = vSolutions.size()-2;
|
|
||||||
map<valtype, valtype> sigs;
|
|
||||||
BOOST_FOREACH(const valtype& sig, allsigs)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < nPubKeys; i++)
|
|
||||||
{
|
|
||||||
const valtype& pubkey = vSolutions[i+1];
|
|
||||||
if (sigs.count(pubkey))
|
|
||||||
continue; // Already got a sig for this pubkey
|
|
||||||
|
|
||||||
if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0, 0))
|
|
||||||
{
|
|
||||||
sigs[pubkey] = sig;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Now build a merged CScript:
|
|
||||||
unsigned int nSigsHave = 0;
|
|
||||||
CScript result; result << OP_0; // 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]];
|
|
||||||
++nSigsHave;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Fill any missing with OP_0:
|
|
||||||
for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
|
|
||||||
result << OP_0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
|
||||||
const txnouttype txType, const vector<valtype>& vSolutions,
|
|
||||||
vector<valtype>& sigs1, vector<valtype>& sigs2)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
case TX_SCRIPTHASH:
|
|
||||||
if (sigs1.empty() || sigs1.back().empty())
|
|
||||||
return PushAll(sigs2);
|
|
||||||
else if (sigs2.empty() || sigs2.back().empty())
|
|
||||||
return PushAll(sigs1);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Recur to combine:
|
|
||||||
valtype spk = sigs1.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, txTo, nIn, txType2, vSolutions2, sigs1, sigs2);
|
|
||||||
result << spk;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
case TX_MULTISIG:
|
|
||||||
return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return CScript();
|
|
||||||
}
|
|
||||||
|
|
||||||
CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
|
||||||
const CScript& scriptSig1, const CScript& scriptSig2)
|
|
||||||
{
|
|
||||||
txnouttype txType;
|
|
||||||
vector<vector<unsigned char> > vSolutions;
|
|
||||||
Solver(scriptPubKey, txType, vSolutions);
|
|
||||||
|
|
||||||
vector<valtype> stack1;
|
|
||||||
EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
|
|
||||||
vector<valtype> stack2;
|
|
||||||
EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
|
|
||||||
|
|
||||||
return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,17 +8,8 @@
|
||||||
|
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "script/interpreter.h"
|
|
||||||
#include "script/standard.h"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class CKeyStore;
|
class CKeyStore;
|
||||||
class CTransaction;
|
|
||||||
struct CMutableTransaction;
|
|
||||||
|
|
||||||
/** IsMine() return codes */
|
/** IsMine() return codes */
|
||||||
enum isminetype
|
enum isminetype
|
||||||
|
@ -34,11 +25,5 @@ typedef uint8_t isminefilter;
|
||||||
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
|
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
|
||||||
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
|
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
|
||||||
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
|
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
|
||||||
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);
|
|
||||||
|
|
||||||
// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
|
|
||||||
// combine them intelligently and return the result.
|
|
||||||
CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
|
|
||||||
|
|
||||||
#endif // H_BITCOIN_SCRIPT
|
#endif // H_BITCOIN_SCRIPT
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "pow.h"
|
#include "pow.h"
|
||||||
#include "scriptutils.h"
|
#include "script/sign.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "script/interpreter.h"
|
#include "script/interpreter.h"
|
||||||
|
#include "script/sign.h"
|
||||||
#include "scriptutils.h"
|
#include "scriptutils.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
|
#include "script/sign.h"
|
||||||
#include "scriptutils.h"
|
#include "scriptutils.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "scriptutils.h"
|
#include "script/sign.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include "checkpoints.h"
|
#include "checkpoints.h"
|
||||||
#include "coincontrol.h"
|
#include "coincontrol.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
#include "script/script.h"
|
||||||
|
#include "script/sign.h"
|
||||||
#include "timedata.h"
|
#include "timedata.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utilmoneystr.h"
|
#include "utilmoneystr.h"
|
||||||
|
|
Loading…
Add table
Reference in a new issue