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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
crate::ix!();

pub type FillableSigningProviderKeyMap    = HashMap<KeyID,Key>;
pub type FillableSigningProviderScriptMap = HashMap<ScriptID,Script>;

/**
  | Fillable signing provider that keeps
  | keys in an address->secret map
  |
  */
pub struct FillableSigningProvider<T> {
    base:         SigningProvider,
    cs_key_store: Arc<Mutex<FillableSigningProviderInner<T>>>,
}

pub struct FillableSigningProviderInner<T> {

    /**
      | 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.
      |
      */
    map_keys: FillableSigningProviderKeyMap,

    /**
      | 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.
      |
      */
    map_scripts:  FillableSigningProviderScriptMap,

    item: T,
}

impl<T> AddKey for FillableSigningProvider<T> {

    fn add_key(&mut self, key: &Key) -> bool {
        
        todo!();
        /*
            return AddKeyPubKey(key, key.GetPubKey());
        */
    }
}

impl<T> FillableSigningProvider<T> {

    #[EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore)]
    pub fn implicitly_learn_related_key_scripts(&mut self, pubkey: &PubKey)  {
        
        todo!();
        /*
            AssertLockHeld(cs_KeyStore);
        CKeyID key_id = pubkey.GetID();
        // This adds the redeemscripts necessary to detect P2WPKH and P2SH-P2WPKH
        // outputs. Technically P2WPKH outputs don't have a redeemscript to be
        // spent. However, our current IsMine logic requires the corresponding
        // P2SH-P2WPKH redeemscript to be present in the wallet in order to accept
        // payment even to P2WPKH outputs.
        // Also note that having superfluous scripts in the keystore never hurts.
        // They're only used to guide recursion in signing and IsMine logic - if
        // a script is present but we can't do anything with it, it has no effect.
        // "Implicitly" refers to fact that scripts are derived automatically from
        // existing keys, and are present in memory, even without being explicitly
        // loaded (e.g. from a file).
        if (pubkey.IsCompressed()) {
            CScript script = GetScriptForDestination(WitnessV0KeyHash(key_id));
            // This does not use AddCScript, as it may be overridden.
            CScriptID id(script);
            mapScripts[id] = std::move(script);
        }
        */
    }
    
    pub fn get_pub_key(&self, 
        address:         &KeyID,
        vch_pub_key_out: &mut PubKey) -> bool {
        
        todo!();
        /*
            CKey key;
        if (!GetKey(address, key)) {
            return false;
        }
        vchPubKeyOut = key.GetPubKey();
        return true;
        */
    }
    
    pub fn add_key_pub_key(&mut self, 
        key:    &Key,
        pubkey: &PubKey) -> bool {
        
        todo!();
        /*
            LOCK(cs_KeyStore);
        mapKeys[pubkey.GetID()] = key;
        ImplicitlyLearnRelatedKeyScripts(pubkey);
        return true;
        */
    }
    
    pub fn have_key(&self, address: &KeyID) -> bool {
        
        todo!();
        /*
            LOCK(cs_KeyStore);
        return mapKeys.count(address) > 0;
        */
    }
    
    pub fn get_keys(&self) -> HashSet<KeyID> {
        
        todo!();
        /*
            LOCK(cs_KeyStore);
        std::set<CKeyID> set_address;
        for (const auto& mi : mapKeys) {
            set_address.insert(mi.first);
        }
        return set_address;
        */
    }
    
    pub fn get_key(&self, 
        address: &KeyID,
        key_out: &mut Key) -> bool {
        
        todo!();
        /*
            LOCK(cs_KeyStore);
        KeyMap::const_iterator mi = mapKeys.find(address);
        if (mi != mapKeys.end()) {
            keyOut = mi->second;
            return true;
        }
        return false;
        */
    }
    
    pub fn add_script(&mut self, redeem_script: &Script) -> bool {
        
        todo!();
        /*
            if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
            return error("FillableSigningProvider::AddCScript(): redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);

        LOCK(cs_KeyStore);
        mapScripts[CScriptID(redeemScript)] = redeemScript;
        return true;
        */
    }
    
    pub fn have_script(&self, hash: &ScriptID) -> bool {
        
        todo!();
        /*
            LOCK(cs_KeyStore);
        return mapScripts.count(hash) > 0;
        */
    }
    
    pub fn get_scripts(&self) -> HashSet<ScriptID> {
        
        todo!();
        /*
            LOCK(cs_KeyStore);
        std::set<CScriptID> set_script;
        for (const auto& mi : mapScripts) {
            set_script.insert(mi.first);
        }
        return set_script;
        */
    }
    
    pub fn get_script(&self, 
        hash:              &ScriptID,
        redeem_script_out: &mut Script) -> bool {
        
        todo!();
        /*
            LOCK(cs_KeyStore);
        ScriptMap::const_iterator mi = mapScripts.find(hash);
        if (mi != mapScripts.end())
        {
            redeemScriptOut = (*mi).second;
            return true;
        }
        return false;
        */
    }
}