aboutsummaryrefslogtreecommitdiff
path: root/src/script/signingprovider.h
blob: f1bded1a8c4cbce1d87a6dd4c65c59e8647b268d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2021 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_SIGNINGPROVIDER_H
#define BITCOIN_SCRIPT_SIGNINGPROVIDER_H

#include <key.h>
#include <pubkey.h>
#include <script/keyorigin.h>
#include <script/script.h>
#include <script/standard.h>
#include <sync.h>

/** An interface to be implemented by keystores that support signing. */
class SigningProvider
{
public:
    virtual ~SigningProvider() {}
    virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
    virtual bool HaveCScript(const CScriptID &scriptid) const { return false; }
    virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; }
    virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; }
    virtual bool HaveKey(const CKeyID &address) const { return false; }
    virtual bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return false; }
    virtual bool GetTaprootSpendData(const XOnlyPubKey& output_key, TaprootSpendData& spenddata) const { return false; }

    bool GetKeyByXOnly(const XOnlyPubKey& pubkey, CKey& key) const
    {
        for (const auto& id : pubkey.GetKeyIDs()) {
            if (GetKey(id, key)) return true;
        }
        return false;
    }

    bool GetPubKeyByXOnly(const XOnlyPubKey& pubkey, CPubKey& out) const
    {
        for (const auto& id : pubkey.GetKeyIDs()) {
            if (GetPubKey(id, out)) return true;
        }
        return false;
    }

    bool GetKeyOriginByXOnly(const XOnlyPubKey& pubkey, KeyOriginInfo& info) const
    {
        for (const auto& id : pubkey.GetKeyIDs()) {
            if (GetKeyOrigin(id, info)) return true;
        }
        return false;
    }
};

extern const SigningProvider& DUMMY_SIGNING_PROVIDER;

class HidingSigningProvider : public SigningProvider
{
private:
    const bool m_hide_secret;
    const bool m_hide_origin;
    const SigningProvider* m_provider;

public:
    HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {}
    bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
    bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
    bool GetKey(const CKeyID& keyid, CKey& key) const override;
    bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
    bool GetTaprootSpendData(const XOnlyPubKey& output_key, TaprootSpendData& spenddata) const override;
};

struct FlatSigningProvider final : public SigningProvider
{
    std::map<CScriptID, CScript> scripts;
    std::map<CKeyID, CPubKey> pubkeys;
    std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> origins;
    std::map<CKeyID, CKey> keys;
    std::map<XOnlyPubKey, TaprootSpendData> tr_spenddata; /** Map from output key to spend data. */

    bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
    bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
    bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
    bool GetKey(const CKeyID& keyid, CKey& key) const override;
    bool GetTaprootSpendData(const XOnlyPubKey& output_key, TaprootSpendData& spenddata) const override;
};

FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b);

/** Fillable signing provider that keeps keys in an address->secret map */
class FillableSigningProvider : public SigningProvider
{
protected:
    using KeyMap = std::map<CKeyID, CKey>;
    using ScriptMap = std::map<CScriptID, CScript>;

    /**
     * Map of key id to unencrypted private keys known by the signing provider.
     * Map may be empty if the provider has another source of keys, like an
     * encrypted store.
     */
    KeyMap mapKeys GUARDED_BY(cs_KeyStore);

    /**
     * Map of script id to scripts known by the signing provider.
     *
     * This map originally just held P2SH redeemScripts, and was used by wallet
     * code to look up script ids referenced in "OP_HASH160 <script id>
     * OP_EQUAL" P2SH outputs. Later in 605e8473a7d it was extended to hold
     * P2WSH witnessScripts as well, and used to look up nested scripts
     * referenced in "OP_0 <script hash>" P2WSH outputs. Later in commits
     * f4691ab3a9d and 248f3a76a82, it was extended once again to hold segwit
     * "OP_0 <key or script hash>" scriptPubKeys, in order to give the wallet a
     * way to distinguish between segwit outputs that it generated addresses for
     * and wanted to receive payments from, and segwit outputs that it never
     * generated addresses for, but it could spend just because of having keys.
     * (Before segwit activation it was also important to not treat segwit
     * outputs to arbitrary wallet keys as payments, because these could be
     * spent by anyone without even needing to sign with the keys.)
     *
     * Some of the scripts stored in mapScripts are memory-only and
     * intentionally not saved to disk. Specifically, scripts added by
     * ImplicitlyLearnRelatedKeyScripts(pubkey) calls are not written to disk so
     * future wallet code can have flexibility to be more selective about what
     * transaction outputs it recognizes as payments, instead of having to treat
     * all outputs spending to keys it knows as payments. By contrast,
     * mapScripts entries added by AddCScript(script),
     * LearnRelatedScripts(pubkey, type), and LearnAllRelatedScripts(pubkey)
     * calls are saved because they are all intentionally used to receive
     * payments.
     *
     * The FillableSigningProvider::mapScripts script map should not be confused
     * with LegacyScriptPubKeyMan::setWatchOnly script set. The two collections
     * can hold the same scripts, but they serve different purposes. The
     * setWatchOnly script set is intended to expand the set of outputs the
     * wallet considers payments. Every output with a script it contains is
     * considered to belong to the wallet, regardless of whether the script is
     * solvable or signable. By contrast, the scripts in mapScripts are only
     * used for solving, and to restrict which outputs are considered payments
     * by the wallet. An output with a script in mapScripts, unlike
     * setWatchOnly, is not automatically considered to belong to the wallet if
     * it can't be solved and signed for.
     */
    ScriptMap mapScripts GUARDED_BY(cs_KeyStore);

    void ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);

public:
    mutable RecursiveMutex cs_KeyStore;

    virtual bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
    virtual bool AddKey(const CKey &key) { return AddKeyPubKey(key, key.GetPubKey()); }
    virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
    virtual bool HaveKey(const CKeyID &address) const override;
    virtual std::set<CKeyID> GetKeys() const;
    virtual bool GetKey(const CKeyID &address, CKey &keyOut) const override;
    virtual bool AddCScript(const CScript& redeemScript);
    virtual bool HaveCScript(const CScriptID &hash) const override;
    virtual std::set<CScriptID> GetCScripts() const;
    virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
};

/** Return the CKeyID of the key involved in a script (if there is a unique one). */
CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest);

#endif // BITCOIN_SCRIPT_SIGNINGPROVIDER_H