1 // Copyright (c) 2018-2019 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <interfaces/wallet.h>
6 
7 #include <amount.h>
8 #include <interfaces/chain.h>
9 #include <interfaces/handler.h>
10 #include <policy/fees.h>
11 #include <primitives/transaction.h>
12 #include <script/standard.h>
13 #include <support/allocators/secure.h>
14 #include <sync.h>
15 #include <ui_interface.h>
16 #include <uint256.h>
17 #include <util/system.h>
18 #include <wallet/feebumper.h>
19 #include <wallet/fees.h>
20 #include <wallet/ismine.h>
21 #include <wallet/load.h>
22 #include <wallet/rpcwallet.h>
23 #include <wallet/wallet.h>
24 #include <key_io.h>
25 #include <qtum/qtumdelegation.h>
26 #include <miner.h>
27 
28 #include <memory>
29 #include <string>
30 #include <utility>
31 #include <vector>
32 #include <algorithm>
33 
34 namespace interfaces {
35 namespace {
36 
37 //! Construct wallet tx struct.
MakeWalletTx(CWallet & wallet,const CWalletTx & wtx)38 WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
39 {
40     WalletTx result;
41     result.tx = wtx.tx;
42     result.txin_is_mine.reserve(wtx.tx->vin.size());
43     for (const auto& txin : wtx.tx->vin) {
44         result.txin_is_mine.emplace_back(wallet.IsMine(txin));
45     }
46     result.txout_is_mine.reserve(wtx.tx->vout.size());
47     result.txout_address.reserve(wtx.tx->vout.size());
48     result.txout_address_is_mine.reserve(wtx.tx->vout.size());
49     for (const auto& txout : wtx.tx->vout) {
50         result.txout_is_mine.emplace_back(wallet.IsMine(txout));
51         result.txout_address.emplace_back();
52         result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ?
53                                                       wallet.IsMine(result.txout_address.back()) :
54                                                       ISMINE_NO);
55     }
56     result.credit = wtx.GetCredit(ISMINE_ALL);
57     result.debit = wtx.GetDebit(ISMINE_ALL);
58     result.change = wtx.GetChange();
59     result.time = wtx.GetTxTime();
60     result.value_map = wtx.mapValue;
61     result.is_coinbase = wtx.IsCoinBase();
62     result.is_coinstake = wtx.IsCoinStake();
63     result.is_in_main_chain = wtx.IsInMainChain();
64     result.has_create_or_call = wtx.tx->HasCreateOrCall();
65     if(result.has_create_or_call)
66     {
67         LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
68         CTxDestination tx_sender_address;
69         if(wtx.tx && wtx.tx->vin.size() > 0 && wallet.mapWallet.find(wtx.tx->vin[0].prevout.hash) != wallet.mapWallet.end() &&
70                 ExtractDestination(wallet.mapWallet.at(wtx.tx->vin[0].prevout.hash).tx->vout[wtx.tx->vin[0].prevout.n].scriptPubKey, tx_sender_address)) {
71             result.tx_sender_key = GetKeyForDestination(*spk_man, tx_sender_address);
72         }
73 
74         for(CTxDestination address : result.txout_address) {
75             result.txout_keys.emplace_back(GetKeyForDestination(*spk_man, address));
76         }
77     }
78     return result;
79 }
80 
81 //! Construct wallet tx status struct.
MakeWalletTxStatus(interfaces::Chain::Lock & locked_chain,const CWalletTx & wtx)82 WalletTxStatus MakeWalletTxStatus(interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx)
83 {
84     WalletTxStatus result;
85     result.block_height = locked_chain.getBlockHeight(wtx.m_confirm.hashBlock).get_value_or(std::numeric_limits<int>::max());
86     result.blocks_to_maturity = wtx.GetBlocksToMaturity();
87     result.depth_in_main_chain = wtx.GetDepthInMainChain();
88     result.time_received = wtx.nTimeReceived;
89     result.lock_time = wtx.tx->nLockTime;
90     result.is_final = locked_chain.checkFinalTx(*wtx.tx);
91     result.is_trusted = wtx.IsTrusted(locked_chain);
92     result.is_abandoned = wtx.isAbandoned();
93     result.is_coinbase = wtx.IsCoinBase();
94     result.is_in_main_chain = wtx.IsInMainChain();
95     result.is_coinstake = wtx.IsCoinStake();
96     return result;
97 }
98 
99 //! Construct wallet TxOut struct.
MakeWalletTxOut(CWallet & wallet,const CWalletTx & wtx,int n,int depth)100 WalletTxOut MakeWalletTxOut(CWallet& wallet,
101     const CWalletTx& wtx,
102     int n,
103     int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
104 {
105     WalletTxOut result;
106     result.txout = wtx.tx->vout[n];
107     result.time = wtx.GetTxTime();
108     result.depth_in_main_chain = depth;
109     result.is_spent = wallet.IsSpent(wtx.GetHash(), n);
110     return result;
111 }
112 
113 //! Construct token info.
MakeTokenInfo(const TokenInfo & token)114 CTokenInfo MakeTokenInfo(const TokenInfo& token)
115 {
116     CTokenInfo result;
117     result.strContractAddress = token.contract_address;
118     result.strTokenName = token.token_name;
119     result.strTokenSymbol = token.token_symbol;
120     result.nDecimals = token.decimals;
121     result.strSenderAddress = token.sender_address;
122     result.nCreateTime = token.time;
123     result.blockHash = token.block_hash;
124     result.blockNumber = token.block_number;
125     return result;
126 }
127 
128 //! Construct wallet token info.
MakeWalletTokenInfo(const CTokenInfo & token)129 TokenInfo MakeWalletTokenInfo(const CTokenInfo& token)
130 {
131     TokenInfo result;
132     result.contract_address = token.strContractAddress;
133     result.token_name = token.strTokenName;
134     result.token_symbol = token.strTokenSymbol;
135     result.decimals = token.nDecimals;
136     result.sender_address = token.strSenderAddress;
137     result.time = token.nCreateTime;
138     result.block_hash = token.blockHash;
139     result.block_number = token.blockNumber;
140     result.hash = token.GetHash();
141     return result;
142 }
143 
144 //! Construct token transaction.
MakeTokenTx(const TokenTx & tokenTx)145 CTokenTx MakeTokenTx(const TokenTx& tokenTx)
146 {
147     CTokenTx result;
148     result.strContractAddress = tokenTx.contract_address;
149     result.strSenderAddress = tokenTx.sender_address;
150     result.strReceiverAddress = tokenTx.receiver_address;
151     result.nValue = tokenTx.value;
152     result.transactionHash = tokenTx.tx_hash;
153     result.nCreateTime = tokenTx.time;
154     result.blockHash = tokenTx.block_hash;
155     result.blockNumber = tokenTx.block_number;
156     result.strLabel = tokenTx.label;
157     return result;
158 }
159 
160 //! Construct wallet token transaction.
MakeWalletTokenTx(const CTokenTx & tokenTx)161 TokenTx MakeWalletTokenTx(const CTokenTx& tokenTx)
162 {
163     TokenTx result;
164     result.contract_address = tokenTx.strContractAddress;
165     result.sender_address = tokenTx.strSenderAddress;
166     result.receiver_address = tokenTx.strReceiverAddress;
167     result.value = tokenTx.nValue;
168     result.tx_hash = tokenTx.transactionHash;
169     result.time = tokenTx.nCreateTime;
170     result.block_hash = tokenTx.blockHash;
171     result.block_number = tokenTx.blockNumber;
172     result.label = tokenTx.strLabel;
173     result.hash = tokenTx.GetHash();
174     return result;
175 }
176 
MakeContractBook(const std::string & id,const CContractBookData & data)177 ContractBookData MakeContractBook(const std::string& id, const CContractBookData& data)
178 {
179     ContractBookData result;
180     result.address = id;
181     result.name = data.name;
182     result.abi = data.abi;
183     return result;
184 }
185 
StringToKeyId(const std::string & strAddress)186 uint160 StringToKeyId(const std::string& strAddress)
187 {
188     CTxDestination dest = DecodeDestination(strAddress);
189     const PKHash *keyID = boost::get<PKHash>(&dest);
190     if(keyID)
191     {
192         return uint160(*keyID);
193     }
194     return uint160();
195 }
196 
KeyIdToString(const uint160 & keyID)197 std::string KeyIdToString(const uint160& keyID)
198 {
199     return EncodeDestination(PKHash(keyID));
200 }
201 
StringToKeyIdList(const std::vector<std::string> & listAddress)202 std::vector<uint160> StringToKeyIdList(const std::vector<std::string>& listAddress)
203 {
204     std::vector<uint160> ret;
205     for(auto address : listAddress)
206     {
207         ret.push_back(StringToKeyId(address));
208     }
209     return ret;
210 }
211 
KeyIdToStringList(const std::vector<uint160> & listKeyID)212 std::vector<std::string> KeyIdToStringList(const std::vector<uint160>& listKeyID)
213 {
214     std::vector<std::string> ret;
215     for(auto keyId : listKeyID)
216     {
217         ret.push_back(KeyIdToString(keyId));
218     }
219     return ret;
220 }
221 
222 //! Construct delegation info.
MakeDelegationInfo(const DelegationInfo & delegation)223 CDelegationInfo MakeDelegationInfo(const DelegationInfo& delegation)
224 {
225     CDelegationInfo result;
226     result.delegateAddress = StringToKeyId(delegation.delegate_address);
227     result.stakerAddress = StringToKeyId(delegation.staker_address);
228     result.strStakerName = delegation.staker_name;
229     result.nFee = delegation.fee;
230     result.nCreateTime = delegation.time;
231     result.blockNumber = delegation.block_number;
232     result.createTxHash = delegation.create_tx_hash;
233     result.removeTxHash = delegation.remove_tx_hash;
234     return result;
235 }
236 
237 //! Construct wallet delegation info.
MakeWalletDelegationInfo(const CDelegationInfo & delegation)238 DelegationInfo MakeWalletDelegationInfo(const CDelegationInfo& delegation)
239 {
240     DelegationInfo result;
241     result.delegate_address = KeyIdToString(delegation.delegateAddress);
242     result.staker_address = KeyIdToString(delegation.stakerAddress);
243     result.staker_name = delegation.strStakerName;
244     result.fee = delegation.nFee;
245     result.time = delegation.nCreateTime;
246     result.block_number = delegation.blockNumber;
247     result.time = delegation.nCreateTime;
248     result.create_tx_hash = delegation.createTxHash;
249     result.remove_tx_hash = delegation.removeTxHash;
250     result.hash = delegation.GetHash();
251     return result;
252 }
253 
254 //! Construct super staker info.
MakeSuperStakerInfo(const SuperStakerInfo & superStaker)255 CSuperStakerInfo MakeSuperStakerInfo(const SuperStakerInfo& superStaker)
256 {
257     CSuperStakerInfo result;
258     result.stakerAddress = StringToKeyId(superStaker.staker_address);
259     result.strStakerName = superStaker.staker_name;
260     result.nMinFee = superStaker.min_fee;
261     result.nCreateTime = superStaker.time;
262     result.fCustomConfig = superStaker.custom_config;
263     result.nMinDelegateUtxo = superStaker.min_delegate_utxo;
264     result.delegateAddressList = StringToKeyIdList(superStaker.delegate_address_list);
265     result.nDelegateAddressType = superStaker.delegate_address_type;
266     return result;
267 }
268 
269 //! Construct wallet super staker info.
MakeWalletSuperStakerInfo(const CSuperStakerInfo & superStaker)270 SuperStakerInfo MakeWalletSuperStakerInfo(const CSuperStakerInfo& superStaker)
271 {
272     SuperStakerInfo result;
273     result.staker_address = KeyIdToString(superStaker.stakerAddress);
274     result.staker_name = superStaker.strStakerName;
275     result.min_fee = superStaker.nMinFee;
276     result.time = superStaker.nCreateTime;
277     result.custom_config = superStaker.fCustomConfig;
278     result.min_delegate_utxo = superStaker.nMinDelegateUtxo;
279     result.delegate_address_list = KeyIdToStringList(superStaker.delegateAddressList);
280     result.delegate_address_type = superStaker.nDelegateAddressType;
281     result.hash = superStaker.GetHash();
282     return result;
283 }
284 
285 //! Construct wallet delegation staker info.
MakeWalletDelegationStakerInfo(interfaces::Chain::Lock & locked_chain,CWallet & wallet,const uint160 & id,const Delegation & delegation)286 DelegationStakerInfo MakeWalletDelegationStakerInfo(interfaces::Chain::Lock& locked_chain, CWallet& wallet, const uint160& id, const Delegation& delegation)
287 {
288     DelegationStakerInfo result;
289     result.delegate_address = EncodeDestination(PKHash(id));
290     result.staker_address = EncodeDestination(PKHash(delegation.staker));
291     result.PoD = HexStr(delegation.PoD);
292     result.fee = delegation.fee;
293     result.time = locked_chain.getBlockTime(delegation.blockHeight);
294     result.block_number = delegation.blockHeight;
295     std::map<uint160, CAmount>::iterator it = wallet.m_delegations_weight.find(id);
296     if(it != wallet.m_delegations_weight.end())
297     {
298         result.weight = it->second;
299     }
300     result.hash = id;
301     return result;
302 }
303 
TokenTxStatus(interfaces::Chain::Lock & locked_chain,CWallet & wallet,const uint256 & txid,int & block_number,bool & in_mempool,int & num_blocks)304 bool TokenTxStatus(interfaces::Chain::Lock& locked_chain, CWallet& wallet, const uint256& txid, int& block_number, bool& in_mempool, int& num_blocks)
305 {
306     auto mi = wallet.mapTokenTx.find(txid);
307     if (mi == wallet.mapTokenTx.end()) {
308         return false;
309     }
310     block_number = mi->second.blockNumber;
311     auto it = wallet.mapWallet.find(mi->second.transactionHash);
312     if(it != wallet.mapWallet.end())
313     {
314         in_mempool = it->second.InMempool();
315     }
316     if (Optional<int> height = locked_chain.getHeight()) {
317         num_blocks = *height;
318     } else {
319         num_blocks = -1;
320     }
321     return true;
322 }
323 
324 class WalletImpl : public Wallet
325 {
326 public:
WalletImpl(const std::shared_ptr<CWallet> & wallet)327     explicit WalletImpl(const std::shared_ptr<CWallet>& wallet) : m_wallet(wallet) {}
328 
encryptWallet(const SecureString & wallet_passphrase)329     bool encryptWallet(const SecureString& wallet_passphrase) override
330     {
331         return m_wallet->EncryptWallet(wallet_passphrase);
332     }
isCrypted()333     bool isCrypted() override { return m_wallet->IsCrypted(); }
lock()334     bool lock() override { return m_wallet->Lock(); }
unlock(const SecureString & wallet_passphrase)335     bool unlock(const SecureString& wallet_passphrase) override { return m_wallet->Unlock(wallet_passphrase); }
isLocked()336     bool isLocked() override { return m_wallet->IsLocked(); }
changeWalletPassphrase(const SecureString & old_wallet_passphrase,const SecureString & new_wallet_passphrase)337     bool changeWalletPassphrase(const SecureString& old_wallet_passphrase,
338         const SecureString& new_wallet_passphrase) override
339     {
340         return m_wallet->ChangeWalletPassphrase(old_wallet_passphrase, new_wallet_passphrase);
341     }
abortRescan()342     void abortRescan() override { m_wallet->AbortRescan(); }
backupWallet(const std::string & filename)343     bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); }
getWalletName()344     std::string getWalletName() override { return m_wallet->GetName(); }
getNewDestination(const OutputType type,const std::string label,CTxDestination & dest)345     bool getNewDestination(const OutputType type, const std::string label, CTxDestination& dest) override
346     {
347         LOCK(m_wallet->cs_wallet);
348         std::string error;
349         return m_wallet->GetNewDestination(type, label, dest, error);
350     }
getPubKey(const CScript & script,const CKeyID & address,CPubKey & pub_key)351     bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) override
352     {
353         std::unique_ptr<SigningProvider> provider = m_wallet->GetSolvingProvider(script);
354         if (provider) {
355             return provider->GetPubKey(address, pub_key);
356         }
357         return false;
358     }
signMessage(const std::string & message,const PKHash & pkhash,std::string & str_sig)359     SigningResult signMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) override
360     {
361         return m_wallet->SignMessage(message, pkhash, str_sig);
362     }
isSpendable(const CTxDestination & dest)363     bool isSpendable(const CTxDestination& dest) override { return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; }
haveWatchOnly()364     bool haveWatchOnly() override
365     {
366         auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
367         if (spk_man) {
368             return spk_man->HaveWatchOnly();
369         }
370         return false;
371     };
setAddressBook(const CTxDestination & dest,const std::string & name,const std::string & purpose)372     bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::string& purpose) override
373     {
374         return m_wallet->SetAddressBook(dest, name, purpose);
375     }
delAddressBook(const CTxDestination & dest)376     bool delAddressBook(const CTxDestination& dest) override
377     {
378         return m_wallet->DelAddressBook(dest);
379     }
getAddress(const CTxDestination & dest,std::string * name,isminetype * is_mine,std::string * purpose)380     bool getAddress(const CTxDestination& dest,
381         std::string* name,
382         isminetype* is_mine,
383         std::string* purpose) override
384     {
385         LOCK(m_wallet->cs_wallet);
386         auto it = m_wallet->m_address_book.find(dest);
387         if (it == m_wallet->m_address_book.end() || it->second.IsChange()) {
388             return false;
389         }
390         if (name) {
391             *name = it->second.GetLabel();
392         }
393         if (is_mine) {
394             *is_mine = m_wallet->IsMine(dest);
395         }
396         if (purpose) {
397             *purpose = it->second.purpose;
398         }
399         return true;
400     }
getAddresses()401     std::vector<WalletAddress> getAddresses() override
402     {
403         LOCK(m_wallet->cs_wallet);
404         std::vector<WalletAddress> result;
405         for (const auto& item : m_wallet->m_address_book) {
406             if (item.second.IsChange()) continue;
407             result.emplace_back(item.first, m_wallet->IsMine(item.first), item.second.GetLabel(), item.second.purpose);
408         }
409         return result;
410     }
addDestData(const CTxDestination & dest,const std::string & key,const std::string & value)411     bool addDestData(const CTxDestination& dest, const std::string& key, const std::string& value) override
412     {
413         LOCK(m_wallet->cs_wallet);
414         WalletBatch batch{m_wallet->GetDatabase()};
415         return m_wallet->AddDestData(batch, dest, key, value);
416     }
eraseDestData(const CTxDestination & dest,const std::string & key)417     bool eraseDestData(const CTxDestination& dest, const std::string& key) override
418     {
419         LOCK(m_wallet->cs_wallet);
420         WalletBatch batch{m_wallet->GetDatabase()};
421         return m_wallet->EraseDestData(batch, dest, key);
422     }
getDestValues(const std::string & prefix)423     std::vector<std::string> getDestValues(const std::string& prefix) override
424     {
425         LOCK(m_wallet->cs_wallet);
426         return m_wallet->GetDestValues(prefix);
427     }
lockCoin(const COutPoint & output)428     void lockCoin(const COutPoint& output) override
429     {
430         auto locked_chain = m_wallet->chain().lock();
431         LOCK(m_wallet->cs_wallet);
432         return m_wallet->LockCoin(output);
433     }
unlockCoin(const COutPoint & output)434     void unlockCoin(const COutPoint& output) override
435     {
436         auto locked_chain = m_wallet->chain().lock();
437         LOCK(m_wallet->cs_wallet);
438         return m_wallet->UnlockCoin(output);
439     }
isLockedCoin(const COutPoint & output)440     bool isLockedCoin(const COutPoint& output) override
441     {
442         auto locked_chain = m_wallet->chain().lock();
443         LOCK(m_wallet->cs_wallet);
444         return m_wallet->IsLockedCoin(output.hash, output.n);
445     }
listLockedCoins(std::vector<COutPoint> & outputs)446     void listLockedCoins(std::vector<COutPoint>& outputs) override
447     {
448         auto locked_chain = m_wallet->chain().lock();
449         LOCK(m_wallet->cs_wallet);
450         return m_wallet->ListLockedCoins(outputs);
451     }
createTransaction(const std::vector<CRecipient> & recipients,const CCoinControl & coin_control,bool sign,int & change_pos,CAmount & fee,std::string & fail_reason)452     CTransactionRef createTransaction(const std::vector<CRecipient>& recipients,
453         const CCoinControl& coin_control,
454         bool sign,
455         int& change_pos,
456         CAmount& fee,
457         std::string& fail_reason) override
458     {
459         auto locked_chain = m_wallet->chain().lock();
460         LOCK(m_wallet->cs_wallet);
461         CTransactionRef tx;
462         if (!m_wallet->CreateTransaction(*locked_chain, recipients, tx, fee, change_pos,
463                 fail_reason, coin_control, sign)) {
464             return {};
465         }
466         return tx;
467     }
commitTransaction(CTransactionRef tx,WalletValueMap value_map,WalletOrderForm order_form)468     void commitTransaction(CTransactionRef tx,
469         WalletValueMap value_map,
470         WalletOrderForm order_form) override
471     {
472         auto locked_chain = m_wallet->chain().lock();
473         LOCK(m_wallet->cs_wallet);
474         m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form));
475     }
transactionCanBeAbandoned(const uint256 & txid)476     bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet->TransactionCanBeAbandoned(txid); }
abandonTransaction(const uint256 & txid)477     bool abandonTransaction(const uint256& txid) override
478     {
479         auto locked_chain = m_wallet->chain().lock();
480         LOCK(m_wallet->cs_wallet);
481         return m_wallet->AbandonTransaction(txid);
482     }
transactionCanBeBumped(const uint256 & txid)483     bool transactionCanBeBumped(const uint256& txid) override
484     {
485         return feebumper::TransactionCanBeBumped(*m_wallet.get(), txid);
486     }
createBumpTransaction(const uint256 & txid,const CCoinControl & coin_control,std::vector<std::string> & errors,CAmount & old_fee,CAmount & new_fee,CMutableTransaction & mtx)487     bool createBumpTransaction(const uint256& txid,
488         const CCoinControl& coin_control,
489         std::vector<std::string>& errors,
490         CAmount& old_fee,
491         CAmount& new_fee,
492         CMutableTransaction& mtx) override
493     {
494         return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx) == feebumper::Result::OK;
495     }
signBumpTransaction(CMutableTransaction & mtx)496     bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(*m_wallet.get(), mtx); }
commitBumpTransaction(const uint256 & txid,CMutableTransaction && mtx,std::vector<std::string> & errors,uint256 & bumped_txid)497     bool commitBumpTransaction(const uint256& txid,
498         CMutableTransaction&& mtx,
499         std::vector<std::string>& errors,
500         uint256& bumped_txid) override
501     {
502         return feebumper::CommitTransaction(*m_wallet.get(), txid, std::move(mtx), errors, bumped_txid) ==
503                feebumper::Result::OK;
504     }
getTx(const uint256 & txid)505     CTransactionRef getTx(const uint256& txid) override
506     {
507         auto locked_chain = m_wallet->chain().lock();
508         LOCK(m_wallet->cs_wallet);
509         auto mi = m_wallet->mapWallet.find(txid);
510         if (mi != m_wallet->mapWallet.end()) {
511             return mi->second.tx;
512         }
513         return {};
514     }
getWalletTx(const uint256 & txid)515     WalletTx getWalletTx(const uint256& txid) override
516     {
517         auto locked_chain = m_wallet->chain().lock();
518         LOCK(m_wallet->cs_wallet);
519         auto mi = m_wallet->mapWallet.find(txid);
520         if (mi != m_wallet->mapWallet.end()) {
521             return MakeWalletTx(*m_wallet, mi->second);
522         }
523         return {};
524     }
getWalletTxs()525     std::vector<WalletTx> getWalletTxs() override
526     {
527         auto locked_chain = m_wallet->chain().lock();
528         LOCK(m_wallet->cs_wallet);
529         std::vector<WalletTx> result;
530         result.reserve(m_wallet->mapWallet.size());
531         for (const auto& entry : m_wallet->mapWallet) {
532             result.emplace_back(MakeWalletTx(*m_wallet, entry.second));
533         }
534         return result;
535     }
tryGetTxStatus(const uint256 & txid,interfaces::WalletTxStatus & tx_status,int & num_blocks,int64_t & block_time)536     bool tryGetTxStatus(const uint256& txid,
537         interfaces::WalletTxStatus& tx_status,
538         int& num_blocks,
539         int64_t& block_time) override
540     {
541         auto locked_chain = m_wallet->chain().lock(true /* try_lock */);
542         if (!locked_chain) {
543             return false;
544         }
545         TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
546         if (!locked_wallet) {
547             return false;
548         }
549         auto mi = m_wallet->mapWallet.find(txid);
550         if (mi == m_wallet->mapWallet.end()) {
551             return false;
552         }
553         if (Optional<int> height = locked_chain->getHeight()) {
554             num_blocks = *height;
555             block_time = locked_chain->getBlockTime(*height);
556         } else {
557             num_blocks = -1;
558             block_time = -1;
559         }
560         tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
561         return true;
562     }
getWalletTxDetails(const uint256 & txid,WalletTxStatus & tx_status,WalletOrderForm & order_form,bool & in_mempool,int & num_blocks)563     WalletTx getWalletTxDetails(const uint256& txid,
564         WalletTxStatus& tx_status,
565         WalletOrderForm& order_form,
566         bool& in_mempool,
567         int& num_blocks) override
568     {
569         auto locked_chain = m_wallet->chain().lock();
570         LOCK(m_wallet->cs_wallet);
571         auto mi = m_wallet->mapWallet.find(txid);
572         if (mi != m_wallet->mapWallet.end()) {
573             num_blocks = locked_chain->getHeight().get_value_or(-1);
574             in_mempool = mi->second.InMempool();
575             order_form = mi->second.vOrderForm;
576             tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
577             return MakeWalletTx(*m_wallet, mi->second);
578         }
579         return {};
580     }
fillPSBT(int sighash_type,bool sign,bool bip32derivs,PartiallySignedTransaction & psbtx,bool & complete)581     TransactionError fillPSBT(int sighash_type,
582         bool sign,
583         bool bip32derivs,
584         PartiallySignedTransaction& psbtx,
585         bool& complete) override
586     {
587         return m_wallet->FillPSBT(psbtx, complete, sighash_type, sign, bip32derivs);
588     }
getBalances()589     WalletBalances getBalances() override
590     {
591         const auto bal = m_wallet->GetBalance();
592         WalletBalances result;
593         result.balance = bal.m_mine_trusted;
594         result.unconfirmed_balance = bal.m_mine_untrusted_pending;
595         result.immature_balance = bal.m_mine_immature;
596         result.stake = bal.m_mine_stake;
597         result.have_watch_only = haveWatchOnly();
598         if (result.have_watch_only) {
599             result.watch_only_balance = bal.m_watchonly_trusted;
600             result.unconfirmed_watch_only_balance = bal.m_watchonly_untrusted_pending;
601             result.immature_watch_only_balance = bal.m_watchonly_immature;
602             result.watch_only_stake = bal.m_watchonly_stake;
603         }
604         return result;
605     }
tryGetBalances(WalletBalances & balances,int & num_blocks,bool force,int cached_num_blocks)606     bool tryGetBalances(WalletBalances& balances, int& num_blocks, bool force, int cached_num_blocks) override
607     {
608         auto locked_chain = m_wallet->chain().lock(true /* try_lock */);
609         if (!locked_chain) return false;
610         num_blocks = locked_chain->getHeight().get_value_or(-1);
611         if (!force && num_blocks == cached_num_blocks) return false;
612         TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
613         if (!locked_wallet) {
614             return false;
615         }
616         balances = getBalances();
617         return true;
618     }
getBalance()619     CAmount getBalance() override { return m_wallet->GetBalance().m_mine_trusted; }
getAvailableBalance(const CCoinControl & coin_control)620     CAmount getAvailableBalance(const CCoinControl& coin_control) override
621     {
622         return m_wallet->GetAvailableBalance(&coin_control);
623     }
txinIsMine(const CTxIn & txin)624     isminetype txinIsMine(const CTxIn& txin) override
625     {
626         auto locked_chain = m_wallet->chain().lock();
627         LOCK(m_wallet->cs_wallet);
628         return m_wallet->IsMine(txin);
629     }
txoutIsMine(const CTxOut & txout)630     isminetype txoutIsMine(const CTxOut& txout) override
631     {
632         auto locked_chain = m_wallet->chain().lock();
633         LOCK(m_wallet->cs_wallet);
634         return m_wallet->IsMine(txout);
635     }
getDebit(const CTxIn & txin,isminefilter filter)636     CAmount getDebit(const CTxIn& txin, isminefilter filter) override
637     {
638         auto locked_chain = m_wallet->chain().lock();
639         LOCK(m_wallet->cs_wallet);
640         return m_wallet->GetDebit(txin, filter);
641     }
getCredit(const CTxOut & txout,isminefilter filter)642     CAmount getCredit(const CTxOut& txout, isminefilter filter) override
643     {
644         auto locked_chain = m_wallet->chain().lock();
645         LOCK(m_wallet->cs_wallet);
646         return m_wallet->GetCredit(txout, filter);
647     }
isUnspentAddress(const std::string & qtumAddress)648     bool isUnspentAddress(const std::string &qtumAddress) override
649     {
650         auto locked_chain = m_wallet->chain().lock();
651         LOCK(m_wallet->cs_wallet);
652 
653         std::vector<COutput> vecOutputs;
654         m_wallet->AvailableCoins(*locked_chain, vecOutputs);
655         for (const COutput& out : vecOutputs)
656         {
657             CTxDestination address;
658             const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
659             bool fValidAddress = ExtractDestination(scriptPubKey, address);
660 
661             if(fValidAddress && EncodeDestination(address) == qtumAddress && out.tx->tx->vout[out.i].nValue)
662             {
663                 return true;
664             }
665         }
666         return false;
667     }
isMineAddress(const std::string & strAddress)668     bool isMineAddress(const std::string &strAddress) override
669     {
670         CTxDestination address = DecodeDestination(strAddress);
671         if(!IsValidDestination(address) || !m_wallet->IsMine(address))
672         {
673             return false;
674         }
675         return true;
676     }
availableAddresses(interfaces::Chain::Lock & locked_chain,bool fIncludeZeroValue)677     std::vector<std::string> availableAddresses(interfaces::Chain::Lock& locked_chain, bool fIncludeZeroValue)
678     {
679         std::vector<std::string> result;
680         std::vector<COutput> vecOutputs;
681         std::map<std::string, bool> mapAddress;
682 
683         if(fIncludeZeroValue)
684         {
685             // Get the user created addresses in from the address book and add them if they are mine
686             for (const auto& item : m_wallet->m_address_book) {
687                 if(!m_wallet->IsMine(item.first)) continue;
688 
689                 std::string strAddress = EncodeDestination(item.first);
690                 if (mapAddress.find(strAddress) == mapAddress.end())
691                 {
692                     mapAddress[strAddress] = true;
693                     result.push_back(strAddress);
694                 }
695             }
696 
697             // Get all coins including the 0 values
698             m_wallet->AvailableCoins(locked_chain, vecOutputs, false, nullptr, 0);
699         }
700         else
701         {
702             // Get all spendable coins
703             m_wallet->AvailableCoins(locked_chain, vecOutputs);
704         }
705 
706         // Extract all coins addresses and add them in the list
707         for (const COutput& out : vecOutputs)
708         {
709             CTxDestination address;
710             const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
711             bool fValidAddress = ExtractDestination(scriptPubKey, address);
712 
713             if (!fValidAddress || !m_wallet->IsMine(address)) continue;
714 
715             std::string strAddress = EncodeDestination(address);
716             if (mapAddress.find(strAddress) == mapAddress.end())
717             {
718                 mapAddress[strAddress] = true;
719                 result.push_back(strAddress);
720             }
721         }
722 
723         return result;
724     }
tryGetAvailableAddresses(std::vector<std::string> & spendableAddresses,std::vector<std::string> & allAddresses,bool & includeZeroValue)725     bool tryGetAvailableAddresses(std::vector<std::string> &spendableAddresses, std::vector<std::string> &allAddresses, bool &includeZeroValue) override
726     {
727         auto locked_chain = m_wallet->chain().lock(true);
728         if (!locked_chain) return false;
729         TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
730         if (!locked_wallet) {
731             return false;
732         }
733 
734         spendableAddresses = availableAddresses(*locked_chain, false);
735         allAddresses = availableAddresses(*locked_chain, true);
736         int num_blocks = locked_chain->getHeight().get_value_or(-1);
737         includeZeroValue = num_blocks >= Params().GetConsensus().QIP5Height;
738 
739         return true;
740     }
listCoins()741     CoinsList listCoins() override
742     {
743         auto locked_chain = m_wallet->chain().lock();
744         LOCK(m_wallet->cs_wallet);
745         CoinsList result;
746         for (const auto& entry : m_wallet->ListCoins(*locked_chain)) {
747             auto& group = result[entry.first];
748             for (const auto& coin : entry.second) {
749                 group.emplace_back(COutPoint(coin.tx->GetHash(), coin.i),
750                     MakeWalletTxOut(*m_wallet, *coin.tx, coin.i, coin.nDepth));
751             }
752         }
753         return result;
754     }
getCoins(const std::vector<COutPoint> & outputs)755     std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override
756     {
757         auto locked_chain = m_wallet->chain().lock();
758         LOCK(m_wallet->cs_wallet);
759         std::vector<WalletTxOut> result;
760         result.reserve(outputs.size());
761         for (const auto& output : outputs) {
762             result.emplace_back();
763             auto it = m_wallet->mapWallet.find(output.hash);
764             if (it != m_wallet->mapWallet.end()) {
765                 int depth = it->second.GetDepthInMainChain();
766                 if (depth >= 0) {
767                     result.back() = MakeWalletTxOut(*m_wallet, it->second, output.n, depth);
768                 }
769             }
770         }
771         return result;
772     }
getRequiredFee(unsigned int tx_bytes)773     CAmount getRequiredFee(unsigned int tx_bytes) override { return GetRequiredFee(*m_wallet, tx_bytes); }
getMinimumFee(unsigned int tx_bytes,const CCoinControl & coin_control,int * returned_target,FeeReason * reason)774     CAmount getMinimumFee(unsigned int tx_bytes,
775         const CCoinControl& coin_control,
776         int* returned_target,
777         FeeReason* reason) override
778     {
779         FeeCalculation fee_calc;
780         CAmount result;
781         result = GetMinimumFee(*m_wallet, tx_bytes, coin_control, &fee_calc);
782         if (returned_target) *returned_target = fee_calc.returnedTarget;
783         if (reason) *reason = fee_calc.reason;
784         return result;
785     }
getConfirmTarget()786     unsigned int getConfirmTarget() override { return m_wallet->m_confirm_target; }
hdEnabled()787     bool hdEnabled() override { return m_wallet->IsHDEnabled(); }
canGetAddresses()788     bool canGetAddresses() override { return m_wallet->CanGetAddresses(); }
privateKeysDisabled()789     bool privateKeysDisabled() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); }
getDefaultAddressType()790     OutputType getDefaultAddressType() override { return m_wallet->m_default_address_type; }
getDefaultChangeType()791     OutputType getDefaultChangeType() override { return m_wallet->m_default_change_type; }
getDefaultMaxTxFee()792     CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; }
remove()793     void remove() override
794     {
795         RemoveWallet(m_wallet);
796     }
addTokenEntry(const TokenInfo & token)797     bool addTokenEntry(const TokenInfo &token) override
798     {
799         return m_wallet->AddTokenEntry(MakeTokenInfo(token), true);
800     }
addTokenTxEntry(const TokenTx & tokenTx,bool fFlushOnClose)801     bool addTokenTxEntry(const TokenTx& tokenTx, bool fFlushOnClose) override
802     {
803         return m_wallet->AddTokenTxEntry(MakeTokenTx(tokenTx), fFlushOnClose);
804     }
existTokenEntry(const TokenInfo & token)805     bool existTokenEntry(const TokenInfo &token) override
806     {
807         auto locked_chain = m_wallet->chain().lock();
808         LOCK(m_wallet->cs_wallet);
809 
810         uint256 hash = MakeTokenInfo(token).GetHash();
811         std::map<uint256, CTokenInfo>::iterator it = m_wallet->mapToken.find(hash);
812 
813         return it != m_wallet->mapToken.end();
814     }
removeTokenEntry(const std::string & sHash)815     bool removeTokenEntry(const std::string &sHash) override
816     {
817         return m_wallet->RemoveTokenEntry(uint256S(sHash), true);
818     }
getInvalidTokens()819     std::vector<TokenInfo> getInvalidTokens() override
820     {
821         auto locked_chain = m_wallet->chain().lock();
822         LOCK(m_wallet->cs_wallet);
823 
824         std::vector<TokenInfo> listInvalid;
825         for(auto& info : m_wallet->mapToken)
826         {
827             std::string strAddress = info.second.strSenderAddress;
828             CTxDestination address = DecodeDestination(strAddress);
829             if(!m_wallet->IsMine(address))
830             {
831                 listInvalid.push_back(MakeWalletTokenInfo(info.second));
832             }
833         }
834 
835         return listInvalid;
836     }
getTokenTx(const uint256 & txid)837     TokenTx getTokenTx(const uint256& txid) override
838     {
839         auto locked_chain = m_wallet->chain().lock();
840         LOCK(m_wallet->cs_wallet);
841 
842         auto mi = m_wallet->mapTokenTx.find(txid);
843         if (mi != m_wallet->mapTokenTx.end()) {
844             return MakeWalletTokenTx(mi->second);
845         }
846         return {};
847     }
getTokenTxs()848     std::vector<TokenTx> getTokenTxs() override
849     {
850         auto locked_chain = m_wallet->chain().lock();
851         LOCK(m_wallet->cs_wallet);
852 
853         std::vector<TokenTx> result;
854         result.reserve(m_wallet->mapTokenTx.size());
855         for (const auto& entry : m_wallet->mapTokenTx) {
856             result.emplace_back(MakeWalletTokenTx(entry.second));
857         }
858         return result;
859     }
getToken(const uint256 & id)860     TokenInfo getToken(const uint256& id) override
861     {
862         auto locked_chain = m_wallet->chain().lock();
863         LOCK(m_wallet->cs_wallet);
864 
865         auto mi = m_wallet->mapToken.find(id);
866         if (mi != m_wallet->mapToken.end()) {
867             return MakeWalletTokenInfo(mi->second);
868         }
869         return {};
870     }
getTokens()871     std::vector<TokenInfo> getTokens() override
872     {
873         auto locked_chain = m_wallet->chain().lock();
874         LOCK(m_wallet->cs_wallet);
875 
876         std::vector<TokenInfo> result;
877         result.reserve(m_wallet->mapToken.size());
878         for (const auto& entry : m_wallet->mapToken) {
879             result.emplace_back(MakeWalletTokenInfo(entry.second));
880         }
881         return result;
882     }
tryGetTokenTxStatus(const uint256 & txid,int & block_number,bool & in_mempool,int & num_blocks)883     bool tryGetTokenTxStatus(const uint256& txid, int& block_number, bool& in_mempool, int& num_blocks) override
884     {
885         auto locked_chain = m_wallet->chain().lock(true);
886         if (!locked_chain) {
887             return false;
888         }
889         TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
890         if (!locked_wallet) {
891             return false;
892         }
893         return TokenTxStatus(*locked_chain, *m_wallet, txid, block_number, in_mempool, num_blocks);
894     }
getTokenTxStatus(const uint256 & txid,int & block_number,bool & in_mempool,int & num_blocks)895     bool getTokenTxStatus(const uint256& txid, int& block_number, bool& in_mempool, int& num_blocks) override
896     {
897         auto locked_chain = m_wallet->chain().lock();
898         LOCK(m_wallet->cs_wallet);
899 
900         return TokenTxStatus(*locked_chain, *m_wallet, txid, block_number, in_mempool, num_blocks);
901     }
getTokenTxDetails(const TokenTx & wtx,uint256 & credit,uint256 & debit,std::string & tokenSymbol,uint8_t & decimals)902     bool getTokenTxDetails(const TokenTx &wtx, uint256& credit, uint256& debit, std::string& tokenSymbol, uint8_t& decimals) override
903     {
904         return m_wallet->GetTokenTxDetails(MakeTokenTx(wtx), credit, debit, tokenSymbol, decimals);
905     }
isTokenTxMine(const TokenTx & wtx)906     bool isTokenTxMine(const TokenTx &wtx) override
907     {
908         return m_wallet->IsTokenTxMine(MakeTokenTx(wtx));
909     }
getContractBook(const std::string & id)910     ContractBookData getContractBook(const std::string& id) override
911     {
912         LOCK(m_wallet->cs_wallet);
913 
914         auto mi = m_wallet->mapContractBook.find(id);
915         if (mi != m_wallet->mapContractBook.end()) {
916             return MakeContractBook(id, mi->second);
917         }
918         return {};
919     }
getContractBooks()920     std::vector<ContractBookData> getContractBooks() override
921     {
922         LOCK(m_wallet->cs_wallet);
923 
924         std::vector<ContractBookData> result;
925         result.reserve(m_wallet->mapContractBook.size());
926         for (const auto& entry : m_wallet->mapContractBook) {
927             result.emplace_back(MakeContractBook(entry.first, entry.second));
928         }
929         return result;
930     }
existContractBook(const std::string & id)931     bool existContractBook(const std::string& id) override
932     {
933         LOCK(m_wallet->cs_wallet);
934 
935         auto mi = m_wallet->mapContractBook.find(id);
936         return mi != m_wallet->mapContractBook.end();
937     }
delContractBook(const std::string & id)938     bool delContractBook(const std::string& id) override
939     {
940         return m_wallet->DelContractBook(id);
941     }
setContractBook(const std::string & id,const std::string & name,const std::string & abi)942     bool setContractBook(const std::string& id, const std::string& name, const std::string& abi) override
943     {
944         return m_wallet->SetContractBook(id, name, abi);
945     }
restoreDelegations()946     uint32_t restoreDelegations() override
947     {
948         RefreshDelegates(m_wallet.get(), true, false);
949 
950         auto locked_chain = m_wallet->chain().lock();
951         LOCK(m_wallet->cs_wallet);
952 
953         int ret = 0;
954         for (const auto& item : m_wallet->m_my_delegations) {
955             DelegationDetails details = getDelegationDetails(KeyIdToString(item.first));
956             if(!details.w_entry_exist && details.c_entry_exist)
957             {
958                 DelegationInfo info = details.toInfo(false);
959                 info.staker_name = info.staker_address;
960                 if(addDelegationEntry(info))
961                     ret++;
962             }
963         }
964 
965         return ret;
966     }
addDelegationEntry(const DelegationInfo & delegation)967     bool addDelegationEntry(const DelegationInfo &delegation) override
968     {
969         return m_wallet->AddDelegationEntry(MakeDelegationInfo(delegation), true);
970     }
existDelegationEntry(const DelegationInfo & delegation)971     bool existDelegationEntry(const DelegationInfo &delegation) override
972     {
973         auto locked_chain = m_wallet->chain().lock();
974         LOCK(m_wallet->cs_wallet);
975 
976         uint256 hash = MakeDelegationInfo(delegation).GetHash();
977         std::map<uint256, CDelegationInfo>::iterator it = m_wallet->mapDelegation.find(hash);
978 
979         return it != m_wallet->mapDelegation.end();
980     }
getDelegation(const uint256 & id)981     DelegationInfo getDelegation(const uint256& id) override
982     {
983         auto locked_chain = m_wallet->chain().lock();
984         LOCK(m_wallet->cs_wallet);
985 
986         auto mi = m_wallet->mapDelegation.find(id);
987         if (mi != m_wallet->mapDelegation.end()) {
988             return MakeWalletDelegationInfo(mi->second);
989         }
990         return {};
991     }
getDelegationContract(const std::string & sHash,bool & validated,bool & contractRet)992     DelegationInfo getDelegationContract(const std::string &sHash, bool& validated, bool& contractRet) override
993     {
994         auto locked_chain = m_wallet->chain().lock();
995         LOCK(m_wallet->cs_wallet);
996 
997         uint256 id;
998         id.SetHex(sHash);
999         auto mi = m_wallet->mapDelegation.find(id);
1000         if (mi != m_wallet->mapDelegation.end()) {
1001             DelegationInfo info = MakeWalletDelegationInfo(mi->second);
1002             Delegation delegation;
1003             CTxDestination dest = DecodeDestination(info.delegate_address);
1004             const PKHash *keyID = boost::get<PKHash>(&dest);
1005             if(keyID)
1006             {
1007                 uint160 address(*keyID);
1008                 contractRet = m_qtumDelegation.ExistDelegationContract() ? m_qtumDelegation.GetDelegation(address, delegation) : false;
1009                 if(contractRet)
1010                 {
1011                     validated = m_qtumDelegation.VerifyDelegation(address, delegation);
1012                     info.staker_address = EncodeDestination(PKHash(delegation.staker));
1013                     info.fee = delegation.fee;
1014                     info.block_number = delegation.blockHeight;
1015                 }
1016                 return info;
1017             }
1018         }
1019         return {};
1020     }
getDelegationDetails(const std::string & sAddress)1021     DelegationDetails getDelegationDetails(const std::string &sAddress) override
1022     {
1023         auto locked_chain = m_wallet->chain().lock();
1024         LOCK(m_wallet->cs_wallet);
1025         DelegationDetails details;
1026 
1027         // Get wallet delegation details
1028         for(auto mi : m_wallet->mapDelegation)
1029         {
1030             if(KeyIdToString(mi.second.delegateAddress) == sAddress)
1031             {
1032                 details.w_entry_exist = true;
1033                 details.w_delegate_address = KeyIdToString(mi.second.delegateAddress);
1034                 details.w_staker_address = KeyIdToString(mi.second.stakerAddress);
1035                 details.w_staker_name = mi.second.strStakerName;
1036                 details.w_fee = mi.second.nFee;
1037                 details.w_time = mi.second.nCreateTime;
1038                 details.w_block_number = mi.second.blockNumber;
1039                 details.w_hash = mi.first;
1040                 details.w_create_tx_hash = mi.second.createTxHash;
1041                 details.w_remove_tx_hash = mi.second.removeTxHash;
1042                 break;
1043             }
1044         }
1045 
1046         // Get wallet create tx details
1047         const CWalletTx* wtx = m_wallet->GetWalletTx(details.w_create_tx_hash);
1048         if(wtx)
1049         {
1050             details.w_create_exist = true;
1051             details.w_create_in_main_chain = wtx->IsInMainChain();
1052             details.w_create_in_mempool = wtx->InMempool();
1053             details.w_create_abandoned = wtx->isAbandoned();
1054         }
1055 
1056         // Get wallet remove tx details
1057         wtx = m_wallet->GetWalletTx(details.w_remove_tx_hash);
1058         if(wtx)
1059         {
1060             details.w_remove_exist = true;
1061             details.w_remove_in_main_chain = wtx->IsInMainChain();
1062             details.w_remove_in_mempool = wtx->InMempool();
1063             details.w_remove_abandoned = wtx->isAbandoned();
1064         }
1065 
1066         // Delegation contract details
1067         Delegation delegation;
1068         CTxDestination dest = DecodeDestination(sAddress);
1069         const PKHash *keyID = boost::get<PKHash>(&dest);
1070         if(keyID)
1071         {
1072             uint160 address(*keyID);
1073             details.c_contract_return = m_qtumDelegation.ExistDelegationContract() ? m_qtumDelegation.GetDelegation(address, delegation) : false;
1074             if(details.c_contract_return)
1075             {
1076                 details.c_entry_exist = m_qtumDelegation.VerifyDelegation(address, delegation);
1077                 details.c_delegate_address = sAddress;
1078                 details.c_staker_address = EncodeDestination(PKHash(delegation.staker));
1079                 details.c_fee = delegation.fee;
1080                 details.c_block_number = delegation.blockHeight;
1081             }
1082         }
1083 
1084         return details;
1085     }
getDelegations()1086     std::vector<DelegationInfo> getDelegations() override
1087     {
1088         auto locked_chain = m_wallet->chain().lock();
1089         LOCK(m_wallet->cs_wallet);
1090 
1091         std::vector<DelegationInfo> result;
1092         result.reserve(m_wallet->mapDelegation.size());
1093         for (const auto& entry : m_wallet->mapDelegation) {
1094             result.emplace_back(MakeWalletDelegationInfo(entry.second));
1095         }
1096         return result;
1097     }
removeDelegationEntry(const std::string & sHash)1098     bool removeDelegationEntry(const std::string &sHash) override
1099     {
1100         return m_wallet->RemoveDelegationEntry(uint256S(sHash), true);
1101     }
setDelegationRemoved(const std::string & sHash,const std::string & sTxid)1102     bool setDelegationRemoved(const std::string &sHash, const std::string &sTxid)
1103     {
1104         bool found = false;
1105         DelegationInfo info;
1106         {
1107             auto locked_chain = m_wallet->chain().lock();
1108             LOCK(m_wallet->cs_wallet);
1109 
1110             uint256 id;
1111             id.SetHex(sHash);
1112 
1113             uint256 txid;
1114             txid.SetHex(sTxid);
1115 
1116             auto mi = m_wallet->mapDelegation.find(id);
1117             if (mi != m_wallet->mapDelegation.end()) {
1118                 info = MakeWalletDelegationInfo(mi->second);
1119                 info.remove_tx_hash = txid;
1120                 found = true;
1121             }
1122         }
1123 
1124         return found ? addDelegationEntry(info) : 0;
1125     }
restoreSuperStakers()1126     uint32_t restoreSuperStakers() override
1127     {
1128         RefreshDelegates(m_wallet.get(), false, true);
1129 
1130         auto locked_chain = m_wallet->chain().lock();
1131         LOCK(m_wallet->cs_wallet);
1132 
1133         std::map<uint160, bool> stakerAddressExist;
1134         for (const auto& item : m_wallet->m_delegations_staker) {
1135             uint160 staker = item.second.staker;
1136             if(!stakerAddressExist[staker])
1137                 stakerAddressExist[staker] = true;
1138         }
1139 
1140         int ret = 0;
1141         for (const auto& item : stakerAddressExist) {
1142             std::string staker_address = KeyIdToString(item.first);
1143             if(!existSuperStaker(staker_address))
1144             {
1145                 SuperStakerInfo info;
1146                 info.staker_name = staker_address;
1147                 info.staker_address = staker_address;
1148                 if(addSuperStakerEntry(info))
1149                     ret++;
1150             }
1151         }
1152 
1153         return ret;
1154     }
existSuperStaker(const std::string & sAddress)1155     bool existSuperStaker(const std::string &sAddress) override
1156     {
1157         LOCK(m_wallet->cs_wallet);
1158         uint160 address = StringToKeyId(sAddress);
1159         if(address.IsNull())
1160             return false;
1161 
1162         for (const auto& entry : m_wallet->mapSuperStaker) {
1163             if(entry.second.stakerAddress == address)
1164                 return true;
1165         }
1166 
1167         return false;
1168     }
getSuperStaker(const uint256 & id)1169     SuperStakerInfo getSuperStaker(const uint256& id) override
1170     {
1171         LOCK(m_wallet->cs_wallet);
1172 
1173         auto mi = m_wallet->mapSuperStaker.find(id);
1174         if (mi != m_wallet->mapSuperStaker.end()) {
1175             return MakeWalletSuperStakerInfo(mi->second);
1176         }
1177         return {};
1178     }
getSuperStakerRecommendedConfig()1179     SuperStakerInfo getSuperStakerRecommendedConfig() override
1180     {
1181         LOCK(m_wallet->cs_wallet);
1182 
1183         // Set recommended config
1184         SuperStakerInfo config;
1185         config.custom_config = false;
1186         config.min_fee = m_wallet->m_staking_min_fee;
1187         config.min_delegate_utxo = m_wallet->m_staking_min_utxo_value;
1188         config.delegate_address_type = SuperStakerAddressList::AcceptAll;
1189 
1190         // Get allow list
1191         std::vector<std::string> allowList;
1192         for (const std::string& strAddress : gArgs.GetArgs("-stakingallowlist"))
1193         {
1194             if(!StringToKeyId(strAddress).IsNull())
1195             {
1196                 if(std::find(allowList.begin(), allowList.end(), strAddress) == allowList.end())
1197                     allowList.push_back(strAddress);
1198             }
1199         }
1200 
1201         // Get exclude list
1202         std::vector<std::string> excludeList;
1203         for (const std::string& strAddress : gArgs.GetArgs("-stakingexcludelist"))
1204         {
1205             if(!StringToKeyId(strAddress).IsNull())
1206             {
1207                 if(std::find(excludeList.begin(), excludeList.end(), strAddress) == excludeList.end())
1208                     excludeList.push_back(strAddress);
1209             }
1210         }
1211 
1212         // Set the address list
1213         if(!allowList.empty())
1214         {
1215             config.delegate_address_type =  SuperStakerAddressList::AllowList;
1216             config.delegate_address_list = allowList;
1217         }
1218         else if(!excludeList.empty())
1219         {
1220             config.delegate_address_type = SuperStakerAddressList::ExcludeList;
1221             config.delegate_address_list = excludeList;
1222         }
1223 
1224         return config;
1225     }
getSuperStakers()1226     std::vector<SuperStakerInfo> getSuperStakers() override
1227     {
1228         LOCK(m_wallet->cs_wallet);
1229 
1230         std::vector<SuperStakerInfo> result;
1231         result.reserve(m_wallet->mapSuperStaker.size());
1232         for (const auto& entry : m_wallet->mapSuperStaker) {
1233             result.emplace_back(MakeWalletSuperStakerInfo(entry.second));
1234         }
1235         return result;
1236     }
addSuperStakerEntry(const SuperStakerInfo & superStaker)1237     bool addSuperStakerEntry(const SuperStakerInfo &superStaker) override
1238     {
1239         return m_wallet->AddSuperStakerEntry(MakeSuperStakerInfo(superStaker), true);
1240     }
removeSuperStakerEntry(const std::string & sHash)1241     bool removeSuperStakerEntry(const std::string &sHash) override
1242     {
1243         return m_wallet->RemoveSuperStakerEntry(uint256S(sHash), true);
1244     }
tryGetStakeWeight(uint64_t & nWeight)1245     bool tryGetStakeWeight(uint64_t& nWeight) override
1246     {
1247         auto locked_chain = m_wallet->chain().lock(true);
1248         if (!locked_chain) {
1249             return false;
1250         }
1251         TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
1252         if (!locked_wallet) {
1253             return false;
1254         }
1255 
1256         nWeight = m_wallet->GetStakeWeight(*locked_chain);
1257         return true;
1258     }
getStakeWeight()1259     uint64_t getStakeWeight() override
1260     {
1261         auto locked_chain = m_wallet->chain().lock();
1262         LOCK(m_wallet->cs_wallet);
1263         return m_wallet->GetStakeWeight(*locked_chain);
1264     }
getLastCoinStakeSearchInterval()1265     int64_t getLastCoinStakeSearchInterval() override
1266     {
1267         return m_wallet->m_last_coin_stake_search_interval;
1268     }
getWalletUnlockStakingOnly()1269     bool getWalletUnlockStakingOnly() override
1270     {
1271         return m_wallet->m_wallet_unlock_staking_only;
1272     }
setWalletUnlockStakingOnly(bool unlock)1273     void setWalletUnlockStakingOnly(bool unlock) override
1274     {
1275         m_wallet->m_wallet_unlock_staking_only = unlock;
1276     }
cleanTokenTxEntries()1277     bool cleanTokenTxEntries() override
1278     {
1279         return m_wallet->CleanTokenTxEntries();
1280     }
setEnabledStaking(bool enabled)1281     void setEnabledStaking(bool enabled) override
1282     {
1283         m_wallet->m_enabled_staking = enabled;
1284     }
getEnabledStaking()1285     bool getEnabledStaking() override
1286     {
1287         return m_wallet->m_enabled_staking;
1288     }
getEnabledSuperStaking()1289     bool getEnabledSuperStaking() override
1290     {
1291         bool fSuperStake = gArgs.GetBoolArg("-superstaking", DEFAULT_SUPER_STAKE);
1292         return fSuperStake;
1293     }
getDelegationStaker(const uint160 & id)1294     DelegationStakerInfo getDelegationStaker(const uint160& id) override
1295     {
1296         auto locked_chain = m_wallet->chain().lock();
1297         LOCK(m_wallet->cs_wallet);
1298 
1299         auto mi = m_wallet->m_delegations_staker.find(id);
1300         if (mi != m_wallet->m_delegations_staker.end()) {
1301             return MakeWalletDelegationStakerInfo(*locked_chain, *m_wallet, mi->first, mi->second);
1302         }
1303         return {};
1304     }
getDelegationsStakers()1305     std::vector<DelegationStakerInfo> getDelegationsStakers() override
1306     {
1307         auto locked_chain = m_wallet->chain().lock();
1308         LOCK(m_wallet->cs_wallet);
1309 
1310         std::vector<DelegationStakerInfo> result;
1311         result.reserve(m_wallet->m_delegations_staker.size());
1312         for (const auto& entry : m_wallet->m_delegations_staker) {
1313             result.emplace_back(MakeWalletDelegationStakerInfo(*locked_chain, *m_wallet, entry.first, entry.second));
1314         }
1315         return result;
1316     }
getSuperStakerWeight(const uint256 & id)1317     uint64_t getSuperStakerWeight(const uint256& id) override
1318     {
1319         LOCK(m_wallet->cs_wallet);
1320         SuperStakerInfo info = getSuperStaker(id);
1321         CTxDestination dest = DecodeDestination(info.staker_address);
1322         const PKHash *keyID = boost::get<PKHash>(&dest);
1323         if(keyID)
1324         {
1325             uint160 address(*keyID);
1326             return m_wallet->GetSuperStakerWeight(address);
1327         }
1328 
1329         return 0;
1330     }
isSuperStakerStaking(const uint256 & id,CAmount & delegationsWeight)1331     bool isSuperStakerStaking(const uint256& id, CAmount& delegationsWeight) override
1332     {
1333         uint64_t lastCoinStakeSearchInterval = getEnabledStaking() ? getLastCoinStakeSearchInterval() : 0;
1334         delegationsWeight = getSuperStakerWeight(id);
1335         return lastCoinStakeSearchInterval && delegationsWeight;
1336     }
getStakerAddressBalance(const std::string & staker,CAmount & balance,CAmount & stake,CAmount & weight)1337     bool getStakerAddressBalance(const std::string& staker, CAmount& balance, CAmount& stake, CAmount& weight) override
1338     {
1339         auto locked_chain = m_wallet->chain().lock();
1340         LOCK(m_wallet->cs_wallet);
1341 
1342         CTxDestination dest = DecodeDestination(staker);
1343         const PKHash *keyID = boost::get<PKHash>(&dest);
1344         if(keyID)
1345         {
1346             m_wallet->GetStakerAddressBalance(*locked_chain, *keyID, balance, stake, weight);
1347         }
1348 
1349         return keyID != 0;
1350     }
handleUnload(UnloadFn fn)1351     std::unique_ptr<Handler> handleUnload(UnloadFn fn) override
1352     {
1353         return MakeHandler(m_wallet->NotifyUnload.connect(fn));
1354     }
handleShowProgress(ShowProgressFn fn)1355     std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
1356     {
1357         return MakeHandler(m_wallet->ShowProgress.connect(fn));
1358     }
handleStatusChanged(StatusChangedFn fn)1359     std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override
1360     {
1361         return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); }));
1362     }
handleAddressBookChanged(AddressBookChangedFn fn)1363     std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override
1364     {
1365         return MakeHandler(m_wallet->NotifyAddressBookChanged.connect(
1366             [fn](CWallet*, const CTxDestination& address, const std::string& label, bool is_mine,
1367                 const std::string& purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); }));
1368     }
handleTransactionChanged(TransactionChangedFn fn)1369     std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override
1370     {
1371         return MakeHandler(m_wallet->NotifyTransactionChanged.connect(
1372             [fn](CWallet*, const uint256& txid, ChangeType status) { fn(txid, status); }));
1373     }
handleTokenTransactionChanged(TokenTransactionChangedFn fn)1374     std::unique_ptr<Handler> handleTokenTransactionChanged(TokenTransactionChangedFn fn) override
1375     {
1376         return MakeHandler(m_wallet->NotifyTokenTransactionChanged.connect(
1377             [fn](CWallet*, const uint256& id, ChangeType status) { fn(id, status); }));
1378     }
handleTokenChanged(TokenChangedFn fn)1379     std::unique_ptr<Handler> handleTokenChanged(TokenChangedFn fn) override
1380     {
1381         return MakeHandler(m_wallet->NotifyTokenChanged.connect(
1382             [fn](CWallet*, const uint256& id, ChangeType status) { fn(id, status); }));
1383     }
handleWatchOnlyChanged(WatchOnlyChangedFn fn)1384     std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) override
1385     {
1386         return MakeHandler(m_wallet->NotifyWatchonlyChanged.connect(fn));
1387     }
handleCanGetAddressesChanged(CanGetAddressesChangedFn fn)1388     std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) override
1389     {
1390         return MakeHandler(m_wallet->NotifyCanGetAddressesChanged.connect(fn));
1391     }
handleContractBookChanged(ContractBookChangedFn fn)1392     std::unique_ptr<Handler> handleContractBookChanged(ContractBookChangedFn fn) override
1393     {
1394         return MakeHandler(m_wallet->NotifyContractBookChanged.connect(
1395             [fn](CWallet*, const std::string& address, const std::string& label,
1396                 const std::string& abi, ChangeType status) { fn(address, label, abi, status); }));
1397     }
handleDelegationChanged(DelegationChangedFn fn)1398     std::unique_ptr<Handler> handleDelegationChanged(DelegationChangedFn fn) override
1399     {
1400         return MakeHandler(m_wallet->NotifyDelegationChanged.connect(
1401             [fn](CWallet*, const uint256& id, ChangeType status) { fn(id, status); }));
1402     }
handleSuperStakerChanged(SuperStakerChangedFn fn)1403     std::unique_ptr<Handler> handleSuperStakerChanged(SuperStakerChangedFn fn) override
1404     {
1405         return MakeHandler(m_wallet->NotifySuperStakerChanged.connect(
1406             [fn](CWallet*, const uint256& id, ChangeType status) { fn(id, status); }));
1407     }
handleDelegationsStakerChanged(DelegationsStakerChangedFn fn)1408     std::unique_ptr<Handler> handleDelegationsStakerChanged(DelegationsStakerChangedFn fn) override
1409     {
1410         return MakeHandler(m_wallet->NotifyDelegationsStakerChanged.connect(
1411             [fn](CWallet*, const uint160& id, ChangeType status) { fn(id, status); }));
1412     }
1413 
1414     std::shared_ptr<CWallet> m_wallet;
1415     QtumDelegation m_qtumDelegation;
1416 };
1417 
1418 class WalletClientImpl : public ChainClient
1419 {
1420 public:
WalletClientImpl(Chain & chain,std::vector<std::string> wallet_filenames)1421     WalletClientImpl(Chain& chain, std::vector<std::string> wallet_filenames)
1422         : m_chain(chain), m_wallet_filenames(std::move(wallet_filenames))
1423     {
1424     }
registerRpcs()1425     void registerRpcs() override
1426     {
1427         g_rpc_chain = &m_chain;
1428         return RegisterWalletRPCCommands(m_chain, m_rpc_handlers);
1429     }
verify()1430     bool verify() override { return VerifyWallets(m_chain, m_wallet_filenames); }
load()1431     bool load() override { return LoadWallets(m_chain, m_wallet_filenames); }
start(CScheduler & scheduler)1432     void start(CScheduler& scheduler) override { return StartWallets(scheduler); }
flush()1433     void flush() override { return FlushWallets(); }
stop()1434     void stop() override { return StopWallets(); }
~WalletClientImpl()1435     ~WalletClientImpl() override { UnloadWallets(); }
1436 
1437     Chain& m_chain;
1438     std::vector<std::string> m_wallet_filenames;
1439     std::vector<std::unique_ptr<Handler>> m_rpc_handlers;
1440 };
1441 
1442 } // namespace
1443 
MakeWallet(const std::shared_ptr<CWallet> & wallet)1444 std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? MakeUnique<WalletImpl>(wallet) : nullptr; }
1445 
MakeWalletClient(Chain & chain,std::vector<std::string> wallet_filenames)1446 std::unique_ptr<ChainClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames)
1447 {
1448     return MakeUnique<WalletClientImpl>(chain, std::move(wallet_filenames));
1449 }
1450 
1451 } // namespace interfaces
1452