Skip to content

Commit e078ee9

Browse files
committed
Merge bitcoin/bitcoin#25664: refactor: Redefine IsSolvable() using descriptors
b16f93c script/sign: remove needless IsSolvable() utility (Antoine Poinsot) c232ef2 outputtype: remove redundant check for uncompressed keys in AddAndGetDestinationForScript (Antoine Poinsot) Pull request description: Now that we have descriptors there is no need to try to sign for a scriptPubKey using dummy signatures, and using a mocked verification of this witness against the interpreter, just to make sure we know how to spend such a Script. Just try to infer a solvable descriptor: any scriptPubKey that we can sign for can be inferred as such. This came up in #24149 but i think it's worth it on its own. ACKs for top commit: instagibbs: ACK bitcoin/bitcoin@b16f93c achow101: re-ACK b16f93c furszy: ACK b16f93c, only change is the `IsSolvable` helper function removal. Tree-SHA512: 137068157ce90210b710b1bf9ac3c400e2ff5af1112f892094b69875ea473d6a899f52adb51e5030cb907dee517602059cd1661107808558efa5de842ba12b41
2 parents 29c195c + b16f93c commit e078ee9

File tree

8 files changed

+4
-34
lines changed

8 files changed

+4
-34
lines changed

src/outputtype.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,6 @@ CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore,
9191
case OutputType::BECH32: {
9292
CTxDestination witdest = WitnessV0ScriptHash(script);
9393
CScript witprog = GetScriptForDestination(witdest);
94-
// Check if the resulting program is solvable (i.e. doesn't use an uncompressed key)
95-
if (!IsSolvable(keystore, witprog)) return ScriptHash(script);
9694
// Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours.
9795
keystore.AddCScript(witprog);
9896
if (type == OutputType::BECH32) {

src/script/sign.cpp

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -632,25 +632,6 @@ class DummySignatureCreator final : public BaseSignatureCreator {
632632
const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator(32, 32);
633633
const BaseSignatureCreator& DUMMY_MAXIMUM_SIGNATURE_CREATOR = DummySignatureCreator(33, 32);
634634

635-
bool IsSolvable(const SigningProvider& provider, const CScript& script)
636-
{
637-
// This check is to make sure that the script we created can actually be solved for and signed by us
638-
// if we were to have the private keys. This is just to make sure that the script is valid and that,
639-
// if found in a transaction, we would still accept and relay that transaction. In particular,
640-
// it will reject witness outputs that require signing with an uncompressed public key.
641-
SignatureData sigs;
642-
// Make sure that STANDARD_SCRIPT_VERIFY_FLAGS includes SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, the most
643-
// important property this function is designed to test for.
644-
static_assert(STANDARD_SCRIPT_VERIFY_FLAGS & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, "IsSolvable requires standard script flags to include WITNESS_PUBKEYTYPE");
645-
if (ProduceSignature(provider, DUMMY_SIGNATURE_CREATOR, script, sigs)) {
646-
// VerifyScript check is just defensive, and should never fail.
647-
bool verified = VerifyScript(sigs.scriptSig, script, &sigs.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, DUMMY_CHECKER);
648-
assert(verified);
649-
return true;
650-
}
651-
return false;
652-
}
653-
654635
bool IsSegWitOutput(const SigningProvider& provider, const CScript& script)
655636
{
656637
int version;

src/script/sign.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,6 @@ bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom,
9797
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout);
9898
void UpdateInput(CTxIn& input, const SignatureData& data);
9999

100-
/* Check whether we know how to sign for an output like this, assuming we
101-
* have all private keys. While this function does not need private keys, the passed
102-
* provider is used to look up public keys and redeemscripts by hash.
103-
* Solvability is unrelated to whether we consider this output to be ours. */
104-
bool IsSolvable(const SigningProvider& provider, const CScript& script);
105-
106100
/** Check whether a scriptPubKey is known to be segwit. */
107101
bool IsSegWitOutput(const SigningProvider& provider, const CScript& script);
108102

src/test/descriptor_tests.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,6 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
302302
// For each of the produced scripts, verify solvability, and when possible, try to sign a transaction spending it.
303303
for (size_t n = 0; n < spks.size(); ++n) {
304304
BOOST_CHECK_EQUAL(ref[n], HexStr(spks[n]));
305-
BOOST_CHECK_EQUAL(IsSolvable(Merge(key_provider, script_provider), spks[n]), (flags & UNSOLVABLE) == 0);
306305

307306
if (flags & SIGNABLE) {
308307
CMutableTransaction spend;
@@ -324,7 +323,7 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
324323
BOOST_CHECK(inferred->Expand(0, provider_inferred, spks_inferred, provider_inferred));
325324
BOOST_CHECK_EQUAL(spks_inferred.size(), 1U);
326325
BOOST_CHECK(spks_inferred[0] == spks[n]);
327-
BOOST_CHECK_EQUAL(IsSolvable(provider_inferred, spks_inferred[0]), !(flags & UNSOLVABLE));
326+
BOOST_CHECK_EQUAL(InferDescriptor(spks_inferred[0], provider_inferred)->IsSolvable(), !(flags & UNSOLVABLE));
328327
BOOST_CHECK(GetKeyOriginData(provider_inferred, flags) == GetKeyOriginData(script_provider, flags));
329328
}
330329

src/test/fuzz/key.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,6 @@ FUZZ_TARGET_INIT(key, initialize_key)
138138
assert(tx_multisig_script.size() == 37);
139139

140140
FillableSigningProvider fillable_signing_provider;
141-
assert(IsSolvable(fillable_signing_provider, tx_pubkey_script));
142-
assert(IsSolvable(fillable_signing_provider, tx_multisig_script));
143141
assert(!IsSegWitOutput(fillable_signing_provider, tx_pubkey_script));
144142
assert(!IsSegWitOutput(fillable_signing_provider, tx_multisig_script));
145143
assert(fillable_signing_provider.GetKeys().size() == 0);

src/test/fuzz/script.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ FUZZ_TARGET_INIT(script, initialize_script)
8989
const FlatSigningProvider signing_provider;
9090
(void)InferDescriptor(script, signing_provider);
9191
(void)IsSegWitOutput(signing_provider, script);
92-
(void)IsSolvable(signing_provider, script);
9392

9493
(void)RecursiveDynamicUsage(script);
9594

src/wallet/rpc/addresses.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ RPCHelpMan getaddressinfo()
578578

579579
if (provider) {
580580
auto inferred = InferDescriptor(scriptPubKey, *provider);
581-
bool solvable = inferred->IsSolvable() || IsSolvable(*provider, scriptPubKey);
581+
bool solvable = inferred->IsSolvable();
582582
ret.pushKV("solvable", solvable);
583583
if (solvable) {
584584
ret.pushKV("desc", inferred->ToString());

src/wallet/scriptpubkeyman.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1456,7 +1456,8 @@ void LegacyScriptPubKeyMan::LearnRelatedScripts(const CPubKey& key, OutputType t
14561456
CTxDestination witdest = WitnessV0KeyHash(key.GetID());
14571457
CScript witprog = GetScriptForDestination(witdest);
14581458
// Make sure the resulting program is solvable.
1459-
assert(IsSolvable(*this, witprog));
1459+
const auto desc = InferDescriptor(witprog, *this);
1460+
assert(desc && desc->IsSolvable());
14601461
AddCScript(witprog);
14611462
}
14621463
}

0 commit comments

Comments
 (0)