Skip to content

Commit

Permalink
Enhancement:
Browse files Browse the repository at this point in the history
- RPCClient: fork detection, highutxos detection.
- UI: Alerts for fork detection and highutxos detection. Allows Autocombine utxos
  • Loading branch information
zimbora committed Sep 25, 2024
1 parent b31e689 commit f7fd7f0
Show file tree
Hide file tree
Showing 32 changed files with 884 additions and 26 deletions.
18 changes: 14 additions & 4 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ BITCOIN_CLI_NAME=__decenomy__-cli
BITCOIN_TX_NAME=__decenomy__-tx

BOOTSTRAP_URL_DEFAULT=https://bootstraps.decenomy.net/
DECENOMY_API_URL_DEFAULT=https://explorer.decenomy.net/api/v2/

dnl Unless the user specified ARFLAGS, force it to be cr
AC_ARG_VAR(ARFLAGS, [Flags for the archiver, defaults to <cr> if not set])
Expand Down Expand Up @@ -122,6 +123,13 @@ AC_ARG_WITH([bootstrap-url],
[BOOTSTRAP_URL="$withval"],
[BOOTSTRAP_URL="$BOOTSTRAP_URL_DEFAULT"])

# Allow the user to specify a different value for DECENOMY_API_URL
AC_ARG_WITH([api-url],
[AS_HELP_STRING([--with-api-url=URL],
[URL for decenomy api])],
[DECENOMY_API_URL="$withval"],
[DECENOMY_API_URL="$DECENOMY_API_URL_DEFAULT"])

