You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
248 lines
9.5 KiB
248 lines
9.5 KiB
/* |
|
* Copyright (c) 2021, evilny0 |
|
* |
|
* This file is part of cpfm. |
|
* |
|
* cpfm is free software: you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation, either version 3 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* cpm is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
|
|
* You should have received a copy of the GNU General Public License |
|
* along with cpfm. If not, see <http://www.gnu.org/licenses/>. |
|
* |
|
*/ |
|
|
|
#include "wallets/wallet_type_eth.h" |
|
|
|
SQLPP_ALIAS_PROVIDER(max_raw_tx_id); |
|
|
|
void WalletTypeETH::update() |
|
{ |
|
if (!m_walletId) |
|
{ |
|
lerr << "Wallet id not defined. Ignoring update."; |
|
} |
|
|
|
linfo << "Analyzing " << getBlockchainName(m_blockchainId) << " wallet " << m_walletId; |
|
|
|
mysql::connection db(getMysqlConfig()); |
|
const auto wallets = TableWallets{}; |
|
const auto wallets_addresses = TableWalletsAddresses{}; |
|
const auto wallets_tx = TableWalletsTx{}; |
|
|
|
// Load wallet address |
|
string address = db(select(wallets.wallet_id,wallets.type_id,wallets_addresses.address).from(wallets.cross_join(wallets_addresses)).where(wallets.wallet_id == wallets_addresses.wallet_id and wallets.wallet_id == m_walletId and wallets.type_id == m_walletTypeId)).front().address; |
|
|
|
// Get wallet tx data from data source and insert it in the DB raw tables. |
|
list<BlockchainTxDetailsTypeETH> l; |
|
l = getTxDetailsListForAddress(address); |
|
addTxDetailsListToRawDB(m_walletId,l); |
|
|
|
// Load tx data from DB raw tables, analyze data, and insert it in DB tables. |
|
l = getTxDetailsListFromRawDB(m_walletId); |
|
|
|
db(remove_from(wallets_tx).where(wallets_tx.wallet_id == m_walletId)); |
|
|
|
addTxDetailsListToDB(m_walletId,address,l); |
|
updateBalanceFromTxDetailsInDB(m_walletId); |
|
} |
|
|
|
void WalletTypeETH::addTxDetailsListToRawDB(const int walletId, const list<BlockchainTxDetailsTypeETH>& l) |
|
{ |
|
mysql::connection db(getMysqlConfig()); |
|
const auto wallets_eth_raw_tx = TableWalletsEthRawTx{}; |
|
const auto blockchain_eth_raw_tx = TableBlockchainEthRawTx{}; |
|
const auto blockchain_eth_raw_tx_details = TableBlockchainEthRawTxDetails{}; |
|
|
|
linfo << "Clearing tx raw data links for " << getBlockchainName(m_blockchainId) << " wallet " << walletId << "."; |
|
|
|
const auto result = db(remove_from(wallets_eth_raw_tx).where(wallets_eth_raw_tx.wallet_id == walletId)); |
|
|
|
linfo << "Now adding raw data to DB for " << getBlockchainName(m_blockchainId) << " wallet " << walletId << "."; |
|
|
|
for (const auto& tx: l) |
|
{ |
|
string hash = tx.hash; |
|
|
|
ldebug << "Adding raw data to DB for tx " << hash << "."; |
|
|
|
const auto result = db(select(blockchain_eth_raw_tx.raw_tx_id).from(blockchain_eth_raw_tx).where(blockchain_eth_raw_tx.hash == hash and blockchain_eth_raw_tx.blockchain_id == m_blockchainId)); |
|
if (!result.empty()) |
|
{ |
|
ldebug << "Raw data for tx " << hash << " is already in DB. Ignoring."; |
|
|
|
db(insert_into(wallets_eth_raw_tx).set( |
|
wallets_eth_raw_tx.raw_tx_id = result.front().raw_tx_id, |
|
wallets_eth_raw_tx.wallet_id = walletId |
|
)); |
|
} |
|
else |
|
{ |
|
Money fee = tx.fee; |
|
|
|
db(insert_into(blockchain_eth_raw_tx).set( |
|
blockchain_eth_raw_tx.hash = hash, |
|
blockchain_eth_raw_tx.unix_time = tx.time.toUnixTime(), |
|
blockchain_eth_raw_tx.blockchain_id = m_blockchainId, |
|
blockchain_eth_raw_tx.fee = fee.toBoostMpf() |
|
)); |
|
|
|
int rawTxId = db(select(max(blockchain_eth_raw_tx.raw_tx_id).as(max_raw_tx_id)).from(blockchain_eth_raw_tx).unconditionally()).front().max_raw_tx_id; |
|
|
|
ldebug << "Raw tax id created : " << rawTxId << "."; |
|
|
|
ldebug << "Adding raw data operations to DB for tx " << hash << "."; |
|
|
|
for (const auto& op : tx.operations) |
|
{ |
|
Money amount = op.amount; |
|
|
|
db(insert_into(blockchain_eth_raw_tx_details).set( |
|
blockchain_eth_raw_tx_details.raw_tx_id = rawTxId, |
|
blockchain_eth_raw_tx_details.address_from = op.addressFrom, |
|
blockchain_eth_raw_tx_details.address_to = op.addressTo, |
|
blockchain_eth_raw_tx_details.amount = amount.toBoostMpf(), |
|
blockchain_eth_raw_tx_details.amount_coin_id = op.amountCoinId |
|
)); |
|
} |
|
|
|
db(insert_into(wallets_eth_raw_tx).set( |
|
wallets_eth_raw_tx.raw_tx_id = rawTxId, |
|
wallets_eth_raw_tx.wallet_id = walletId |
|
)); |
|
} |
|
} |
|
} |
|
|
|
list<BlockchainTxDetailsTypeETH> WalletTypeETH::getTxDetailsListFromRawDB(const int walletId) |
|
{ |
|
mysql::connection db(getMysqlConfig()); |
|
const auto wallets_eth_raw_tx = TableWalletsEthRawTx{}; |
|
const auto blockchain_eth_raw_tx = TableBlockchainEthRawTx{}; |
|
const auto blockchain_eth_raw_tx_details = TableBlockchainEthRawTxDetails{}; |
|
|
|
linfo << "Retrieving data from raw DB for " << getBlockchainName(m_blockchainId) << " wallet " << walletId << "."; |
|
|
|
list<BlockchainTxDetailsTypeETH> l; |
|
for (const auto& rowTx: db.run(select(blockchain_eth_raw_tx.raw_tx_id,blockchain_eth_raw_tx.hash,blockchain_eth_raw_tx.unix_time,blockchain_eth_raw_tx.fee).from(blockchain_eth_raw_tx.cross_join(wallets_eth_raw_tx)).where(blockchain_eth_raw_tx.raw_tx_id == wallets_eth_raw_tx.raw_tx_id and wallets_eth_raw_tx.wallet_id == walletId))) |
|
{ |
|
ldebug << "Retrieving data from raw DB for tx " << rowTx.hash << "."; |
|
|
|
BlockchainTxDetailsTypeETH tx; |
|
|
|
tx.hash = rowTx.hash; |
|
tx.time.setFromUnixTime(rowTx.unix_time); |
|
tx.fee = rowTx.fee; |
|
|
|
ldebug << "Retrieving operations data from raw DB for tx " << rowTx.hash << "."; |
|
|
|
for (const auto& rowOp: db.run(select(blockchain_eth_raw_tx_details.amount,blockchain_eth_raw_tx_details.amount_coin_id,blockchain_eth_raw_tx_details.address_from,blockchain_eth_raw_tx_details.address_to).from(blockchain_eth_raw_tx_details).where(blockchain_eth_raw_tx_details.raw_tx_id == rowTx.raw_tx_id))) |
|
{ |
|
BlockchainTxOperationTypeETH op; |
|
op.addressFrom = rowOp.address_from; |
|
op.addressTo = rowOp.address_to; |
|
op.amount = rowOp.amount; |
|
op.amountCoinId = rowOp.amount_coin_id; |
|
|
|
tx.operations.push_back(op); |
|
} |
|
|
|
l.push_back(tx); |
|
} |
|
|
|
return l; |
|
} |
|
|
|
void WalletTypeETH::addTxDetailsListToDB(const int walletId, string address, const list<BlockchainTxDetailsTypeETH>& l) |
|
{ |
|
mysql::connection db(getMysqlConfig()); |
|
const auto wallets_tx = TableWalletsTx{}; |
|
|
|
linfo << "Now adding data to DB for " << getBlockchainName(m_blockchainId) << " wallet " << walletId << "."; |
|
|
|
for (const auto& tx: l) |
|
{ |
|
ltrace << "Now adding data to DB for tx " << tx.hash << "."; |
|
|
|
bool bFeeAdded = false; |
|
|
|
for (const auto& op: tx.operations) |
|
{ |
|
Money amount; |
|
Money fee; |
|
|
|
if (address == op.addressFrom) |
|
{ |
|
// Even if we have multiple operations for the same tx, the fee only applies once. |
|
if (!bFeeAdded) |
|
{ |
|
// The fee only applies in case this tx was initiated by the wallet |
|
fee = tx.fee; |
|
} |
|
|
|
amount = 0-op.amount; |
|
} |
|
else |
|
{ |
|
amount = op.amount; |
|
} |
|
|
|
db(insert_into(wallets_tx).set( |
|
wallets_tx.wallet_id = walletId, |
|
wallets_tx.amount = amount.toBoostMpf(), |
|
wallets_tx.fee = fee.toBoostMpf(), |
|
wallets_tx.unix_time = tx.time.toUnixTime(), |
|
wallets_tx.amount_coin_id = op.amountCoinId, |
|
wallets_tx.fee_coin_id = m_coinId, |
|
wallets_tx.operation_type = CPFM_WALLET_OPERATION_UNKNOWN |
|
)); |
|
} |
|
} |
|
} |
|
|
|
void WalletTypeETH::updateBalanceFromTxDetailsInDB(int walletId) |
|
{ |
|
mysql::connection db(getMysqlConfig()); |
|
const auto wallets_tx = TableWalletsTx{}; |
|
const auto wallets_balances = TableWalletsBalances{}; |
|
|
|
ldebug << "------------------------------------------------------------"; |
|
|
|
map<int,Money> walletBalances; |
|
|
|
for (const auto& row: db.run(select(wallets_tx.amount, wallets_tx.amount_coin_id, wallets_tx.fee).from(wallets_tx).where(wallets_tx.wallet_id == walletId).order_by(wallets_tx.unix_time.asc()))) |
|
{ |
|
Money txAmount(row.amount); |
|
Money txFee(row.fee); |
|
|
|
walletBalances[row.amount_coin_id] += txAmount; |
|
walletBalances[m_coinId] -= txFee; |
|
|
|
string sReason = "?"; |
|
|
|
ltrace << "Tx Amount: " << txAmount |
|
<< ", Coin: " << getCoinName(row.amount_coin_id) |
|
<< ". Reason: " << sReason |
|
<< ". Tx Fees: " << txFee; |
|
} |
|
|
|
db(remove_from(wallets_balances).where(wallets_balances.wallet_id == walletId)); |
|
|
|
for (const auto b: walletBalances) |
|
{ |
|
linfo << "Wallet " << walletId << " " << getCoinName(b.first) << " balance is: " << b.second; |
|
|
|
Money m = b.second; |
|
db(insert_into(wallets_balances).set( |
|
wallets_balances.wallet_id = walletId, |
|
wallets_balances.coin_id = b.first, |
|
wallets_balances.balance = m.toBoostMpf() |
|
)); |
|
} |
|
}
|
|
|