Browse Source

Abstract out IsSolvable from Witnessifier

0.16
Pieter Wuille 7 years ago
parent
commit
0c8ea6380c
  1. 36
      src/policy/policy.h
  2. 19
      src/script/sign.cpp
  3. 6
      src/script/sign.h
  4. 14
      src/wallet/rpcwallet.cpp

36
src/policy/policy.h

@ -49,28 +49,28 @@ static const unsigned int DUST_RELAY_TX_FEE = 3000;
* with. However scripts violating these flags may still be present in valid * with. However scripts violating these flags may still be present in valid
* blocks and we must accept those blocks. * blocks and we must accept those blocks.
*/ */
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS | static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_DERSIG |
SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_STRICTENC |
SCRIPT_VERIFY_MINIMALDATA | SCRIPT_VERIFY_MINIMALDATA |
SCRIPT_VERIFY_NULLDUMMY | SCRIPT_VERIFY_NULLDUMMY |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_CLEANSTACK |
SCRIPT_VERIFY_MINIMALIF | SCRIPT_VERIFY_MINIMALIF |
SCRIPT_VERIFY_NULLFAIL | SCRIPT_VERIFY_NULLFAIL |
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY | SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_LOW_S |
SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_WITNESS |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE; SCRIPT_VERIFY_WITNESS_PUBKEYTYPE;
/** For convenience, standard but not mandatory verify flags. */ /** For convenience, standard but not mandatory verify flags. */
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
/** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */ /** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */
static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE | static constexpr unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE |
LOCKTIME_MEDIAN_TIME_PAST; LOCKTIME_MEDIAN_TIME_PAST;
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee); CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);

19
src/script/sign.cpp

@ -422,3 +422,22 @@ bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const
vchSig[6 + 33 + 32] = SIGHASH_ALL; vchSig[6 + 33 + 32] = SIGHASH_ALL;
return true; return true;
} }
bool IsSolvable(const CKeyStore& store, const CScript& script)
{
// 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 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.
DummySignatureCreator creator(&store);
SignatureData sigs;
// Make sure that STANDARD_SCRIPT_VERIFY_FLAGS includes SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, the most
// important property this function is designed to test for.
static_assert(STANDARD_SCRIPT_VERIFY_FLAGS & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, "IsSolvable requires standard script flags to include WITNESS_PUBKEYTYPE");
if (ProduceSignature(creator, script, sigs)) {
// VerifyScript check is just defensive, and should never fail.
assert(VerifyScript(sigs.scriptSig, script, &sigs.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()));
return true;
}
return false;
}

6
src/script/sign.h

@ -81,4 +81,10 @@ SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignature
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn); SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn);
void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data); void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data);
/* 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
* keystore is used to look up public keys and redeemscripts by hash.
* Solvability is unrelated to whether we consider this output to be ours. */
bool IsSolvable(const CKeyStore& store, const CScript& script);
#endif // BITCOIN_SCRIPT_SIGN_H #endif // BITCOIN_SCRIPT_SIGN_H

14
src/wallet/rpcwallet.cpp

@ -1204,12 +1204,7 @@ public:
if (pwallet) { if (pwallet) {
CScript basescript = GetScriptForDestination(keyID); CScript basescript = GetScriptForDestination(keyID);
CScript witscript = GetScriptForWitness(basescript); CScript witscript = GetScriptForWitness(basescript);
SignatureData sigs; if (!IsSolvable(*pwallet, witscript)) {
// 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 found in a transaction, we would still accept and relay that transaction.
if (!ProduceSignature(DummySignatureCreator(pwallet), witscript, sigs) ||
!VerifyScript(sigs.scriptSig, witscript, &sigs.scriptWitness, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, DummySignatureCreator(pwallet).Checker())) {
return false; return false;
} }
return ExtractDestination(witscript, result); return ExtractDestination(witscript, result);
@ -1228,12 +1223,7 @@ public:
return true; return true;
} }
CScript witscript = GetScriptForWitness(subscript); CScript witscript = GetScriptForWitness(subscript);
SignatureData sigs; if (!IsSolvable(*pwallet, witscript)) {
// 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 found in a transaction, we would still accept and relay that transaction.
if (!ProduceSignature(DummySignatureCreator(pwallet), witscript, sigs) ||
!VerifyScript(sigs.scriptSig, witscript, &sigs.scriptWitness, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, DummySignatureCreator(pwallet).Checker())) {
return false; return false;
} }
return ExtractDestination(witscript, result); return ExtractDestination(witscript, result);

Loading…
Cancel
Save