# Enable wallet
AC_ARG_ENABLE([wallet],
[AS_HELP_STRING([--disable-wallet],
Expand Down Expand Up @@ -1411,6 +1419,7 @@ AC_DEFINE(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE, [Version is rel
AC_DEFINE(COPYRIGHT_YEAR, _COPYRIGHT_YEAR, [Version is release])
AC_DEFINE_UNQUOTED(PARAMS_DIR, ["$params_path"], [Path to the zk params dir during unit tests on windows])
AC_DEFINE_UNQUOTED([BOOTSTRAP_URL], ["$BOOTSTRAP_URL"], [URL for bootstrap data])
AC_DEFINE_UNQUOTED([DECENOMY_API_URL], ["$DECENOMY_API_URL"], [URL for decenomy api])
AC_SUBST(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR)
AC_SUBST(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR)
AC_SUBST(CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION)
Expand Down Expand Up @@ -1529,10 +1538,11 @@ esac

echo
echo "Options used to compile and link:"
echo " with wallet = $enable_wallet"
echo " with bootstrap = $enable_bootstrap"
echo " bootstrap url = $BOOTSTRAP_URL"
echo " with gui / qt = $bitcoin_enable_qt"
echo " with wallet = $enable_wallet"
echo " with bootstrap = $enable_bootstrap"
echo " bootstrap url = $BOOTSTRAP_URL"
echo " decenomy api url = $DECENOMY_API_URL"
echo " with gui / qt = $bitcoin_enable_qt"
if test x$bitcoin_enable_qt != xno; then
echo " with qtcharts = $use_qtcharts"
fi
Expand Down
3 changes: 3 additions & 0 deletions src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,9 @@ RES_ICONS = \
qt/pivx/res/img/ic-check-peers-off.svg \
qt/pivx/res/img/ic-nav-dashboard.svg \
qt/pivx/res/img/ic-wallet-status-unlocked.svg \
qt/pivx/res/img/ic-package-fork.svg \
qt/pivx/res/img/ic-package-highutxos.svg \
qt/pivx/res/img/ic-wallet-status-unlocked.svg \
qt/pivx/res/img/ic-check-peers.svg \
qt/pivx/res/img/ic-nav-master-active.svg \
qt/pivx/res/img/ic-watch-password-white.svg \
Expand Down
3 changes: 2 additions & 1 deletion src/bootstrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ bool CBootstrap::DownloadAndApply()

try {
// Step 1: Download the bootstrap file
if (!CCurlWrapper::DownloadFile(url, fileName.string(), progressCallback)) {
CCurlWrapper client;
if (!client.DownloadFile(url, fileName.string(), progressCallback)) {
LogPrintf(
"CBootstrap::%s: Failed to download the bootstrap file: %s\n",
__func__,
Expand Down
227 changes: 209 additions & 18 deletions src/curl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@

#include "init.h"
#include "logging.h"
#include "fs.h"

#include <openssl/md5.h>
#include <boost/filesystem.hpp>

namespace fs = boost::filesystem;

// Callback function to write downloaded data to a file
size_t writeCallback(void* data, size_t size, size_t nmemb, void* clientp)
size_t downloadWriteCallback(void* data, size_t size, size_t nmemb, void* clientp)
{
if(ShutdownRequested()) {
LogPrintf(
Expand All @@ -23,20 +29,112 @@ size_t writeCallback(void* data, size_t size, size_t nmemb, void* clientp)
return total_size;
}

bool CCurlWrapper::DownloadFile(
const std::string& url,
const std::string& filename,
curl_xferinfo_callback xferinfoCallback)
{
try {
// Initializes libcurl
const auto curl = curl_easy_init();
if (!curl) {
LogPrintf(
"CCurlWrapper::%s: Error initializing libcurl.\n", __func__);
return false;
}
// Callback function to append downloaded data from a request method
size_t requestWriteCallback(void* ptr, size_t size, size_t nmemb, std::string* data) {
data->append((char*)ptr, size * nmemb);
return size * nmemb;
}

// Callback function to write received headers to a string
size_t headerCallback(void* buffer, size_t size, size_t nmemb, std::string* headers) {
size_t totalSize = size * nmemb;
headers->append((char*)buffer, totalSize);
return totalSize;
}

std::string CalculateMD5(const std::string& filePath) {
std::ifstream file(filePath, std::ios::binary);
if (!file) {
LogPrintf("-MD5: Error opening file: %s\n",filePath);
return "";
}

MD5_CTX mdContext;
MD5_Init(&mdContext);

const int bufferSize = 4096;
char buffer[bufferSize];
while (file) {
file.read(buffer, bufferSize);
MD5_Update(&mdContext, buffer, file.gcount());
}
file.close();

unsigned char digest[MD5_DIGEST_LENGTH];
MD5_Final(digest, &mdContext);

char md5String[MD5_DIGEST_LENGTH * 2 + 1];
for(int i = 0; i < MD5_DIGEST_LENGTH; i++)
sprintf(&md5String[i*2], "%02x", (unsigned int)digest[i]);

return md5String;
}

bool Base64Decode(const std::string &input, std::string &out) {
static constexpr unsigned char kDecodingTable[] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64
};

size_t in_len = input.size();
if (in_len % 4 != 0)
return false;

size_t out_len = in_len / 4 * 3;
if (in_len >= 1 && input[in_len - 1] == '=')
out_len--;
if (in_len >= 2 && input[in_len - 2] == '=')
out_len--;

out.resize(out_len);

for (size_t i = 0, j = 0; i < in_len;) {
uint32_t a = input[i] == '='
? 0 & i++
: kDecodingTable[static_cast<int>(input[i++])];
uint32_t b = input[i] == '='
? 0 & i++
: kDecodingTable[static_cast<int>(input[i++])];
uint32_t c = input[i] == '='
? 0 & i++
: kDecodingTable[static_cast<int>(input[i++])];
uint32_t d = input[i] == '='
? 0 & i++
: kDecodingTable[static_cast<int>(input[i++])];

uint32_t triple =
(a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6);

if (j < out_len)
out[j++] = (triple >> 2 * 8) & 0xFF;
if (j < out_len)
out[j++] = (triple >> 1 * 8) & 0xFF;
if (j < out_len)
out[j++] = (triple >> 0 * 8) & 0xFF;
}

return true;
}

CCurlWrapper::CCurlWrapper() {
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (!curl) {
LogPrintf("CCurlWrapper::%s: Error initializing libcurl.\n", __func__);
}else{
// Gets libcurl version information
const auto info = curl_version_info(CURLVERSION_NOW);
if (info) {
Expand All @@ -53,14 +151,40 @@ bool CCurlWrapper::DownloadFile(
LogPrintf(
"CCurlWrapper::%s: Failed to retrieve libcurl version information.\n",
__func__);
return false;
}
}
}

CCurlWrapper::~CCurlWrapper() {
if (curl) {
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}

bool CCurlWrapper::DownloadFile(
const std::string& url,
const std::string& filename,
curl_xferinfo_callback xferinfoCallback)
{
try {

LogPrintf(
"CCurlWrapper::%s: Downloading from %s\n",
__func__,
url);

if(fs::exists(filename))
fs::remove(filename);

// Try to set permissions
if(!GrantWritePermissions(fs::current_path())){
LogPrintf(
"CCurlWrapper::%s: Couldn't grant permissions for folder: %s\n",
__func__,fs::current_path().string());
return false;
}

// Creates and open the destination file
std::ofstream outputFile(filename, std::ios::binary);
if (!outputFile.is_open()) {
Expand All @@ -82,7 +206,7 @@ bool CCurlWrapper::DownloadFile(
#endif

// Sets file releated parameters
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, downloadWriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &outputFile);

// Sets progress function parameters
Expand All @@ -95,13 +219,38 @@ bool CCurlWrapper::DownloadFile(
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, NULL);
}

// Follow redirects
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

// Set the callback function to receive headers
std::string headers;
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headerCallback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headers);

const auto info = curl_version_info(CURLVERSION_NOW);
LogPrintf("curl: version: %s\n",info->version);
// Set User-Agent header
if (info) {
curl_easy_setopt(curl, CURLOPT_USERAGENT, info->version);
}

// HTTP call execution
const auto res = curl_easy_perform(curl);

// Cleanup
curl_easy_cleanup(curl);
outputFile.close();

/* !! calculate md5hash if available
std::string hexMD5 = CalculateMD5(outputFileName);
std::cout << "calculated md5: " << hexMD5 << std::endl;
// get md5 from header
std::string headerMD5 = "Z+Ye9ExZ/IUfkl/Rb5piiQ==";
std::string decoded = "";
Base64Decode(headerMD5,decoded);
std::string hex = StringToHex(decoded);
std::cout << "headerMD5: " << hex << std::endl;
*/

// Evaluation and return
if (res != CURLE_OK) {
if(!ShutdownRequested()) {
Expand All @@ -122,3 +271,45 @@ bool CCurlWrapper::DownloadFile(

return true;
}

std::string CCurlWrapper::Request(const std::string& url) {

std::string response = "";
try {
LogPrintf("CCurlWrapper::%s: request: %s\n", __func__, url);
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); // Verify the peer's SSL certificate
curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, requestWriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);

#if defined(__APPLE__)
LogPrintf("CCurlWrapper::%s: apple ca path: %s\n", __func__, (const char*)APPLE_CA_PATH);
curl_easy_setopt(curl, CURLOPT_CAINFO, (const char*)APPLE_CA_PATH);
#endif

// Set User-Agent header
curl_version_info_data *info = curl_version_info(CURLVERSION_NOW);

if (info) {
curl_easy_setopt(curl, CURLOPT_USERAGENT, info->version);
}else{
curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl x.xx");
}

CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
LogPrintf("CCurlWrapper::%s: error: Failed to perform HTTP request: %s", __func__, curl_easy_strerror(res));
}
}
} catch (const std::exception& e) {
LogPrintf(
"CCurlWrapper::%s: Error requesting url: %s\n",
__func__, e.what());
return "";
}


return response;
}
7 changes: 6 additions & 1 deletion src/curl.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@
class CCurlWrapper
{
public:
static bool DownloadFile(
CCurlWrapper();
~CCurlWrapper();
bool DownloadFile(
const std::string& url,
const std::string& filename,
curl_xferinfo_callback xferinfoCallback = nullptr);
std::string Request(const std::string& url);
private:
CURL* curl;
};

#endif // CURL_H
Loading

0 comments on commit f7fd7f0

Please sign in to comment.