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