Implement raw transaction RPC calls

Implement listunspent / getrawtransaction / createrawtransaction /
signrawtransaction, to support creation and
signing-on-multiple-device multisignature transactions.
This commit is contained in:
Gavin Andresen
2012-05-31 16:01:16 -04:00
parent 899d373b3c
commit a2709fad7f
12 changed files with 750 additions and 56 deletions

View File

@@ -1331,15 +1331,12 @@ bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint2
{
int nSigned = 0;
int nRequired = multisigdata.front()[0];
for (vector<valtype>::const_iterator it = multisigdata.begin()+1; it != multisigdata.begin()+multisigdata.size()-1; it++)
for (int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
{
const valtype& pubkey = *it;
const valtype& pubkey = multisigdata[i];
CKeyID keyID = CPubKey(pubkey).GetID();
if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
{
++nSigned;
if (nSigned == nRequired) break;
}
}
return nSigned==nRequired;
}
@@ -1612,12 +1609,13 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa
// Recompute txn hash using subscript in place of scriptPubKey:
uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType);
txnouttype subType;
if (!Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType))
return false;
if (subType == TX_SCRIPTHASH)
return false;
txin.scriptSig << static_cast<valtype>(subscript); // Append serialized subscript
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
@@ -1648,6 +1646,127 @@ bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsig
return VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, fValidatePayToScriptHash, 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 CTransaction& 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:
int nSigsRequired = vSolutions.front()[0];
int nPubKeys = vSolutions.size()-2;
map<valtype, valtype> sigs;
BOOST_FOREACH(const valtype& sig, allsigs)
{
for (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))
{
sigs[pubkey] = sig;
break;
}
}
}
// Now build a merged CScript:
unsigned int nSigsHave = 0;
CScript result; result << OP_0; // pop-one-too-many workaround
for (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 (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:
// 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
{
// Recurse 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, 0);
vector<valtype> stack2;
EvalScript(stack2, scriptSig2, CTransaction(), 0, 0);
return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
}
unsigned int CScript::GetSigOpCount(bool fAccurate) const
{
unsigned int n = 0;