Skip to content

Commit 0a06873

Browse files
committed
token balances fixed
1 parent f081e90 commit 0a06873

3 files changed

Lines changed: 110 additions & 81 deletions

File tree

api/include/tokens.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ struct Token {
4242
std::string totalSupply { "not loaded" };
4343

4444
struct HolderInfo {
45-
std::string balance { "not loaded" };
45+
std::string balance { "0" };
4646
uint64_t transfersCount = 0;
4747
};
4848
std::map<HolderKey, HolderInfo> holders; // Including guys with zero balance
@@ -60,7 +60,7 @@ class TokensMaster {
6060

6161
void checkNewState(const csdb::Address& sc, const csdb::Address& initiator, const api::SmartContractInvocation&, const std::string& newState);
6262

63-
void loadTokenInfo(const std::vector<csdb::Address>& vaddr, const std::function<void(const TokensMap&, const HoldersMap&)>, bool needLoad = true);
63+
void loadTokenInfo(const std::vector<csdb::Address>& vaddr, const std::function<void(const TokensMap&, const HoldersMap&)>);
6464

6565
static bool isTransfer(const std::string& method, const std::vector<general::Variant>& params);
6666

api/src/apihandler.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,7 +1604,18 @@ void APIHandler::ExecuteCountGet(ExecuteCountGetResult& _return, const std::stri
16041604

16051605
void APIHandler::TokenBalancesGet(api::TokenBalancesResult& _return, const general::Address& address) {
16061606
const csdb::Address addr = BlockChain::getAddressFromKey(address);
1607-
tm.loadTokenInfo(std::vector(1, addr), [&_return, &addr](const TokensMap& tokens, const HoldersMap& holders) {
1607+
1608+
std::vector<csdb::Address> vtokenAddr;
1609+
tm.loadTokenInfo({}, [&vtokenAddr, &addr](const TokensMap& tokens, const HoldersMap& holders) {
1610+
if (auto holderIt = holders.find(addr); holderIt != holders.end()) {
1611+
for (const auto& tokAddr : holderIt->second) {
1612+
if (tokens.find(tokAddr) != tokens.end())
1613+
vtokenAddr.push_back(tokAddr);
1614+
}
1615+
}
1616+
});
1617+
1618+
tm.loadTokenInfo(vtokenAddr, [&_return, &addr](const TokensMap& tokens, const HoldersMap& holders) {
16081619
auto holderIt = holders.find(addr);
16091620
if (holderIt != holders.end()) {
16101621
for (const auto& tokAddr : holderIt->second) {
@@ -1712,7 +1723,7 @@ void APIHandler::TokenTransfersListGet(api::TokenTransfersResult& _return, int64
17121723
totalTransfers += t.second.transfersCount;
17131724
tokenTransPools.insert(std::make_pair(s_blockchain.getLastTransaction(t.first).pool_seq(), t.first));
17141725
}
1715-
}, false);
1726+
});
17161727

17171728
_return.count = uint32_t(totalTransfers);
17181729

@@ -1780,7 +1791,6 @@ void APIHandler::TokenTransactionsGet(api::TokenTransactionsResult& _return, con
17801791

17811792
void APIHandler::TokenInfoGet(api::TokenInfoResult& _return, const general::Address& token) {
17821793
bool found = false;
1783-
17841794
const csdb::Address addr = BlockChain::getAddressFromKey(token);
17851795
tm.loadTokenInfo(std::vector<csdb::Address>(1, addr), [&token, &addr, &found, &_return](const TokensMap& tm, const HoldersMap&) {
17861796
auto tIt = tm.find(addr);
@@ -1789,7 +1799,6 @@ void APIHandler::TokenInfoGet(api::TokenInfoResult& _return, const general::Addr
17891799
putTokenInfo(_return.token, token, tIt->second);
17901800
}
17911801
});
1792-
17931802
SetResponseStatus(_return.status, found ? APIRequestStatusType::SUCCESS : APIRequestStatusType::FAILURE);
17941803
}
17951804

@@ -1882,17 +1891,26 @@ void APIHandler::TokensListGet(api::TokensListResult& _return, int64_t offset, i
18821891

18831892
switch (order) {
18841893
case TL_Code:
1894+
#ifdef SLOW_WORK
18851895
comparator = getComparator<VT>(&Token::symbol, desc);
18861896
break;
1897+
#endif
1898+
[[fallthrough]];
18871899
case TL_Name:
1900+
#ifdef SLOW_WORK
18881901
comparator = getComparator<VT>(&Token::name, desc);
18891902
break;
1890-
case TL_Address:
1891-
comparator = [desc](const VT& lhs, const VT& rhs) { return desc ^ (lhs.first < rhs.first); };
1892-
break;
1903+
#endif
1904+
[[fallthrough]];
18931905
case TL_TotalSupply:
1906+
#ifdef SLOW_WORK
18941907
comparator = [desc](const VT& lhs, const VT& rhs) { return desc ^ (stod(lhs.second.totalSupply) < stod(rhs.second.totalSupply)); };
18951908
break;
1909+
#endif
1910+
[[fallthrough]];
1911+
case TL_Address:
1912+
comparator = [desc](const VT& lhs, const VT& rhs) { return desc ^ (lhs.first < rhs.first); };
1913+
break;
18961914
case TL_HoldersCount:
18971915
comparator = getComparator<VT>(&Token::realHoldersCount, desc);
18981916
break;

api/src/tokens.cpp

Lines changed: 83 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -184,47 +184,7 @@ void TokensMaster::refreshTokenState(const csdb::Address& token, const std::stri
184184
auto& t = tokens_[token];
185185
t.name = name;
186186
t.symbol = symbol;
187-
t.totalSupply = totalSupply;
188-
189-
// balance
190-
if (checkBalance) {
191-
executor::ExecuteByteCodeMultipleResult result;
192-
if (byteCodeObjects.empty())
193-
return;
194-
195-
executor::SmartContractBinary smartContractBinary;
196-
smartContractBinary.contractAddress = addr;
197-
smartContractBinary.object.byteCodeObjects = byteCodeObjects;
198-
smartContractBinary.object.instance = newState;
199-
smartContractBinary.stateCanModify = 0;
200-
201-
std::vector<csdb::Address> holders;
202-
holders.reserve(t.holders.size());
203-
for (auto& h : t.holders)
204-
holders.push_back(h.first);
205-
206-
std::vector<std::vector<general::Variant>> holderKeysParams;
207-
holderKeysParams.reserve(holders.size());
208-
for (auto& h : holders) {
209-
general::Variant var;
210-
auto key = h.public_key();
211-
var.__set_v_string(EncodeBase58(cs::Bytes(key.begin(), key.end())));
212-
holderKeysParams.push_back(std::vector<general::Variant>(1, var));
213-
}
214-
215-
api_->getExecutor().executeByteCodeMultiple(result, dpAddr, smartContractBinary, "balanceOf", holderKeysParams, 100, executor::Executor::kUseLastSequence);
216-
217-
++t.realHoldersCount = 0;
218-
if (!result.status.code && (result.results.size() == holders.size())) {
219-
for (uint32_t i = 0; i < holders.size(); ++i) {
220-
const auto& res = result.results[i];
221-
if (!res.status.code) {
222-
t.holders[holders[i]].balance = tryExtractAmount(getVariantAs<std::string>(res.ret_val));
223-
++t.realHoldersCount;
224-
}
225-
}
226-
}
227-
}
187+
t.totalSupply = totalSupply;
228188
}
229189

230190
/* Call under data lock only */
@@ -269,6 +229,73 @@ void TokensMaster::updateTokenChaches(const csdb::Address& addr, const std::stri
269229
initiateHolder(tIt->second, tIt->first, regDude);
270230
}
271231
}
232+
233+
// Balance update
234+
auto refreshBalance = [&](const csdb::Address& addrFrom, const csdb::Address& addrTo = csdb::Address{}, const std::string& amount = "") {
235+
auto getCurrBalance = [&](const csdb::Address& addrOwner) -> std::string {
236+
bool present = false;
237+
auto byteCodeObjects = api_->getSmartByteCode(addr, present);
238+
if (!present || byteCodeObjects.empty()) return "0";
239+
240+
general::Address addrToken{ addr.public_key().begin(), addr.public_key().end() };
241+
242+
auto dpAddrPK = tokens_[addr].owner.public_key();
243+
general::Address dpAddr{ dpAddrPK.begin(), dpAddrPK.end() };
244+
245+
// param: owner
246+
std::vector<general::Variant> param(1);
247+
std::string addrOwnerStr = addrOwner.to_api_addr();
248+
param[0].__set_v_string(EncodeBase58({ addrOwnerStr.begin(), addrOwnerStr.end() }));
249+
//
250+
std::string retBalance{ "0" };
251+
executeAndCall<std::string>(api_, dpAddr, addrToken, byteCodeObjects, newState, "balanceOf", param,
252+
[&retBalance](const std::string& balance) { retBalance = balance; });
253+
254+
if (!std::all_of(retBalance.begin(), retBalance.end(), [](char ch) { return (isdigit(ch) || ch == '.'); })) {
255+
retBalance = "0";
256+
cserror() << "executor return text balance!";
257+
}
258+
return retBalance;
259+
};
260+
261+
auto& t = tokens_[addr];
262+
if (addrTo == csdb::Address{}) { // for deploy token
263+
t.holders[addrFrom].balance = getCurrBalance(addrFrom);
264+
++t.realHoldersCount;
265+
return;
266+
}
267+
268+
// from
269+
auto& currFromBalance = t.holders[addrFrom].balance;
270+
auto newFromBalance = [&] {
271+
if (isZeroAmount(currFromBalance))
272+
return getCurrBalance(addrFrom);
273+
else
274+
return std::to_string(stof(currFromBalance) - stof(amount));
275+
}();
276+
if (isZeroAmount(newFromBalance))
277+
--t.realHoldersCount;
278+
currFromBalance = newFromBalance;
279+
280+
// to
281+
auto& currToBalance = t.holders[addrTo].balance;
282+
auto newToBalance = [&] {
283+
if (isZeroAmount(currToBalance))
284+
return getCurrBalance(addrTo);
285+
else
286+
return std::to_string(stof(currToBalance) + stof(amount));
287+
}();
288+
if (isZeroAmount(currToBalance) && !isZeroAmount(newToBalance))
289+
++t.realHoldersCount;
290+
currToBalance = newToBalance;
291+
};
292+
293+
if (ps.method == "transfer" && ps.params.size() == 2)
294+
refreshBalance(ps.initiator, tryExtractPublicKey(ps.params[0].v_string), ps.params[1].v_string);
295+
else if (ps.method == "transferFrom" && ps.params.size() == 3)
296+
refreshBalance(tryExtractPublicKey(ps.params[0].v_string), tryExtractPublicKey(ps.params[1].v_string), ps.params[2].v_string);
297+
else if (ps.method.empty()) // deploy token
298+
refreshBalance(tokens_[addr].owner);
272299
}
273300

274301
void TokensMaster::checkNewDeploy(const csdb::Address& sc, const csdb::Address& deployer, const api::SmartContractInvocation& sci) {
@@ -303,40 +330,24 @@ void TokensMaster::checkNewState(const csdb::Address& sc, const csdb::Address& i
303330
updateTokenChaches(sc, newState, ps);
304331
}
305332

306-
void TokensMaster::loadTokenInfo(const std::vector<csdb::Address>& vtokenAddr, const std::function<void(const TokensMap&, const HoldersMap&)> func, bool needLoad) {
333+
void TokensMaster::loadTokenInfo(const std::vector<csdb::Address>& vtokenAddr, const std::function<void(const TokensMap&, const HoldersMap&)> func) {
307334
std::lock_guard<decltype(dataMut_)> l(dataMut_);
308-
if (!needLoad) {
335+
if (vtokenAddr.empty()) {
309336
func(tokens_, holders_);
310337
return;
311338
}
312-
auto freeChache = [&tokens_ = tokens_](const csdb::Address& addr, bool checkBalance = true) {
313-
tokens_[addr].name = "not loaded";
314-
tokens_[addr].symbol = "not loaded";
315-
tokens_[addr].totalSupply = "not loaded";
316-
if (checkBalance) {
317-
for (auto& h : tokens_[addr].holders)
318-
h.second.balance = "not loaded";
319-
}
320-
};
321-
322-
if (!vtokenAddr.empty()) {
323-
TokensMap loadedToken;
324-
for (const auto& addr : vtokenAddr) {
325-
if (tokens_.find(addr) == tokens_.end())
326-
continue;
327-
refreshTokenState(addr, cs::SmartContracts::get_contract_state(api_->get_s_blockchain(), addr));
328-
loadedToken[addr] = tokens_[addr];
329-
}
330-
func(loadedToken, holders_);
331-
for (const auto& itLoaded : loadedToken)
332-
freeChache(itLoaded.first);
333-
}
334-
else {
335-
for (const auto& tk : tokens_) // need for sort
336-
refreshTokenState(tk.first, cs::SmartContracts::get_contract_state(api_->get_s_blockchain(), tk.first), false);
337-
func(tokens_, holders_);
338-
for (const auto& tk : tokens_)
339-
freeChache(tk.first, false);
339+
TokensMap loadedToken;
340+
for (const auto& addr : vtokenAddr) {
341+
if (tokens_.find(addr) == tokens_.end())
342+
continue;
343+
refreshTokenState(addr, cs::SmartContracts::get_contract_state(api_->get_s_blockchain(), addr));
344+
loadedToken[addr] = tokens_[addr];
345+
}
346+
func(loadedToken, holders_);
347+
for (const auto& itLoaded : loadedToken) {
348+
tokens_[itLoaded.first].name = "not loaded";
349+
tokens_[itLoaded.first].symbol = "not loaded";
350+
tokens_[itLoaded.first].totalSupply = "not loaded";
340351
}
341352
}
342353

@@ -380,7 +391,7 @@ void TokensMaster::checkNewDeploy(const csdb::Address&, const csdb::Address&, co
380391
}
381392
void TokensMaster::checkNewState(const csdb::Address&, const csdb::Address&, const api::SmartContractInvocation&, const std::string&) {
382393
}
383-
void TokensMaster::loadTokenInfo(const std::vector<csdb::Address>&, const std::function<void(const TokensMap&, const HoldersMap&)>, bool) {
394+
void TokensMaster::loadTokenInfo(const std::vector<csdb::Address>&, const std::function<void(const TokensMap&, const HoldersMap&)>) {
384395
}
385396
bool TokensMaster::isTransfer(const std::string&, const std::vector<general::Variant>&) {
386397
return false;

0 commit comments

Comments
 (0)