Page MenuHomePhabricator

No OneTemporary

diff --git a/src/keystore.h b/src/keystore.h
index 6e698650f..51365069c 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -1,93 +1,90 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEYSTORE_H
#define BITCOIN_KEYSTORE_H
#include <key.h>
#include <pubkey.h>
#include <script/script.h>
+#include <script/sign.h>
#include <script/standard.h>
#include <sync.h>
#include <boost/signals2/signal.hpp>
/** A virtual base class for key stores */
-class CKeyStore {
-public:
- virtual ~CKeyStore() {}
+class CKeyStore : public SigningProvider {
+protected:
+ mutable CCriticalSection cs_KeyStore;
+public:
//! Add a key to the store.
virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) = 0;
//! Check whether a key corresponding to a given address is present in the
//! store.
virtual bool HaveKey(const CKeyID &address) const = 0;
- virtual bool GetKey(const CKeyID &address, CKey &keyOut) const = 0;
virtual std::set<CKeyID> GetKeys() const = 0;
- virtual bool GetPubKey(const CKeyID &address,
- CPubKey &vchPubKeyOut) const = 0;
//! Support for BIP 0013 : see
//! https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki
virtual bool AddCScript(const CScript &redeemScript) = 0;
virtual bool HaveCScript(const CScriptID &hash) const = 0;
virtual std::set<CScriptID> GetCScripts() const = 0;
- virtual bool GetCScript(const CScriptID &hash,
- CScript &redeemScriptOut) const = 0;
//! Support for Watch-only addresses
virtual bool AddWatchOnly(const CScript &dest) = 0;
virtual bool RemoveWatchOnly(const CScript &dest) = 0;
virtual bool HaveWatchOnly(const CScript &dest) const = 0;
virtual bool HaveWatchOnly() const = 0;
};
typedef std::map<CKeyID, CKey> KeyMap;
typedef std::map<CKeyID, CPubKey> WatchKeyMap;
typedef std::map<CScriptID, CScript> ScriptMap;
typedef std::set<CScript> WatchOnlySet;
/** Basic key store, that keeps keys in an address->secret map */
class CBasicKeyStore : public CKeyStore {
protected:
mutable CCriticalSection cs_KeyStore;
KeyMap mapKeys;
WatchKeyMap mapWatchKeys;
ScriptMap mapScripts;
WatchOnlySet setWatchOnly;
void ImplicitlyLearnRelatedKeyScripts(const CPubKey &pubkey);
public:
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override;
bool AddKey(const CKey &key) { return AddKeyPubKey(key, key.GetPubKey()); }
bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override;
bool HaveKey(const CKeyID &address) const override;
std::set<CKeyID> GetKeys() const override;
bool GetKey(const CKeyID &address, CKey &keyOut) const override;
bool AddCScript(const CScript &redeemScript) override;
bool HaveCScript(const CScriptID &hash) const override;
std::set<CScriptID> GetCScripts() const override;
bool GetCScript(const CScriptID &hash,
CScript &redeemScriptOut) const override;
bool AddWatchOnly(const CScript &dest) override;
bool RemoveWatchOnly(const CScript &dest) override;
bool HaveWatchOnly(const CScript &dest) const override;
bool HaveWatchOnly() const override;
};
typedef std::vector<uint8_t, secure_allocator<uint8_t>> CKeyingMaterial;
typedef std::map<CKeyID, std::pair<CPubKey, std::vector<uint8_t>>>
CryptedKeyMap;
/**
* Return the CKeyID of the key involved in a script (if there is a unique one).
*/
CKeyID GetKeyForDestination(const CKeyStore &store, const CTxDestination &dest);
#endif // BITCOIN_KEYSTORE_H
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 781b7e5c0..e6064b21d 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -1,391 +1,387 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <script/sign.h>
#include <key.h>
-#include <keystore.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
#include <script/standard.h>
#include <uint256.h>
typedef std::vector<uint8_t> valtype;
TransactionSignatureCreator::TransactionSignatureCreator(
- const CKeyStore *keystoreIn, const CTransaction *txToIn, unsigned int nInIn,
- const Amount amountIn, SigHashType sigHashTypeIn)
- : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn),
+ const SigningProvider *provider, const CTransaction *txToIn,
+ unsigned int nInIn, const Amount amountIn, SigHashType sigHashTypeIn)
+ : BaseSignatureCreator(provider), txTo(txToIn), nIn(nInIn),
amount(amountIn), sigHashType(sigHashTypeIn),
checker(txTo, nIn, amountIn) {}
bool TransactionSignatureCreator::CreateSig(std::vector<uint8_t> &vchSig,
const CKeyID &address,
const CScript &scriptCode) const {
CKey key;
- if (!keystore->GetKey(address, key)) {
+ if (!m_provider->GetKey(address, key)) {
return false;
}
uint256 hash = SignatureHash(scriptCode, *txTo, nIn, sigHashType, amount);
if (!key.SignECDSA(hash, vchSig)) {
return false;
}
vchSig.push_back(uint8_t(sigHashType.getRawSigHashType()));
return true;
}
static bool Sign1(const CKeyID &address, const BaseSignatureCreator &creator,
const CScript &scriptCode, std::vector<valtype> &ret) {
std::vector<uint8_t> vchSig;
if (!creator.CreateSig(vchSig, address, scriptCode)) {
return false;
}
ret.push_back(vchSig);
return true;
}
static bool SignN(const std::vector<valtype> &multisigdata,
const BaseSignatureCreator &creator,
const CScript &scriptCode, std::vector<valtype> &ret) {
int nSigned = 0;
int nRequired = multisigdata.front()[0];
for (size_t i = 1; i < multisigdata.size() - 1 && nSigned < nRequired;
i++) {
const valtype &pubkey = multisigdata[i];
CKeyID keyID = CPubKey(pubkey).GetID();
if (Sign1(keyID, creator, scriptCode, ret)) {
++nSigned;
}
}
return nSigned == nRequired;
}
/**
* Sign scriptPubKey using signature made with creator.
* 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.
*/
static bool SignStep(const BaseSignatureCreator &creator,
const CScript &scriptPubKey, std::vector<valtype> &ret,
txnouttype &whichTypeRet) {
CScript scriptRet;
uint160 h160;
ret.clear();
std::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, creator, scriptPubKey, ret);
case TX_PUBKEYHASH: {
keyID = CKeyID(uint160(vSolutions[0]));
if (!Sign1(keyID, creator, scriptPubKey, ret)) {
return false;
}
CPubKey vch;
- creator.KeyStore().GetPubKey(keyID, vch);
+ creator.Provider().GetPubKey(keyID, vch);
ret.push_back(ToByteVector(vch));
return true;
}
case TX_SCRIPTHASH:
- if (creator.KeyStore().GetCScript(uint160(vSolutions[0]),
+ if (creator.Provider().GetCScript(uint160(vSolutions[0]),
scriptRet)) {
ret.push_back(
std::vector<uint8_t>(scriptRet.begin(), scriptRet.end()));
return true;
}
-
return false;
-
case TX_MULTISIG:
// workaround CHECKMULTISIG bug
ret.push_back(valtype());
return (SignN(vSolutions, creator, scriptPubKey, ret));
-
default:
return false;
}
}
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) {
std::vector<valtype> result;
txnouttype whichType;
bool solved = SignStep(creator, fromPubKey, result, whichType);
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:
subscript = CScript(result[0].begin(), result[0].end());
solved = solved && SignStep(creator, subscript, result, whichType) &&
whichType != TX_SCRIPTHASH;
result.push_back(
std::vector<uint8_t>(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 UpdateInput(CTxIn &input, const SignatureData &data) {
input.scriptSig = data.scriptSig;
}
void UpdateTransaction(CMutableTransaction &tx, unsigned int nIn,
const SignatureData &data) {
assert(tx.vin.size() > nIn);
UpdateInput(tx.vin[nIn], data);
}
-bool SignSignature(const CKeyStore &keystore, const CScript &fromPubKey,
+bool SignSignature(const SigningProvider &provider, const CScript &fromPubKey,
CMutableTransaction &txTo, unsigned int nIn,
const Amount amount, SigHashType sigHashType) {
assert(nIn < txTo.vin.size());
CTransaction txToConst(txTo);
- TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount,
+ TransactionSignatureCreator creator(&provider, &txToConst, nIn, amount,
sigHashType);
SignatureData sigdata;
bool ret = ProduceSignature(creator, fromPubKey, sigdata);
UpdateTransaction(txTo, nIn, sigdata);
return ret;
}
-bool SignSignature(const CKeyStore &keystore, const CTransaction &txFrom,
+bool SignSignature(const SigningProvider &provider, const CTransaction &txFrom,
CMutableTransaction &txTo, unsigned int nIn,
SigHashType sigHashType) {
assert(nIn < txTo.vin.size());
CTxIn &txin = txTo.vin[nIn];
assert(txin.prevout.GetN() < txFrom.vout.size());
const CTxOut &txout = txFrom.vout[txin.prevout.GetN()];
- return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue,
+ return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue,
sigHashType);
}
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) {
// Combine all the signatures we've got:
std::set<valtype> allsigs;
for (const valtype &v : sigs1) {
if (!v.empty()) {
allsigs.insert(v);
}
}
for (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;
std::map<valtype, valtype> sigs;
for (const valtype &sig : allsigs) {
for (unsigned int i = 0; i < nPubKeys; i++) {
const valtype &pubkey = vSolutions[i + 1];
// Already got a sig for this pubkey
if (sigs.count(pubkey)) {
continue;
}
if (checker.CheckSig(sig, pubkey, scriptPubKey,
STANDARD_SCRIPT_VERIFY_FLAGS)) {
sigs[pubkey] = sig;
break;
}
}
}
// Now build a merged CScript:
unsigned int nSigsHave = 0;
// pop-one-too-many workaround
std::vector<valtype> result;
result.push_back(valtype());
for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) {
if (sigs.count(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.push_back(valtype());
}
return result;
}
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, MANDATORY_SCRIPT_VERIFY_FLAGS,
BaseSignatureChecker());
}
SignatureData Output() const {
SignatureData result;
result.scriptSig = PushAll(script);
return result;
}
};
} // namespace
static Stacks CombineSignatures(const CScript &scriptPubKey,
const BaseSignatureChecker &checker,
const txnouttype txType,
const std::vector<valtype> &vSolutions,
Stacks sigs1, Stacks sigs2) {
switch (txType) {
case TX_NONSTANDARD:
case TX_NULL_DATA:
// Don't know anything about this, assume bigger one is correct:
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.script.empty() || sigs1.script[0].empty()) {
return sigs2;
}
return sigs1;
case TX_SCRIPTHASH: {
if (sigs1.script.empty() || sigs1.script.back().empty()) {
return sigs2;
}
if (sigs2.script.empty() || sigs2.script.back().empty()) {
return sigs1;
}
// Recur to combine:
valtype spk = sigs1.script.back();
CScript pubKey2(spk.begin(), spk.end());
txnouttype txType2;
std::vector<std::vector<uint8_t>> vSolutions2;
Solver(pubKey2, txType2, vSolutions2);
sigs1.script.pop_back();
sigs2.script.pop_back();
Stacks result = CombineSignatures(pubKey2, checker, txType2,
vSolutions2, sigs1, sigs2);
result.script.push_back(spk);
return result;
}
case TX_MULTISIG:
return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions,
sigs1.script, sigs2.script));
default:
return Stacks();
}
}
SignatureData CombineSignatures(const CScript &scriptPubKey,
const BaseSignatureChecker &checker,
const SignatureData &scriptSig1,
const SignatureData &scriptSig2) {
txnouttype txType;
std::vector<std::vector<uint8_t>> vSolutions;
Solver(scriptPubKey, txType, vSolutions);
return CombineSignatures(scriptPubKey, checker, txType, vSolutions,
Stacks(scriptSig1), Stacks(scriptSig2))
.Output();
}
namespace {
/** Dummy signature checker which accepts all signatures. */
class DummySignatureChecker : public BaseSignatureChecker {
public:
DummySignatureChecker() {}
bool CheckSig(const std::vector<uint8_t> &scriptSig,
const std::vector<uint8_t> &vchPubKey,
const CScript &scriptCode, uint32_t flags) const override {
return true;
}
};
const DummySignatureChecker dummyChecker;
} // namespace
const BaseSignatureChecker &DummySignatureCreator::Checker() const {
return dummyChecker;
}
bool DummySignatureCreator::CreateSig(std::vector<uint8_t> &vchSig,
const CKeyID &keyid,
const CScript &scriptCode) const {
// Create a dummy signature that is a valid DER-encoding
vchSig.assign(72, '\000');
vchSig[0] = 0x30;
vchSig[1] = 69;
vchSig[2] = 0x02;
vchSig[3] = 33;
vchSig[4] = 0x01;
vchSig[4 + 33] = 0x02;
vchSig[5 + 33] = 32;
vchSig[6 + 33] = 0x01;
vchSig[6 + 33 + 32] = SIGHASH_ALL | SIGHASH_FORKID;
return true;
}
diff --git a/src/script/sign.h b/src/script/sign.h
index 423e44c9f..1685d4b01 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -1,110 +1,121 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_SCRIPT_SIGN_H
#define BITCOIN_SCRIPT_SIGN_H
#include <script/interpreter.h>
#include <script/sighashtype.h>
+class CKey;
class CKeyID;
-class CKeyStore;
class CMutableTransaction;
class CScript;
+class CScriptID;
class CTransaction;
+/** An interface to be implemented by keystores that support signing. */
+class SigningProvider {
+public:
+ virtual ~SigningProvider() {}
+ virtual bool GetCScript(const CScriptID &scriptid,
+ CScript &script) const = 0;
+ virtual bool GetPubKey(const CKeyID &address, CPubKey &pubkey) const = 0;
+ virtual bool GetKey(const CKeyID &address, CKey &key) const = 0;
+};
+
/** Virtual base class for signature creators. */
class BaseSignatureCreator {
protected:
- const CKeyStore *keystore;
+ const SigningProvider *m_provider;
public:
- explicit BaseSignatureCreator(const CKeyStore *keystoreIn)
- : keystore(keystoreIn) {}
- const CKeyStore &KeyStore() const { return *keystore; };
+ explicit BaseSignatureCreator(const SigningProvider *provider)
+ : m_provider(provider) {}
+ const SigningProvider &Provider() const { return *m_provider; }
virtual ~BaseSignatureCreator() {}
virtual const BaseSignatureChecker &Checker() const = 0;
/** Create a singular (non-script) signature. */
virtual bool CreateSig(std::vector<uint8_t> &vchSig, const CKeyID &keyid,
const CScript &scriptCode) const = 0;
};
/** A signature creator for transactions. */
class TransactionSignatureCreator : public BaseSignatureCreator {
const CTransaction *txTo;
unsigned int nIn;
Amount amount;
SigHashType sigHashType;
const TransactionSignatureChecker checker;
public:
- TransactionSignatureCreator(const CKeyStore *keystoreIn,
+ TransactionSignatureCreator(const SigningProvider *provider,
const CTransaction *txToIn, unsigned int nInIn,
const Amount amountIn,
SigHashType sigHashTypeIn = SigHashType());
const BaseSignatureChecker &Checker() const override { return checker; }
bool CreateSig(std::vector<uint8_t> &vchSig, const CKeyID &keyid,
const CScript &scriptCode) const override;
};
class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
CTransaction tx;
public:
- MutableTransactionSignatureCreator(const CKeyStore *keystoreIn,
+ MutableTransactionSignatureCreator(const SigningProvider *provider,
const CMutableTransaction *txToIn,
unsigned int nInIn,
const Amount amountIn,
SigHashType sigHashTypeIn)
- : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amountIn,
+ : TransactionSignatureCreator(provider, &tx, nInIn, amountIn,
sigHashTypeIn),
tx(*txToIn) {}
};
/** A signature creator that just produces 72-byte empty signatures. */
class DummySignatureCreator : public BaseSignatureCreator {
public:
- explicit DummySignatureCreator(const CKeyStore *keystoreIn)
- : BaseSignatureCreator(keystoreIn) {}
+ explicit DummySignatureCreator(const SigningProvider *provider)
+ : BaseSignatureCreator(provider) {}
const BaseSignatureChecker &Checker() const override;
bool CreateSig(std::vector<uint8_t> &vchSig, const CKeyID &keyid,
const CScript &scriptCode) 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, SignatureData &sigdata);
/** Produce a script signature for a transaction. */
-bool SignSignature(const CKeyStore &keystore, const CScript &fromPubKey,
+bool SignSignature(const SigningProvider &provider, const CScript &fromPubKey,
CMutableTransaction &txTo, unsigned int nIn,
const Amount amount, SigHashType sigHashType);
-bool SignSignature(const CKeyStore &keystore, const CTransaction &txFrom,
+bool SignSignature(const SigningProvider &provider, const CTransaction &txFrom,
CMutableTransaction &txTo, unsigned int nIn,
SigHashType sigHashType);
/** Combine two script signatures using a generic signature checker,
* intelligently, possibly with OP_0 placeholders. */
SignatureData CombineSignatures(const CScript &scriptPubKey,
const BaseSignatureChecker &checker,
const SignatureData &scriptSig1,
const SignatureData &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);
void UpdateInput(CTxIn &input, const SignatureData &data);
#endif // BITCOIN_SCRIPT_SIGN_H

File Metadata

Mime Type
text/x-diff
Expires
Sun, Mar 2, 09:26 (1 d, 4 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187197
Default Alt Text
(23 KB)

Event Timeline