|
10 | 10 | #include <policy/policy.h>
|
11 | 11 | #include <primitives/transaction.h>
|
12 | 12 | #include <script/keyorigin.h>
|
| 13 | +#include <script/miniscript.h> |
13 | 14 | #include <script/signingprovider.h>
|
14 | 15 | #include <script/standard.h>
|
15 | 16 | #include <uint256.h>
|
@@ -381,6 +382,74 @@ static CScript PushAll(const std::vector<valtype>& values)
|
381 | 382 | return result;
|
382 | 383 | }
|
383 | 384 |
|
| 385 | +/** |
| 386 | + * Context for solving a Miniscript. |
| 387 | + * If enough material (access to keys, hash preimages, ..) is given, produces a valid satisfaction. |
| 388 | + */ |
| 389 | +struct Satisfier { |
| 390 | + typedef CPubKey Key; |
| 391 | + |
| 392 | + const SigningProvider& m_provider; |
| 393 | + SignatureData& m_sig_data; |
| 394 | + const BaseSignatureCreator& m_creator; |
| 395 | + const CScript& m_witness_script; |
| 396 | + |
| 397 | + explicit Satisfier(const SigningProvider& provider LIFETIMEBOUND, SignatureData& sig_data LIFETIMEBOUND, |
| 398 | + const BaseSignatureCreator& creator LIFETIMEBOUND, |
| 399 | + const CScript& witscript LIFETIMEBOUND) : m_provider(provider), |
| 400 | + m_sig_data(sig_data), |
| 401 | + m_creator(creator), |
| 402 | + m_witness_script(witscript) {} |
| 403 | + |
| 404 | + static bool KeyCompare(const Key& a, const Key& b) { |
| 405 | + return a < b; |
| 406 | + } |
| 407 | + |
| 408 | + //! Conversion from a raw public key. |
| 409 | + template <typename I> |
| 410 | + std::optional<Key> FromPKBytes(I first, I last) const |
| 411 | + { |
| 412 | + Key pubkey{first, last}; |
| 413 | + if (pubkey.IsValid()) return pubkey; |
| 414 | + return {}; |
| 415 | + } |
| 416 | + |
| 417 | + //! Conversion from a raw public key hash. |
| 418 | + template<typename I> |
| 419 | + std::optional<Key> FromPKHBytes(I first, I last) const { |
| 420 | + assert(last - first == 20); |
| 421 | + Key pubkey; |
| 422 | + CKeyID key_id; |
| 423 | + std::copy(first, last, key_id.begin()); |
| 424 | + if (GetPubKey(m_provider, m_sig_data, key_id, pubkey)) return pubkey; |
| 425 | + m_sig_data.missing_pubkeys.push_back(key_id); |
| 426 | + return {}; |
| 427 | + } |
| 428 | + |
| 429 | + //! Conversion to raw public key. |
| 430 | + std::vector<unsigned char> ToPKBytes(const CPubKey& key) const { return {key.begin(), key.end()}; } |
| 431 | + |
| 432 | + //! Satisfy a signature check. |
| 433 | + miniscript::Availability Sign(const CPubKey& key, std::vector<unsigned char>& sig) const { |
| 434 | + if (CreateSig(m_creator, m_sig_data, m_provider, sig, key, m_witness_script, SigVersion::WITNESS_V0)) { |
| 435 | + return miniscript::Availability::YES; |
| 436 | + } |
| 437 | + return miniscript::Availability::NO; |
| 438 | + } |
| 439 | + |
| 440 | + //! Time lock satisfactions. |
| 441 | + // TODO |
| 442 | + bool CheckAfter(uint32_t value) const { return false; } |
| 443 | + bool CheckOlder(uint32_t value) const { return false; } |
| 444 | + |
| 445 | + //! Hash preimage satisfactions. |
| 446 | + // TODO |
| 447 | + miniscript::Availability SatSHA256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return miniscript::Availability::NO; } |
| 448 | + miniscript::Availability SatRIPEMD160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return miniscript::Availability::NO; } |
| 449 | + miniscript::Availability SatHASH256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return miniscript::Availability::NO; } |
| 450 | + miniscript::Availability SatHASH160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return miniscript::Availability::NO; } |
| 451 | +}; |
| 452 | + |
384 | 453 | bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata)
|
385 | 454 | {
|
386 | 455 | if (sigdata.complete) return true;
|
@@ -416,9 +485,21 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
|
416 | 485 | {
|
417 | 486 | CScript witnessscript(result[0].begin(), result[0].end());
|
418 | 487 | sigdata.witness_script = witnessscript;
|
419 |
| - TxoutType subType; |
| 488 | + |
| 489 | + TxoutType subType{TxoutType::NONSTANDARD}; |
420 | 490 | solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata) && subType != TxoutType::SCRIPTHASH && subType != TxoutType::WITNESS_V0_SCRIPTHASH && subType != TxoutType::WITNESS_V0_KEYHASH;
|
| 491 | + |
| 492 | + // If we couldn't find a solution with the legacy satisfier, try satisfying the script using Miniscript. |
| 493 | + // Note we need to check if the result stack is empty before, because it might be used even if the Script |
| 494 | + // isn't fully solved. For instance the CHECKMULTISIG satisfaction in SignStep() pushes partial signatures |
| 495 | + // and the extractor relies on this behaviour to combine witnesses. |
| 496 | + if (!solved && result.empty()) { |
| 497 | + Satisfier ms_satisfier{provider, sigdata, creator, witnessscript}; |
| 498 | + const auto ms = miniscript::FromScript(witnessscript, ms_satisfier); |
| 499 | + solved = ms && ms->Satisfy(ms_satisfier, result) == miniscript::Availability::YES; |
| 500 | + } |
421 | 501 | result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end()));
|
| 502 | + |
422 | 503 | sigdata.scriptWitness.stack = result;
|
423 | 504 | sigdata.witness = true;
|
424 | 505 | result.clear();
|
@@ -592,8 +673,8 @@ class DummySignatureChecker final : public BaseSignatureChecker
|
592 | 673 | {
|
593 | 674 | public:
|
594 | 675 | DummySignatureChecker() = default;
|
595 |
| - bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return true; } |
596 |
| - bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) const override { return true; } |
| 676 | + bool CheckECDSASignature(const std::vector<unsigned char>& sig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return sig.size() != 0; } |
| 677 | + bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) const override { return sig.size() != 0; } |
597 | 678 | };
|
598 | 679 | }
|
599 | 680 |
|
|
0 commit comments