From 60c834e3d58af7a1e36a2d0f585d59a5f58d012e Mon Sep 17 00:00:00 2001 From: timemarkovqtum Date: Wed, 26 Jun 2024 16:10:31 +0200 Subject: [PATCH] Port token interfaces --- src/bip324.cpp | 2 +- src/interfaces/chain.h | 3 + src/merkleblock.cpp | 2 +- src/node/interfaces.cpp | 1 + src/undo.h | 5 +- src/versionbits.cpp | 7 + src/versionbits.h | 2 + src/wallet/interfaces.cpp | 362 +++++++++++++++++++++++++++++++++-- src/wallet/wallet.cpp | 388 ++++++++++++++++++++++++++++++++++++++ src/wallet/wallet.h | 32 ++++ 10 files changed, 781 insertions(+), 23 deletions(-) diff --git a/src/bip324.cpp b/src/bip324.cpp index f579a25193..1d88ac9c73 100644 --- a/src/bip324.cpp +++ b/src/bip324.cpp @@ -35,7 +35,7 @@ void BIP324Cipher::Initialize(const EllSwiftPubKey& their_pubkey, bool initiator { // Determine salt (fixed string + network magic bytes) const auto& message_header = Params().MessageStart(); - std::string salt = std::string{"bitcoin_v2_shared_secret"} + std::string(std::begin(message_header), std::end(message_header)); + std::string salt = std::string{"qtum_v2_shared_secret"} + std::string(std::begin(message_header), std::end(message_header)); // Perform ECDH to derive shared secret. ECDHSecret ecdh_secret = m_key.ComputeBIP324ECDHSecret(their_pubkey, m_our_pubkey, initiator); diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 045693721f..c54bf2ff28 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -325,6 +325,9 @@ class Chain //! Check if shutdown requested. virtual bool shutdownRequested() = 0; + //! Get adjusted time. + virtual int64_t getAdjustedTime() = 0; + //! Send init message. virtual void initMessage(const std::string& message) = 0; diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index c75f5c5e60..27fc84d3d5 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -152,7 +152,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector &vMatch, std::ve if (nTransactions == 0) return uint256(); // check for excessively high numbers of transactions - if (nTransactions > MAX_BLOCK_WEIGHT / MIN_TRANSACTION_WEIGHT) + if (nTransactions > dgpMaxBlockSize * WITNESS_SCALE_FACTOR / MIN_TRANSACTION_WEIGHT) return uint256(); // there can never be more hashes provided than one for every txid if (vHash.size() > nTransactions) diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index dcaa02a983..7700125ff1 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -822,6 +822,7 @@ class ChainImpl : public Chain return chainman().IsInitialBlockDownload(); } bool shutdownRequested() override { return ShutdownRequested(m_node); } + int64_t getAdjustedTime() override { return TicksSinceEpoch(NodeClock::now()); } void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); } void initWarning(const bilingual_str& message) override { InitWarning(message); } void initError(const bilingual_str& message) override { InitError(message); } diff --git a/src/undo.h b/src/undo.h index 1fb9ac0688..958ec932cd 100644 --- a/src/undo.h +++ b/src/undo.h @@ -23,7 +23,7 @@ struct TxInUndoFormatter { template void Ser(Stream &s, const Coin& txout) { - ::Serialize(s, VARINT(txout.nHeight * uint32_t{2} + txout.fCoinBase )); + ::Serialize(s, VARINT((txout.nHeight << 2) + (txout.fCoinStake ? 2u : 0u) + (txout.fCoinBase ? 1u : 0u))); if (txout.nHeight > 0) { // Required to maintain compatibility with older undo format. ::Serialize(s, (unsigned char)0); @@ -35,8 +35,9 @@ struct TxInUndoFormatter void Unser(Stream &s, Coin& txout) { uint32_t nCode = 0; ::Unserialize(s, VARINT(nCode)); - txout.nHeight = nCode >> 1; + txout.nHeight = nCode >> 2; txout.fCoinBase = nCode & 1; + txout.fCoinStake = (nCode >> 1) & 1; if (txout.nHeight > 0) { // Old versions stored the version number for the last spend of // a transaction's outputs. Non-final spends were indicated with diff --git a/src/versionbits.cpp b/src/versionbits.cpp index fa9d1fe9c9..ae2705855f 100644 --- a/src/versionbits.cpp +++ b/src/versionbits.cpp @@ -238,6 +238,13 @@ int32_t VersionBitsCache::ComputeBlockVersion(const CBlockIndex* pindexPrev, con return nVersion; } +void VersionBitsCache::Erase(CBlockIndex *pindex) { + LOCK(m_mutex); + for (int b = 0; b < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; b++) { + m_caches[b].erase(pindex); + } +} + void VersionBitsCache::Clear() { LOCK(m_mutex); diff --git a/src/versionbits.h b/src/versionbits.h index 09313d2054..a7b75414c3 100644 --- a/src/versionbits.h +++ b/src/versionbits.h @@ -101,6 +101,8 @@ class VersionBitsCache */ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + void Erase(CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + void Clear() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); }; diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index bc74c560db..b556085326 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -144,6 +144,214 @@ WalletTxOut MakeWalletTxOut(const CWallet& wallet, return result; } +//! Construct token info. +CTokenInfo MakeTokenInfo(const TokenInfo& token) +{ + CTokenInfo result; + result.strContractAddress = token.contract_address; + result.strTokenName = token.token_name; + result.strTokenSymbol = token.token_symbol; + result.nDecimals = token.decimals; + result.strSenderAddress = token.sender_address; + result.nCreateTime = token.time; + result.blockHash = token.block_hash; + result.blockNumber = token.block_number; + return result; +} + +//! Construct wallet token info. +TokenInfo MakeWalletTokenInfo(const CTokenInfo& token) +{ + TokenInfo result; + result.contract_address = token.strContractAddress; + result.token_name = token.strTokenName; + result.token_symbol = token.strTokenSymbol; + result.decimals = token.nDecimals; + result.sender_address = token.strSenderAddress; + result.time = token.nCreateTime; + result.block_hash = token.blockHash; + result.block_number = token.blockNumber; + result.hash = token.GetHash(); + return result; +} + +//! Construct token transaction. +CTokenTx MakeTokenTx(const TokenTx& tokenTx) +{ + CTokenTx result; + result.strContractAddress = tokenTx.contract_address; + result.strSenderAddress = tokenTx.sender_address; + result.strReceiverAddress = tokenTx.receiver_address; + result.nValue = tokenTx.value; + result.transactionHash = tokenTx.tx_hash; + result.nCreateTime = tokenTx.time; + result.blockHash = tokenTx.block_hash; + result.blockNumber = tokenTx.block_number; + result.strLabel = tokenTx.label; + return result; +} + +//! Construct wallet token transaction. +TokenTx MakeWalletTokenTx(const CTokenTx& tokenTx) +{ + TokenTx result; + result.contract_address = tokenTx.strContractAddress; + result.sender_address = tokenTx.strSenderAddress; + result.receiver_address = tokenTx.strReceiverAddress; + result.value = tokenTx.nValue; + result.tx_hash = tokenTx.transactionHash; + result.time = tokenTx.nCreateTime; + result.block_hash = tokenTx.blockHash; + result.block_number = tokenTx.blockNumber; + result.label = tokenTx.strLabel; + result.hash = tokenTx.GetHash(); + return result; +} + +ContractBookData MakeContractBook(const std::string& id, const CContractBookData& data) +{ + ContractBookData result; + result.address = id; + result.name = data.name; + result.abi = data.abi; + return result; +} + +uint160 StringToKeyId(const std::string& strAddress) +{ + CTxDestination dest = DecodeDestination(strAddress); + if(std::holds_alternative(dest)) + { + PKHash keyID = std::get(dest); + return uint160(keyID); + } + return uint160(); +} + +std::string KeyIdToString(const uint160& keyID) +{ + return EncodeDestination(PKHash(keyID)); +} + +std::vector StringToKeyIdList(const std::vector& listAddress) +{ + std::vector ret; + for(auto address : listAddress) + { + ret.push_back(StringToKeyId(address)); + } + return ret; +} + +std::vector KeyIdToStringList(const std::vector& listKeyID) +{ + std::vector ret; + for(auto keyId : listKeyID) + { + ret.push_back(KeyIdToString(keyId)); + } + return ret; +} + +//! Construct delegation info. +CDelegationInfo MakeDelegationInfo(const DelegationInfo& delegation) +{ + CDelegationInfo result; + result.delegateAddress = StringToKeyId(delegation.delegate_address); + result.stakerAddress = StringToKeyId(delegation.staker_address); + result.strStakerName = delegation.staker_name; + result.nFee = delegation.fee; + result.nCreateTime = delegation.time; + result.blockNumber = delegation.block_number; + result.createTxHash = delegation.create_tx_hash; + result.removeTxHash = delegation.remove_tx_hash; + return result; +} + +//! Construct wallet delegation info. +DelegationInfo MakeWalletDelegationInfo(const CDelegationInfo& delegation) +{ + DelegationInfo result; + result.delegate_address = KeyIdToString(delegation.delegateAddress); + result.staker_address = KeyIdToString(delegation.stakerAddress); + result.staker_name = delegation.strStakerName; + result.fee = delegation.nFee; + result.time = delegation.nCreateTime; + result.block_number = delegation.blockNumber; + result.time = delegation.nCreateTime; + result.create_tx_hash = delegation.createTxHash; + result.remove_tx_hash = delegation.removeTxHash; + result.hash = delegation.GetHash(); + return result; +} + +//! Construct super staker info. +CSuperStakerInfo MakeSuperStakerInfo(const SuperStakerInfo& superStaker) +{ + CSuperStakerInfo result; + result.stakerAddress = StringToKeyId(superStaker.staker_address); + result.strStakerName = superStaker.staker_name; + result.nMinFee = superStaker.min_fee; + result.nCreateTime = superStaker.time; + result.fCustomConfig = superStaker.custom_config; + result.nMinDelegateUtxo = superStaker.min_delegate_utxo; + result.delegateAddressList = StringToKeyIdList(superStaker.delegate_address_list); + result.nDelegateAddressType = superStaker.delegate_address_type; + return result; +} + +//! Construct wallet super staker info. +SuperStakerInfo MakeWalletSuperStakerInfo(const CSuperStakerInfo& superStaker) +{ + SuperStakerInfo result; + result.staker_address = KeyIdToString(superStaker.stakerAddress); + result.staker_name = superStaker.strStakerName; + result.min_fee = superStaker.nMinFee; + result.time = superStaker.nCreateTime; + result.custom_config = superStaker.fCustomConfig; + result.min_delegate_utxo = superStaker.nMinDelegateUtxo; + result.delegate_address_list = KeyIdToStringList(superStaker.delegateAddressList); + result.delegate_address_type = superStaker.nDelegateAddressType; + result.hash = superStaker.GetHash(); + return result; +} + +//! Construct wallet delegation staker info. +DelegationStakerInfo MakeWalletDelegationStakerInfo(CWallet& wallet, const uint160& id, const Delegation& delegation) +{ + DelegationStakerInfo result; + result.delegate_address = EncodeDestination(PKHash(id)); + result.staker_address = EncodeDestination(PKHash(delegation.staker)); + result.PoD = HexStr(delegation.PoD); + result.fee = delegation.fee; + result.time = -1; + wallet.chain().findBlock(wallet.chain().getBlockHash(delegation.blockHeight), FoundBlock().time(result.time)); + result.block_number = delegation.blockHeight; + std::map::iterator it = wallet.m_delegations_weight.find(id); + if(it != wallet.m_delegations_weight.end()) + { + result.weight = it->second; + } + result.hash = id; + return result; +} + +bool TokenTxStatus(CWallet& wallet, const uint256& txid, int& block_number, bool& in_mempool, int& num_blocks) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) +{ + auto mi = wallet.mapTokenTx.find(txid); + if (mi == wallet.mapTokenTx.end()) { + return false; + } + block_number = mi->second.blockNumber; + auto it = wallet.mapWallet.find(mi->second.transactionHash); + if(it != wallet.mapWallet.end()) + { + in_mempool = it->second.InMempool(); + } + num_blocks = wallet.GetLastBlockHeight(); + return true; +} + class WalletImpl : public Wallet { public: @@ -556,64 +764,133 @@ class WalletImpl : public Wallet bool isLegacy() override { return m_wallet->IsLegacy(); } bool addTokenEntry(const TokenInfo &token) override { + return m_wallet->AddTokenEntry(MakeTokenInfo(token), true); } bool addTokenTxEntry(const TokenTx& tokenTx, bool fFlushOnClose) override { + return m_wallet->AddTokenTxEntry(MakeTokenTx(tokenTx), fFlushOnClose); } bool existTokenEntry(const TokenInfo &token) override { - return {}; + LOCK(m_wallet->cs_wallet); + + uint256 hash = MakeTokenInfo(token).GetHash(); + std::map::iterator it = m_wallet->mapToken.find(hash); + + return it != m_wallet->mapToken.end(); } bool removeTokenEntry(const std::string &sHash) override { + return m_wallet->RemoveTokenEntry(uint256S(sHash), true); } std::vector getInvalidTokens() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector listInvalid; + for(auto& info : m_wallet->mapToken) + { + std::string strAddress = info.second.strSenderAddress; + CTxDestination address = DecodeDestination(strAddress); + if(!m_wallet->IsMine(address)) + { + listInvalid.push_back(MakeWalletTokenInfo(info.second)); + } + } + + return listInvalid; } TokenTx getTokenTx(const uint256& txid) override { + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->mapTokenTx.find(txid); + if (mi != m_wallet->mapTokenTx.end()) { + return MakeWalletTokenTx(mi->second); + } return {}; } std::vector getTokenTxs() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector result; + result.reserve(m_wallet->mapTokenTx.size()); + for (const auto& entry : m_wallet->mapTokenTx) { + result.emplace_back(MakeWalletTokenTx(entry.second)); + } + return result; } TokenInfo getToken(const uint256& id) override { + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->mapToken.find(id); + if (mi != m_wallet->mapToken.end()) { + return MakeWalletTokenInfo(mi->second); + } return {}; } std::vector getTokens() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector result; + result.reserve(m_wallet->mapToken.size()); + for (const auto& entry : m_wallet->mapToken) { + result.emplace_back(MakeWalletTokenInfo(entry.second)); + } + return result; } bool tryGetTokenTxStatus(const uint256& txid, int& block_number, bool& in_mempool, int& num_blocks) override { - return {}; + TRY_LOCK(m_wallet->cs_wallet, locked_wallet); + if (!locked_wallet) { + return false; + } + return TokenTxStatus(*m_wallet, txid, block_number, in_mempool, num_blocks); } bool getTokenTxStatus(const uint256& txid, int& block_number, bool& in_mempool, int& num_blocks) override { - return {}; + LOCK(m_wallet->cs_wallet); + + return TokenTxStatus(*m_wallet, txid, block_number, in_mempool, num_blocks); } bool getTokenTxDetails(const TokenTx &wtx, uint256& credit, uint256& debit, std::string& tokenSymbol, uint8_t& decimals) override { - return {}; + return m_wallet->GetTokenTxDetails(MakeTokenTx(wtx), credit, debit, tokenSymbol, decimals); } bool isTokenTxMine(const TokenTx &wtx) override { - return {}; + return m_wallet->IsTokenTxMine(MakeTokenTx(wtx)); } ContractBookData getContractBook(const std::string& id) override { + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->mapContractBook.find(id); + if (mi != m_wallet->mapContractBook.end()) { + return MakeContractBook(id, mi->second); + } return {}; } std::vector getContractBooks() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector result; + result.reserve(m_wallet->mapContractBook.size()); + for (const auto& entry : m_wallet->mapContractBook) { + result.emplace_back(MakeContractBook(entry.first, entry.second)); + } + return result; } bool existContractBook(const std::string& id) override { - return {}; + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->mapContractBook.find(id); + return mi != m_wallet->mapContractBook.end(); } bool delContractBook(const std::string& id) override { @@ -629,14 +906,25 @@ class WalletImpl : public Wallet } bool addDelegationEntry(const DelegationInfo &delegation) override { - return {}; + return m_wallet->AddDelegationEntry(MakeDelegationInfo(delegation), true); } bool existDelegationEntry(const DelegationInfo &delegation) override { - return {}; + LOCK(m_wallet->cs_wallet); + + uint256 hash = MakeDelegationInfo(delegation).GetHash(); + std::map::iterator it = m_wallet->mapDelegation.find(hash); + + return it != m_wallet->mapDelegation.end(); } DelegationInfo getDelegation(const uint256& id) override { + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->mapDelegation.find(id); + if (mi != m_wallet->mapDelegation.end()) { + return MakeWalletDelegationInfo(mi->second); + } return {}; } DelegationInfo getDelegationContract(const std::string &sHash, bool& validated, bool& contractRet) override @@ -649,11 +937,18 @@ class WalletImpl : public Wallet } std::vector getDelegations() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector result; + result.reserve(m_wallet->mapDelegation.size()); + for (const auto& entry : m_wallet->mapDelegation) { + result.emplace_back(MakeWalletDelegationInfo(entry.second)); + } + return result; } bool removeDelegationEntry(const std::string &sHash) override { - return {}; + return m_wallet->RemoveDelegationEntry(uint256S(sHash), true); } bool setDelegationRemoved(const std::string &sHash, const std::string &sTxid) override { @@ -665,10 +960,26 @@ class WalletImpl : public Wallet } bool existSuperStaker(const std::string &sAddress) override { - return {}; + LOCK(m_wallet->cs_wallet); + uint160 address = StringToKeyId(sAddress); + if(address.IsNull()) + return false; + + for (const auto& entry : m_wallet->mapSuperStaker) { + if(entry.second.stakerAddress == address) + return true; + } + + return false; } SuperStakerInfo getSuperStaker(const uint256& id) override { + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->mapSuperStaker.find(id); + if (mi != m_wallet->mapSuperStaker.end()) { + return MakeWalletSuperStakerInfo(mi->second); + } return {}; } SuperStakerInfo getSuperStakerRecommendedConfig() override @@ -677,15 +988,22 @@ class WalletImpl : public Wallet } std::vector getSuperStakers() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector result; + result.reserve(m_wallet->mapSuperStaker.size()); + for (const auto& entry : m_wallet->mapSuperStaker) { + result.emplace_back(MakeWalletSuperStakerInfo(entry.second)); + } + return result; } bool addSuperStakerEntry(const SuperStakerInfo &superStaker) override { - return {}; + return m_wallet->AddSuperStakerEntry(MakeSuperStakerInfo(superStaker), true); } bool removeSuperStakerEntry(const std::string &sHash) override { - return {}; + return m_wallet->RemoveSuperStakerEntry(uint256S(sHash), true); } bool tryGetStakeWeight(uint64_t& nWeight) override { @@ -709,7 +1027,7 @@ class WalletImpl : public Wallet } bool cleanTokenTxEntries() override { - return {}; + return m_wallet->CleanTokenTxEntries(); } void setEnabledStaking(bool enabled) override { @@ -726,6 +1044,12 @@ class WalletImpl : public Wallet } DelegationStakerInfo getDelegationStaker(const uint160& id) override { + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->m_delegations_staker.find(id); + if (mi != m_wallet->m_delegations_staker.end()) { + return MakeWalletDelegationStakerInfo(*m_wallet, mi->first, mi->second); + } return {}; } std::vector getDelegationsStakers() override diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 9a48a0fe96..e5be77cd78 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -3400,6 +3402,94 @@ bool CWallet::LoadTokenTx(const CTokenTx &tokenTx) return true; } +bool CWallet::AddTokenEntry(const CTokenInfo &token, bool fFlushOnClose) +{ + LOCK(cs_wallet); + + WalletBatch batch(GetDatabase(), fFlushOnClose); + + uint256 hash = token.GetHash(); + + bool fInsertedNew = true; + + std::map::iterator it = mapToken.find(hash); + if(it!=mapToken.end()) + { + fInsertedNew = false; + } + + // Write to disk + CTokenInfo wtoken = token; + if(!fInsertedNew) + { + wtoken.nCreateTime = chain().getAdjustedTime(); + } + else + { + wtoken.nCreateTime = it->second.nCreateTime; + } + + if (!batch.WriteToken(wtoken)) + return false; + + mapToken[hash] = wtoken; + + NotifyTokenChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); + + // Refresh token tx + if(fInsertedNew) + { + for(auto it = mapTokenTx.begin(); it != mapTokenTx.end(); it++) + { + uint256 tokenTxHash = it->second.GetHash(); + NotifyTokenTransactionChanged(this, tokenTxHash, CT_UPDATED); + } + } + + LogPrintf("AddTokenEntry %s\n", wtoken.GetHash().ToString()); + + return true; +} + +bool CWallet::AddTokenTxEntry(const CTokenTx &tokenTx, bool fFlushOnClose) +{ + LOCK(cs_wallet); + + WalletBatch batch(GetDatabase(), fFlushOnClose); + + uint256 hash = tokenTx.GetHash(); + + bool fInsertedNew = true; + + std::map::iterator it = mapTokenTx.find(hash); + if(it!=mapTokenTx.end()) + { + fInsertedNew = false; + } + + // Write to disk + CTokenTx wtokenTx = tokenTx; + if(!fInsertedNew) + { + wtokenTx.strLabel = it->second.strLabel; + } + int64_t blockTime; + uint256 blockHash = wtokenTx.blockNumber < 0 ? uint256() : chain().getBlockHash(wtokenTx.blockNumber); + bool found = !blockHash.IsNull() && chain().findBlock(blockHash, FoundBlock().time(blockTime)); + wtokenTx.nCreateTime = found ? blockTime : chain().getAdjustedTime(); + + if (!batch.WriteTokenTx(wtokenTx)) + return false; + + mapTokenTx[hash] = wtokenTx; + + NotifyTokenTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); + + LogPrintf("AddTokenTxEntry %s\n", wtokenTx.GetHash().ToString()); + + return true; +} + CKeyPool::CKeyPool() { nTime = GetTime(); @@ -4532,6 +4622,156 @@ uint256 CSuperStakerInfo::GetHash() const return (HashWriter{} << SER_INFO_GETHASH(*this)).GetHash(); } +bool CWallet::GetTokenTxDetails(const CTokenTx &wtx, uint256 &credit, uint256 &debit, std::string &tokenSymbol, uint8_t &decimals) const +{ + LOCK(cs_wallet); + bool ret = false; + + for(auto it = mapToken.begin(); it != mapToken.end(); it++) + { + CTokenInfo info = it->second; + if(wtx.strContractAddress == info.strContractAddress) + { + if(wtx.strSenderAddress == info.strSenderAddress) + { + debit = wtx.nValue; + tokenSymbol = info.strTokenSymbol; + decimals = info.nDecimals; + ret = true; + } + + if(wtx.strReceiverAddress == info.strSenderAddress) + { + credit = wtx.nValue; + tokenSymbol = info.strTokenSymbol; + decimals = info.nDecimals; + ret = true; + } + } + } + + return ret; +} + +bool CWallet::IsTokenTxMine(const CTokenTx &wtx) const +{ + LOCK(cs_wallet); + bool ret = false; + + for(auto it = mapToken.begin(); it != mapToken.end(); it++) + { + CTokenInfo info = it->second; + if(wtx.strContractAddress == info.strContractAddress) + { + if(wtx.strSenderAddress == info.strSenderAddress || + wtx.strReceiverAddress == info.strSenderAddress) + { + ret = true; + } + } + } + + return ret; +} + +bool CWallet::RemoveTokenEntry(const uint256 &tokenHash, bool fFlushOnClose) +{ + LOCK(cs_wallet); + + WalletBatch batch(GetDatabase(), fFlushOnClose); + + bool fFound = false; + + std::map::iterator it = mapToken.find(tokenHash); + if(it!=mapToken.end()) + { + fFound = true; + } + + if(fFound) + { + // Remove from disk + if (!batch.EraseToken(tokenHash)) + return false; + + mapToken.erase(it); + + NotifyTokenChanged(this, tokenHash, CT_DELETED); + + // Refresh token tx + for(auto it = mapTokenTx.begin(); it != mapTokenTx.end(); it++) + { + uint256 tokenTxHash = it->second.GetHash(); + NotifyTokenTransactionChanged(this, tokenTxHash, CT_UPDATED); + } + } + + LogPrintf("RemoveTokenEntry %s\n", tokenHash.ToString()); + + return true; +} + +bool CWallet::CleanTokenTxEntries(bool fFlushOnClose) +{ + LOCK(cs_wallet); + + // Open db + WalletBatch batch(GetDatabase(), fFlushOnClose); + + // Get all token transaction hashes + std::vector tokenTxHashes; + for(auto it = mapTokenTx.begin(); it != mapTokenTx.end(); it++) + { + tokenTxHashes.push_back(it->first); + } + + // Remove existing entries + for(size_t i = 0; i < tokenTxHashes.size(); i++) + { + // Get the I entry + uint256 hashTxI = tokenTxHashes[i]; + auto itTxI = mapTokenTx.find(hashTxI); + if(itTxI == mapTokenTx.end()) continue; + CTokenTx tokenTxI = itTxI->second; + + for(size_t j = 0; j < tokenTxHashes.size(); j++) + { + // Skip the same entry + if(i == j) continue; + + // Get the J entry + uint256 hashTxJ = tokenTxHashes[j]; + auto itTxJ = mapTokenTx.find(hashTxJ); + if(itTxJ == mapTokenTx.end()) continue; + CTokenTx tokenTxJ = itTxJ->second; + + // Compare I and J entries + if(tokenTxI.strContractAddress != tokenTxJ.strContractAddress) continue; + if(tokenTxI.strSenderAddress != tokenTxJ.strSenderAddress) continue; + if(tokenTxI.strReceiverAddress != tokenTxJ.strReceiverAddress) continue; + if(tokenTxI.blockHash != tokenTxJ.blockHash) continue; + if(tokenTxI.blockNumber != tokenTxJ.blockNumber) continue; + if(tokenTxI.transactionHash != tokenTxJ.transactionHash) continue; + + // Delete the lower entry from disk + size_t nLower = uintTou256(tokenTxI.nValue) < uintTou256(tokenTxJ.nValue) ? i : j; + auto itTx = nLower == i ? itTxI : itTxJ; + uint256 hashTx = nLower == i ? hashTxI : hashTxJ; + + if (!batch.EraseTokenTx(hashTx)) + return false; + + mapTokenTx.erase(itTx); + + NotifyTokenTransactionChanged(this, hashTx, CT_DELETED); + + break; + } + } + + return true; +} + void CWallet::CacheNewScriptPubKeys(const std::set& spks, ScriptPubKeyMan* spkm) { for (const auto& script : spks) { @@ -4571,6 +4811,78 @@ bool CWallet::LoadDelegation(const CDelegationInfo &delegation) return true; } +bool CWallet::AddDelegationEntry(const CDelegationInfo& delegation, bool fFlushOnClose) +{ + LOCK(cs_wallet); + + WalletBatch batch(GetDatabase(), fFlushOnClose); + + uint256 hash = delegation.GetHash(); + + bool fInsertedNew = true; + + std::map::iterator it = mapDelegation.find(hash); + if(it!=mapDelegation.end()) + { + fInsertedNew = false; + } + + // Write to disk + CDelegationInfo wdelegation = delegation; + if(!fInsertedNew) + { + wdelegation.nCreateTime = chain().getAdjustedTime(); + } + else + { + wdelegation.nCreateTime = it->second.nCreateTime; + } + + if (!batch.WriteDelegation(wdelegation)) + return false; + + mapDelegation[hash] = wdelegation; + + NotifyDelegationChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); + + if(fInsertedNew) + { + LogPrintf("AddDelegationEntry %s\n", wdelegation.GetHash().ToString()); + } + + return true; +} + +bool CWallet::RemoveDelegationEntry(const uint256& delegationHash, bool fFlushOnClose) +{ + LOCK(cs_wallet); + + WalletBatch batch(GetDatabase(), fFlushOnClose); + + bool fFound = false; + + std::map::iterator it = mapDelegation.find(delegationHash); + if(it!=mapDelegation.end()) + { + fFound = true; + } + + if(fFound) + { + // Remove from disk + if (!batch.EraseDelegation(delegationHash)) + return false; + + mapDelegation.erase(it); + + NotifyDelegationChanged(this, delegationHash, CT_DELETED); + } + + LogPrintf("RemoveDelegationEntry %s\n", delegationHash.ToString()); + + return true; +} + bool CWallet::LoadSuperStaker(const CSuperStakerInfo &superStaker) { uint256 hash = superStaker.GetHash(); @@ -4579,4 +4891,80 @@ bool CWallet::LoadSuperStaker(const CSuperStakerInfo &superStaker) return true; } +bool CWallet::AddSuperStakerEntry(const CSuperStakerInfo& superStaker, bool fFlushOnClose) +{ + LOCK(cs_wallet); + + WalletBatch batch(GetDatabase(), fFlushOnClose); + + uint256 hash = superStaker.GetHash(); + + bool fInsertedNew = true; + + std::map::iterator it = mapSuperStaker.find(hash); + if(it!=mapSuperStaker.end()) + { + fInsertedNew = false; + } + + // Write to disk + CSuperStakerInfo wsuperStaker = superStaker; + if(!fInsertedNew) + { + wsuperStaker.nCreateTime = chain().getAdjustedTime(); + } + else + { + wsuperStaker.nCreateTime = it->second.nCreateTime; + } + + if (!batch.WriteSuperStaker(wsuperStaker)) + return false; + + mapSuperStaker[hash] = wsuperStaker; + + NotifySuperStakerChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); + + if(fInsertedNew) + { + LogPrintf("AddSuperStakerEntry %s\n", wsuperStaker.GetHash().ToString()); + } + else + { + fUpdatedSuperStaker = true; + } + + return true; +} + +bool CWallet::RemoveSuperStakerEntry(const uint256& superStakerHash, bool fFlushOnClose) +{ + LOCK(cs_wallet); + + WalletBatch batch(GetDatabase(), fFlushOnClose); + + bool fFound = false; + + std::map::iterator it = mapSuperStaker.find(superStakerHash); + if(it!=mapSuperStaker.end()) + { + fFound = true; + } + + if(fFound) + { + // Remove from disk + if (!batch.EraseSuperStaker(superStakerHash)) + return false; + + mapSuperStaker.erase(it); + + NotifySuperStakerChanged(this, superStakerHash, CT_DELETED); + } + + LogPrintf("RemoveSuperStakerEntry %s\n", superStakerHash.ToString()); + + return true; +} + } // namespace wallet diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 0d774f0980..5bb6406f3a 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1158,13 +1158,45 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati void TopUpCallback(const std::set& spks, ScriptPubKeyMan* spkm) override; + /* Add token entry into the wallet */ + bool AddTokenEntry(const CTokenInfo& token, bool fFlushOnClose=true); + + /* Add token tx entry into the wallet */ + bool AddTokenTxEntry(const CTokenTx& tokenTx, bool fFlushOnClose=true); + + /* Get details token tx entry into the wallet */ + bool GetTokenTxDetails(const CTokenTx &wtx, uint256& credit, uint256& debit, std::string& tokenSymbol, uint8_t& decimals) const; + + /* Check if token transaction is mine */ + bool IsTokenTxMine(const CTokenTx &wtx) const; + + /* Remove token entry from the wallet */ + bool RemoveTokenEntry(const uint256& tokenHash, bool fFlushOnClose=true); + + /* Clean token transaction entries in the wallet */ + bool CleanTokenTxEntries(bool fFlushOnClose=true); + /* Load delegation entry into the wallet */ bool LoadDelegation(const CDelegationInfo &delegation); + /* Add delegation entry into the wallet */ + bool AddDelegationEntry(const CDelegationInfo& delegation, bool fFlushOnClose=true); + + /* Remove delegation entry from the wallet */ + bool RemoveDelegationEntry(const uint256& delegationHash, bool fFlushOnClose=true); + /* Load super staker entry into the wallet */ bool LoadSuperStaker(const CSuperStakerInfo &superStaker); + /* Add super staker entry into the wallet */ + bool AddSuperStakerEntry(const CSuperStakerInfo& superStaker, bool fFlushOnClose=true); + + /* Remove super staker entry from the wallet */ + bool RemoveSuperStakerEntry(const uint256& superStakerHash, bool fFlushOnClose=true); + + std::map m_delegations_staker; std::map m_delegations_weight; + std::map m_my_delegations; std::map m_have_coin_superstaker; int m_num_threads = 1; mutable boost::thread_group threads;