Introduce interface for signing providers
CKeyStore is a rich interface that provides many features, including knowledge of scripts and pubkeys for solving, private keys for signing, in addition to watch-only keys and scripts, and distinguishing lack of keys from them just being encrypted. The signing logic in script/sign does not actually need most of these features. Here we introduce a simpler interface (SigningProvider) which *only* provides keys and scripts. This is actually sufficient for signing. In addtion, we swap the dependency between keystore and script/sign (keystore now depends on script/script with CKeyStore deriving from SigningProvider, rather than CKeyStore being the interface that signing relies on).
This commit is contained in:
parent
af20f9b1d4
commit
d40f06a3da
3 changed files with 35 additions and 29 deletions
|
@ -9,35 +9,31 @@
|
||||||
#include <key.h>
|
#include <key.h>
|
||||||
#include <pubkey.h>
|
#include <pubkey.h>
|
||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
|
#include <script/sign.h>
|
||||||
#include <script/standard.h>
|
#include <script/standard.h>
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
|
|
||||||
#include <boost/signals2/signal.hpp>
|
#include <boost/signals2/signal.hpp>
|
||||||
|
|
||||||
/** A virtual base class for key stores */
|
/** A virtual base class for key stores */
|
||||||
class CKeyStore
|
class CKeyStore : public SigningProvider
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
mutable CCriticalSection cs_KeyStore;
|
mutable CCriticalSection cs_KeyStore;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~CKeyStore() {}
|
|
||||||
|
|
||||||
//! Add a key to the store.
|
//! Add a key to the store.
|
||||||
virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) =0;
|
virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) =0;
|
||||||
virtual bool AddKey(const CKey &key);
|
virtual bool AddKey(const CKey &key);
|
||||||
|
|
||||||
//! Check whether a key corresponding to a given address is present in the store.
|
//! Check whether a key corresponding to a given address is present in the store.
|
||||||
virtual bool HaveKey(const CKeyID &address) const =0;
|
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 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
|
//! Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki
|
||||||
virtual bool AddCScript(const CScript& redeemScript) =0;
|
virtual bool AddCScript(const CScript& redeemScript) =0;
|
||||||
virtual bool HaveCScript(const CScriptID &hash) const =0;
|
virtual bool HaveCScript(const CScriptID &hash) const =0;
|
||||||
virtual std::set<CScriptID> GetCScripts() const =0;
|
virtual std::set<CScriptID> GetCScripts() const =0;
|
||||||
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0;
|
|
||||||
|
|
||||||
//! Support for Watch-only addresses
|
//! Support for Watch-only addresses
|
||||||
virtual bool AddWatchOnly(const CScript &dest) =0;
|
virtual bool AddWatchOnly(const CScript &dest) =0;
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include <script/sign.h>
|
#include <script/sign.h>
|
||||||
|
|
||||||
#include <key.h>
|
#include <key.h>
|
||||||
#include <keystore.h>
|
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <script/standard.h>
|
#include <script/standard.h>
|
||||||
|
@ -15,12 +14,12 @@
|
||||||
|
|
||||||
typedef std::vector<unsigned char> valtype;
|
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) {}
|
TransactionSignatureCreator::TransactionSignatureCreator(const SigningProvider* provider, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(provider), 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, SigVersion sigversion) const
|
bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const
|
||||||
{
|
{
|
||||||
CKey key;
|
CKey key;
|
||||||
if (!keystore->GetKey(address, key))
|
if (!m_provider->GetKey(address, key))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Signing with uncompressed keys is disabled in witness scripts
|
// Signing with uncompressed keys is disabled in witness scripts
|
||||||
|
@ -91,12 +90,12 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CPubKey vch;
|
CPubKey vch;
|
||||||
creator.KeyStore().GetPubKey(keyID, vch);
|
creator.Provider().GetPubKey(keyID, vch);
|
||||||
ret.push_back(ToByteVector(vch));
|
ret.push_back(ToByteVector(vch));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case TX_SCRIPTHASH:
|
case TX_SCRIPTHASH:
|
||||||
if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) {
|
if (creator.Provider().GetCScript(uint160(vSolutions[0]), scriptRet)) {
|
||||||
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
|
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +111,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
|
||||||
|
|
||||||
case TX_WITNESS_V0_SCRIPTHASH:
|
case TX_WITNESS_V0_SCRIPTHASH:
|
||||||
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin());
|
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin());
|
||||||
if (creator.KeyStore().GetCScript(h160, scriptRet)) {
|
if (creator.Provider().GetCScript(h160, scriptRet)) {
|
||||||
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
|
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -206,12 +205,12 @@ void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const Signatur
|
||||||
UpdateInput(tx.vin[nIn], data);
|
UpdateInput(tx.vin[nIn], data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
|
bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
|
||||||
{
|
{
|
||||||
assert(nIn < txTo.vin.size());
|
assert(nIn < txTo.vin.size());
|
||||||
|
|
||||||
CTransaction txToConst(txTo);
|
CTransaction txToConst(txTo);
|
||||||
TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType);
|
TransactionSignatureCreator creator(&provider, &txToConst, nIn, amount, nHashType);
|
||||||
|
|
||||||
SignatureData sigdata;
|
SignatureData sigdata;
|
||||||
bool ret = ProduceSignature(creator, fromPubKey, sigdata);
|
bool ret = ProduceSignature(creator, fromPubKey, sigdata);
|
||||||
|
@ -219,14 +218,14 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutabl
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
||||||
{
|
{
|
||||||
assert(nIn < txTo.vin.size());
|
assert(nIn < txTo.vin.size());
|
||||||
CTxIn& txin = txTo.vin[nIn];
|
CTxIn& txin = txTo.vin[nIn];
|
||||||
assert(txin.prevout.n < txFrom.vout.size());
|
assert(txin.prevout.n < txFrom.vout.size());
|
||||||
const CTxOut& txout = txFrom.vout[txin.prevout.n];
|
const CTxOut& txout = txFrom.vout[txin.prevout.n];
|
||||||
|
|
||||||
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType);
|
return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
|
static std::vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
|
||||||
|
@ -427,13 +426,13 @@ bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSolvable(const CKeyStore& store, const CScript& script)
|
bool IsSolvable(const SigningProvider& provider, const CScript& script)
|
||||||
{
|
{
|
||||||
// This check is to make sure that the script we created can actually be solved for and signed by us
|
// This check is to make sure that the script we created can actually be solved for and signed by us
|
||||||
// if we were to have the private keys. This is just to make sure that the script is valid and that,
|
// if we were to have the private keys. This is just to make sure that the script is valid and that,
|
||||||
// if found in a transaction, we would still accept and relay that transaction. In particular,
|
// if found in a transaction, we would still accept and relay that transaction. In particular,
|
||||||
// it will reject witness outputs that require signing with an uncompressed public key.
|
// it will reject witness outputs that require signing with an uncompressed public key.
|
||||||
DummySignatureCreator creator(&store);
|
DummySignatureCreator creator(&provider);
|
||||||
SignatureData sigs;
|
SignatureData sigs;
|
||||||
// Make sure that STANDARD_SCRIPT_VERIFY_FLAGS includes SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, the most
|
// Make sure that STANDARD_SCRIPT_VERIFY_FLAGS includes SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, the most
|
||||||
// important property this function is designed to test for.
|
// important property this function is designed to test for.
|
||||||
|
|
|
@ -8,21 +8,32 @@
|
||||||
|
|
||||||
#include <script/interpreter.h>
|
#include <script/interpreter.h>
|
||||||
|
|
||||||
|
class CKey;
|
||||||
class CKeyID;
|
class CKeyID;
|
||||||
class CKeyStore;
|
|
||||||
class CScript;
|
class CScript;
|
||||||
|
class CScriptID;
|
||||||
class CTransaction;
|
class CTransaction;
|
||||||
|
|
||||||
struct CMutableTransaction;
|
struct CMutableTransaction;
|
||||||
|
|
||||||
|
/** 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. */
|
/** Virtual base class for signature creators. */
|
||||||
class BaseSignatureCreator {
|
class BaseSignatureCreator {
|
||||||
protected:
|
protected:
|
||||||
const CKeyStore* keystore;
|
const SigningProvider* m_provider;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BaseSignatureCreator(const CKeyStore* keystoreIn) : keystore(keystoreIn) {}
|
explicit BaseSignatureCreator(const SigningProvider* provider) : m_provider(provider) {}
|
||||||
const CKeyStore& KeyStore() const { return *keystore; };
|
const SigningProvider& Provider() const { return *m_provider; }
|
||||||
virtual ~BaseSignatureCreator() {}
|
virtual ~BaseSignatureCreator() {}
|
||||||
virtual const BaseSignatureChecker& Checker() const =0;
|
virtual const BaseSignatureChecker& Checker() const =0;
|
||||||
|
|
||||||
|
@ -39,7 +50,7 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
|
||||||
const TransactionSignatureChecker checker;
|
const TransactionSignatureChecker checker;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);
|
TransactionSignatureCreator(const SigningProvider* provider, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);
|
||||||
const BaseSignatureChecker& Checker() const override { return checker; }
|
const BaseSignatureChecker& Checker() const override { return checker; }
|
||||||
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
|
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
|
||||||
};
|
};
|
||||||
|
@ -48,13 +59,13 @@ class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
|
||||||
CTransaction tx;
|
CTransaction tx;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amountIn, nHashTypeIn), tx(*txToIn) {}
|
MutableTransactionSignatureCreator(const SigningProvider* provider, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : TransactionSignatureCreator(provider, &tx, nInIn, amountIn, nHashTypeIn), tx(*txToIn) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A signature creator that just produces 72-byte empty signatures. */
|
/** A signature creator that just produces 72-byte empty signatures. */
|
||||||
class DummySignatureCreator : public BaseSignatureCreator {
|
class DummySignatureCreator : public BaseSignatureCreator {
|
||||||
public:
|
public:
|
||||||
explicit DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
|
explicit DummySignatureCreator(const SigningProvider* provider) : BaseSignatureCreator(provider) {}
|
||||||
const BaseSignatureChecker& Checker() const override;
|
const BaseSignatureChecker& Checker() const override;
|
||||||
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
|
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
|
||||||
};
|
};
|
||||||
|
@ -71,8 +82,8 @@ struct SignatureData {
|
||||||
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata);
|
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata);
|
||||||
|
|
||||||
/** Produce a script signature for a transaction. */
|
/** Produce a script signature for a transaction. */
|
||||||
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType);
|
bool SignSignature(const SigningProvider &provider, 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);
|
bool SignSignature(const SigningProvider &provider, 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. */
|
/** 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);
|
SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2);
|
||||||
|
@ -84,8 +95,8 @@ void UpdateInput(CTxIn& input, const SignatureData& data);
|
||||||
|
|
||||||
/* Check whether we know how to sign for an output like this, assuming we
|
/* Check whether we know how to sign for an output like this, assuming we
|
||||||
* have all private keys. While this function does not need private keys, the passed
|
* have all private keys. While this function does not need private keys, the passed
|
||||||
* keystore is used to look up public keys and redeemscripts by hash.
|
* provider is used to look up public keys and redeemscripts by hash.
|
||||||
* Solvability is unrelated to whether we consider this output to be ours. */
|
* Solvability is unrelated to whether we consider this output to be ours. */
|
||||||
bool IsSolvable(const CKeyStore& store, const CScript& script);
|
bool IsSolvable(const SigningProvider& provider, const CScript& script);
|
||||||
|
|
||||||
#endif // BITCOIN_SCRIPT_SIGN_H
|
#endif // BITCOIN_SCRIPT_SIGN_H
|
||||||
|
|
Loading…
Reference in a new issue