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.
 
 
 

137 lines
4.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 "datasources/blockchain_info.h"
list<BlockchainTxDetailsTypeBTC> BlockchainDataSourceBTC_BlockchainInfo::getTxDetailsListForAddress(string address)
{
linfo << "Blockchain.info : Analyzing address: " << address;
list<BlockchainTxDetailsTypeBTC> l;
if (!bfs::exists(getCacheFilenameForAddress(address)))
{
saveBlockchainAddressDataToCacheFile(address);
}
if (!bfs::exists(getCacheFilenameForAddress(address)))
{
lerr << "Blockchain.info : cache file could not be found. Address data was not retrieved.";
return l;
}
ifstream f;
f.open(getCacheFilenameForAddress(address));
json::value jvalue = json::value::parse(f);
f.close();
linfo << "Blockchain.info : analyzing address: " << jvalue["address"].as_string();
for (int i=0;i<jvalue["txs"].size();i++)
{
BlockchainTxDetailsTypeBTC tx;
tx.hash = jvalue["txs"][i]["hash"].as_string();
tx.time.setFromUnixTime(jvalue["txs"][i]["time"].as_integer());
for (int j=0;j<jvalue["txs"][i]["inputs"].size();j++)
{
string addr = jvalue["txs"][i]["inputs"][j]["prev_out"]["addr"].as_string();
__int64 amount = jvalue["txs"][i]["inputs"][j]["prev_out"]["value"].as_integer();
Money m = amount;
Money mdecimals = m/100000000;
// The same address can be multiple time in the inputs, so we need to sum the amounts.
tx.inputs[addr] += mdecimals;
}
for (int j=0;j<jvalue["txs"][i]["out"].size();j++)
{
string addr = jvalue["txs"][i]["out"][j]["addr"].as_string();
__int64 amount = jvalue["txs"][i]["out"][j]["value"].as_integer();
Money m = amount;
Money mdecimals = m/100000000;
// The same address can only be once in the outputs.
tx.outputs[addr] = mdecimals;
}
l.push_back(tx);
}
return l;
}
string BlockchainDataSourceBTC_BlockchainInfo::getCacheFilenameForAddress(string address)
{
string cacheFilename("data/cache/blockchain.info/btc/" + address);
return cacheFilename;
}
void BlockchainDataSourceBTC_BlockchainInfo::saveBlockchainAddressDataToCacheFile(string address)
{
try
{
linfo << "Blockchain.info : querying API about " << address;
string sRequestURL = "/rawaddr/";
sRequestURL += address;
http_client apiclient("https://blockchain.info/");
m_currentRequestCacheFilename = getCacheFilenameForAddress(address);
apiclient.request(methods::GET,sRequestURL).then([](http_response response)
{
if (response.status_code() == status_codes::OK)
{
ldebug << "Blockchain.info : response OK.";
return response.extract_json();
}
else if (response.status_code() == status_codes::TooManyRequests)
{
lwarn << "Blockchain.info : too many queries! We are being rate limited.";
pplx::task_from_result(json::value());
}
return pplx::task_from_result(json::value());
})
.then([this](pplx::task<json::value> previousTask)
{
if (previousTask.get() != json::value::null())
{
linfo << "Blockchain.info : saving query result to " << m_currentRequestCacheFilename;
ofstream f;
f.open(m_currentRequestCacheFilename);
f << previousTask.get();
f.close();
}
else
{
lerr << "Blockchain.info : query result is empty. Nothing will be saved to the cache file.";
}
})
.wait();
}
catch(const http::http_exception& e)
{
lerr << "Blockchain.info : failed to query API about " << address;
}
}