Merge pull request #254 into master
c3d128eacontainer: root: test: benchmark/unit: add bitcoin plugin support (Aaron Fiore)0bf4c359container: root: macro: add bitcoin plugin support (Aaron Fiore)2268ae80container: root: src: add bitcoin plugin support (Aaron Fiore)8d6a7960container: plugins: root: add bitcoin plugin (Aaron Fiore)d130d078client: add bitcoin plugin, update custom build deps (Aaron Fiore)
This commit was merged in pull request #254.
This commit is contained in:
@@ -54,6 +54,18 @@ RUN pacman -Syu --noconfirm
|
||||
#WORKDIR /home/@DOCKER_FINANCE_USER@
|
||||
#RUN pipx install xlsx2csv
|
||||
|
||||
##
|
||||
## Plugins (dependencies)
|
||||
##
|
||||
|
||||
## libbitcoinkernel (bitcoin)
|
||||
#RUN pacman -Syu \
|
||||
# boost \
|
||||
# capnproto \
|
||||
# cmake \
|
||||
# db \
|
||||
# --noconfirm --disable-download-timeout
|
||||
|
||||
## Add yours below, as needed
|
||||
|
||||
|
||||
|
||||
341
client/plugins/docker/bitcoin.bash
Executable file
341
client/plugins/docker/bitcoin.bash
Executable file
@@ -0,0 +1,341 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# docker-finance | modern accounting for the power-user
|
||||
#
|
||||
# Copyright (C) 2025 Aaron Fiore (Founder, Evergreen Crypto LLC)
|
||||
#
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#
|
||||
# NOTES:
|
||||
#
|
||||
# This plugin provides a rudimentary clone/pull/build process that
|
||||
# adheres to the expectations from the container-side bitcoin plugin.
|
||||
#
|
||||
# The only requirement for this plugin is that build dependencies
|
||||
# are installed on your existing/running image (which is assumed to
|
||||
# have also been built with the `root` module enabled):
|
||||
#
|
||||
# 1. Uncomment plugin's image build requirements:
|
||||
#
|
||||
# $ dfi <platform/user:tag> edit type=build
|
||||
#
|
||||
# 2. Build/re-build your image with `root` module:
|
||||
#
|
||||
# $ dfi <platform/user:tag> build type=default
|
||||
#
|
||||
# If you do bitcoin development on your client (host) and prefer to
|
||||
# use your own build process, you can skip the above requirements and,
|
||||
# instead, ensure the following:
|
||||
#
|
||||
# 1. Your bitcoin repository is dropped into your client-side shared
|
||||
# directory:
|
||||
#
|
||||
# $DOCKER_FINANCE_CLIENT_SHARED
|
||||
#
|
||||
# The expected path by the container-side plugin will be in your
|
||||
# container-side shared directory:
|
||||
#
|
||||
# "${DOCKER_FINANCE_CONTAINER_SHARED}"/bitcoin
|
||||
#
|
||||
# To see or edit your shared client/container path prior to
|
||||
# running this (or the container's) plugin, run the following:
|
||||
#
|
||||
# $ dfi <platform/user:tag> edit type=env
|
||||
#
|
||||
# 2. Bitcoin's libraries are built as a shared (when possible) and
|
||||
# should continue to remain within the repo's build directory,
|
||||
# prior to running the container-side `root` bitcoin plugin.
|
||||
#
|
||||
|
||||
#
|
||||
# "Libraries"
|
||||
#
|
||||
|
||||
[ -z "$DOCKER_FINANCE_CLIENT_REPO" ] && exit 1
|
||||
source "${DOCKER_FINANCE_CLIENT_REPO}/client/src/docker/lib/lib_docker.bash" || exit 1
|
||||
|
||||
[[ -z "$global_platform" || -z "$global_arg_delim_1" || -z "$global_user" || -z "$global_tag" ]] && lib_utils::die_fatal
|
||||
instance="${global_platform}${global_arg_delim_1}${global_user}:${global_tag}"
|
||||
|
||||
# Initialize "constructor"
|
||||
# NOTE: "constructor" only needed if calling library directly
|
||||
lib_docker::docker "$instance" || lib_utils::die_fatal
|
||||
|
||||
#
|
||||
# Implementation
|
||||
#
|
||||
|
||||
# WARNING: *MUST* be synced with image (assuming Arch Linux finance image)
|
||||
declare -r plugin_bitcoin_deps=("boost" "capnproto" "cmake" "db")
|
||||
|
||||
# WARNING: *MUST* be synced with container's plugin implementation
|
||||
[ -z "$DOCKER_FINANCE_CONTAINER_SHARED" ] && lib_utils::die_fatal
|
||||
declare -r plugin_bitcoin_path="${DOCKER_FINANCE_CONTAINER_SHARED}/bitcoin"
|
||||
|
||||
function bitcoin::__parse_args()
|
||||
{
|
||||
[ -z "$global_usage" ] && lib_utils::die_fatal
|
||||
[ -z "$global_arg_delim_1" ] && lib_utils::die_fatal
|
||||
[ -z "$global_arg_delim_2" ] && lib_utils::die_fatal
|
||||
|
||||
local -r _default_arg_remote="https://github.com/bitcoin/bitcoin"
|
||||
local -r _default_arg_branch="master"
|
||||
local -r _default_arg_cmake="-DBUILD_BITCOIN_BIN=OFF -DBUILD_CLI=OFF -DBUILD_DAEMON=OFF -DBUILD_TESTS=OFF -DBUILD_UTIL=OFF -DBUILD_WALLET_TOOL=OFF -DINSTALL_MAN=OFF -DSECP256K1_BUILD_TESTS=OFF -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF -DBUILD_KERNEL_LIB=ON -DBUILD_SHARED_LIBS=ON"
|
||||
|
||||
# Re-seat global usage
|
||||
local _global_usage
|
||||
_global_usage="$global_usage plugins repo${global_arg_delim_1}$(basename $0)"
|
||||
declare -r _global_usage
|
||||
|
||||
local -r _usage="
|
||||
\e[32mDescription:\e[0m
|
||||
|
||||
Build bitcoin libraries for \`root\` container-side plugin.
|
||||
|
||||
\e[32mUsage:\e[0m
|
||||
|
||||
$ $_global_usage <get | build | clean> [remote${global_arg_delim_2}<remote>] [branch${global_arg_delim_2}<branch>] [cmake${global_arg_delim_2}<cmake>]
|
||||
|
||||
\e[32mArguments:\e[0m
|
||||
|
||||
Git remote to get; default:
|
||||
|
||||
remote${global_arg_delim_2}\"$_default_arg_remote\"
|
||||
|
||||
Git branch to build from; default:
|
||||
|
||||
branch${global_arg_delim_2}\"$_default_arg_branch\"
|
||||
|
||||
CMake build options; default:
|
||||
|
||||
cmake${global_arg_delim_2}\"$_default_arg_cmake\"
|
||||
|
||||
\e[32mExamples:\e[0m
|
||||
|
||||
\e[37;2m# Get from default\e[0m
|
||||
$ $_global_usage get
|
||||
|
||||
\e[37;2m# Get from given remote 'https://my.custom.remote/bitcoin'\e[0m
|
||||
$ $_global_usage get remote${global_arg_delim_2}\"https://my.custom.remote/bitcoin\"
|
||||
|
||||
\e[37;2m# Build default branch\e[0m
|
||||
$ $_global_usage build
|
||||
|
||||
\e[37;2m# Checkout and build given branch\e[0m
|
||||
$ $_global_usage build branch=\"my_dev\"
|
||||
|
||||
\e[37;2m# Checkout and build given commit\e[0m
|
||||
$ $_global_usage build branch=\"b30262dcaa28c40a0a5072847b7194b3db203160\"
|
||||
|
||||
\e[37;2m# Build given branch with custom CMake options\e[0m
|
||||
$ $_global_usage build branch=\"my_dev\" cmake${global_arg_delim_2}\"-DBUILD_BITCOIN_BIN=ON -DBUILD_CLI=ON -DBUILD_DAEMON=ON -DBUILD_TESTS=ON -DBUILD_UTIL=ON -DBUILD_WALLET_TOOL=ON -DINSTALL_MAN=ON -DSECP256K1_BUILD_TESTS=ON -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=ON -DBUILD_KERNEL_LIB=ON -DBUILD_SHARED_LIBS=ON\"
|
||||
|
||||
\e[37;2m# Clean entire build directory\e[0m
|
||||
$ $_global_usage clean
|
||||
"
|
||||
|
||||
[ $# -eq 0 ] && lib_utils::die_usage "$_usage"
|
||||
|
||||
[[ ! "$1" =~ ^get$|^build$|^clean$ ]] \
|
||||
&& lib_utils::die_usage "$_usage" \
|
||||
|| declare -gr plugin_arg_cmd="$1"
|
||||
|
||||
for _arg in "${@:2}"; do
|
||||
[[ ! "$_arg" =~ ^remote${global_arg_delim_2} ]] \
|
||||
&& [[ ! "$_arg" =~ ^branch${global_arg_delim_2} ]] \
|
||||
&& [[ ! "$_arg" =~ ^cmake${global_arg_delim_2} ]] \
|
||||
&& lib_utils::die_usage "$_usage"
|
||||
done
|
||||
|
||||
for _arg in "${@:2}"; do
|
||||
local _key="${_arg%${global_arg_delim_2}*}"
|
||||
local _len="$((${#_key} + 1))"
|
||||
|
||||
if [[ "$_key" =~ ^remote$ ]]; then
|
||||
local _arg_remote="${_arg:${_len}}"
|
||||
[ -z "$_arg_remote" ] && lib_utils::die_usage "$_usage"
|
||||
fi
|
||||
|
||||
if [[ "$_key" =~ ^branch$ ]]; then
|
||||
local _arg_branch="${_arg:${_len}}"
|
||||
[ -z "$_arg_branch" ] && lib_utils::die_usage "$_usage"
|
||||
fi
|
||||
|
||||
if [[ "$_key" =~ ^cmake$ ]]; then
|
||||
local _arg_cmake="${_arg:${_len}}"
|
||||
[ -z "$_arg_cmake" ] && lib_utils::die_usage "$_usage"
|
||||
fi
|
||||
done
|
||||
|
||||
# Arg: get
|
||||
if [[ "$plugin_arg_cmd" =~ ^get$ ]]; then
|
||||
if [[ ! -z "$_arg_branch" || ! -z "$_arg_cmake" ]]; then
|
||||
lib_utils::die_usage "$_usage"
|
||||
fi
|
||||
|
||||
# Arg: remote
|
||||
if [ -z "$_arg_remote" ]; then
|
||||
_arg_remote="$_default_arg_remote"
|
||||
fi
|
||||
declare -gr plugin_arg_remote="$_arg_remote"
|
||||
lib_utils::print_info "Using remote: ${_arg_remote}"
|
||||
fi
|
||||
|
||||
# Arg: build
|
||||
if [[ "$plugin_arg_cmd" =~ ^build$ ]]; then
|
||||
if [[ ! -z "$_arg_remote" ]]; then
|
||||
lib_utils::die_usage "$_usage"
|
||||
fi
|
||||
|
||||
# Arg: branch
|
||||
if [ -z "$_arg_branch" ]; then
|
||||
_arg_branch="$_default_arg_branch"
|
||||
fi
|
||||
declare -gr plugin_arg_branch="$_arg_branch"
|
||||
lib_utils::print_info "Using branch: ${plugin_arg_branch}"
|
||||
|
||||
# Arg: cmake
|
||||
if [ -z "$_arg_cmake" ]; then
|
||||
_arg_cmake="$_default_arg_cmake"
|
||||
fi
|
||||
declare -gr plugin_arg_cmake="$_arg_cmake"
|
||||
lib_utils::print_info "Using CMake options: ${plugin_arg_cmake}"
|
||||
fi
|
||||
|
||||
# Arg: clean
|
||||
if [[ "$plugin_arg_cmd" =~ ^clean$ ]]; then
|
||||
if [[ ! -z "$_arg_remote" || ! -z "$_arg_branch" || ! -z "$_arg_cmake" ]]; then
|
||||
lib_utils::die_usage "$_usage"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function bitcoin::__getter()
|
||||
{
|
||||
[ -z "$plugin_arg_remote" ] && lib_utils::die_fatal
|
||||
[ -z "$plugin_bitcoin_path" ] && lib_utils::die_fatal
|
||||
|
||||
lib_docker::exec "if [ ! -d $plugin_bitcoin_path ]; then git clone $plugin_arg_remote $plugin_bitcoin_path ; fi" \
|
||||
|| lib_utils::die_fatal "Could not clone '${plugin_arg_remote}' to '${plugin_bitcoin_path}'"
|
||||
|
||||
lib_docker::exec "pushd $plugin_bitcoin_path 1>/dev/null && git pull $plugin_arg_remote && popd 1>/dev/null" \
|
||||
|| lib_utils::die_fatal "Could not pull '${plugin_arg_remote}' to '${plugin_bitcoin_path}'"
|
||||
}
|
||||
|
||||
function bitcoin::__builder()
|
||||
{
|
||||
#
|
||||
# Ensure dependencies
|
||||
#
|
||||
|
||||
local -r _no_deps="Build dependencies not found!
|
||||
|
||||
Did you uncomment them with:
|
||||
|
||||
\t\$ dfi $instance edit type=build
|
||||
|
||||
and then re-build your image with:
|
||||
|
||||
\t\$ dfi $instance build type=<type>"
|
||||
|
||||
# NOTE: *MUST* be synced with end-user Dockerfile (`edit type=build`)
|
||||
# TODO: not ideal, would prefer runtime dependency pulling but that has drawbacks as well
|
||||
[ -z "${plugin_bitcoin_deps[*]}" ] && lib_utils::die_fatal
|
||||
lib_docker::exec "pacman -Q ${plugin_bitcoin_deps[*]}" | grep "^error: package" \
|
||||
&& lib_utils::die_fatal "$_no_deps"
|
||||
|
||||
#
|
||||
# Execute build
|
||||
#
|
||||
|
||||
[ -z "$plugin_arg_cmake" ] && lib_utils::die_fatal
|
||||
[ -z "$plugin_bitcoin_path" ] && lib_utils::die_fatal
|
||||
|
||||
lib_docker::exec "pushd $plugin_bitcoin_path 1>/dev/null && git checkout $plugin_arg_branch && popd 1>/dev/null" \
|
||||
|| lib_utils::die_fatal "Could not checkout '${plugin_arg_branch}'"
|
||||
|
||||
lib_docker::exec "cmake $plugin_arg_cmake -B ${plugin_bitcoin_path}/build $plugin_bitcoin_path" \
|
||||
|| lib_utils::die_fatal "Could not prepare build with given options"
|
||||
|
||||
lib_docker::exec "cmake --build ${plugin_bitcoin_path}/build -j$(nproc)" \
|
||||
|| lib_utils::die_fatal "Could not build"
|
||||
|
||||
lib_utils::print_info "$(lib_docker::exec "find ${plugin_bitcoin_path} -name libbitcoinkernel.so")"
|
||||
}
|
||||
|
||||
function bitcoin::__cleaner()
|
||||
{
|
||||
[ -z "$plugin_bitcoin_path" ] && lib_utils::die_fatal
|
||||
local -r _build="${plugin_bitcoin_path}/build"
|
||||
|
||||
lib_utils::print_info "Removing '${_build}'"
|
||||
lib_docker::exec "rm -fr $_build" || lib_utils::die_fatal "Could not delete= '${_build}'"
|
||||
}
|
||||
|
||||
#
|
||||
# Facade
|
||||
#
|
||||
|
||||
function bitcoin::get()
|
||||
{
|
||||
lib_utils::print_info "Getting repository"
|
||||
bitcoin::__getter
|
||||
}
|
||||
|
||||
function bitcoin::build()
|
||||
{
|
||||
lib_utils::print_info "Building repository"
|
||||
bitcoin::__builder
|
||||
}
|
||||
|
||||
function bitcoin::clean()
|
||||
{
|
||||
lib_utils::print_info "Cleaning repository"
|
||||
bitcoin::__cleaner
|
||||
}
|
||||
|
||||
function main()
|
||||
{
|
||||
bitcoin::__parse_args "$@"
|
||||
|
||||
# Ensure running instance
|
||||
local -r _no_instance="Did you start a running instance?
|
||||
|
||||
Run the following in a separate shell:
|
||||
|
||||
\t$ dfi $instance up"
|
||||
|
||||
lib_docker::exec "" || lib_utils::die_fatal "$_no_instance"
|
||||
|
||||
[ -z "$plugin_arg_cmd" ] && lib_utils::die_fatal
|
||||
case "$plugin_arg_cmd" in
|
||||
get)
|
||||
bitcoin::get
|
||||
;;
|
||||
build)
|
||||
bitcoin::build
|
||||
;;
|
||||
clean)
|
||||
bitcoin::clean
|
||||
;;
|
||||
*)
|
||||
lib_utils::die_fatal "Not implemented"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
# vim: sw=2 sts=2 si ai et
|
||||
104
container/plugins/root/bitcoin/bitcoin.cc
Normal file
104
container/plugins/root/bitcoin/bitcoin.cc
Normal file
@@ -0,0 +1,104 @@
|
||||
// docker-finance | modern accounting for the power-user
|
||||
//
|
||||
// Copyright (C) 2025 Aaron Fiore (Founder, Evergreen Crypto LLC)
|
||||
//
|
||||
// This program 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.
|
||||
//
|
||||
// This program 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 this program. If not see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! \file
|
||||
//! \author Aaron Fiore (Founder, Evergreen Crypto LLC)
|
||||
//! \note File intended to be loaded into ROOT.cern framework / Cling interpreter
|
||||
//! \since docker-finance 1.1.0
|
||||
|
||||
//! \namespace dfi::plugin
|
||||
//! \brief docker-finance plugins
|
||||
//! \warning All plugins (repo/custom) must exist within this namespace
|
||||
//! and work within their own inner namespace
|
||||
//! \since docker-finance 1.0.0
|
||||
namespace dfi::plugin
|
||||
{
|
||||
//! \namespace dfi::plugin::bitcoin
|
||||
//! \brief docker-finance bitcoin plugin namespace
|
||||
//! \warning Bitcoin inherently pollutes the global namespace - be wary
|
||||
//! \since docker-finance 1.1.0
|
||||
namespace bitcoin
|
||||
{
|
||||
//! \brief Get container-side path to bitcoin repository
|
||||
//! \return Absolute path of shared (bind-mounted) bitcoin repository
|
||||
//! \todo To avoid future include conflicts, consider adjusting base path
|
||||
//! \since docker-finance 1.1.0
|
||||
inline std::string get_repo_path()
|
||||
{
|
||||
return ::dfi::common::get_env("DOCKER_FINANCE_CONTAINER_SHARED")
|
||||
+ "/bitcoin/";
|
||||
}
|
||||
|
||||
//! \brief Initialize this bitcoin plugin
|
||||
//! \details Bare-essential initializations, will require manual loading for any further functionality
|
||||
//! \warning Initializations *MUST* occur here before any other bitcoin lib use
|
||||
//! \ingroup cpp_plugin_impl
|
||||
//! \since docker-finance 1.1.0
|
||||
void load(const std::string& arg = {})
|
||||
{
|
||||
namespace common = ::dfi::common;
|
||||
|
||||
const std::string repo{get_repo_path()};
|
||||
|
||||
// Minimum requirements
|
||||
common::add_include_dir(repo + "src");
|
||||
common::add_linked_lib(repo + "build/lib/libbitcoinkernel.so");
|
||||
// WARNING: assertions *MUST* be enabled before loading any bitcoin headers
|
||||
common::line("#undef NDEBUG");
|
||||
common::load(repo + "src/kernel/bitcoinkernel_wrapper.h");
|
||||
|
||||
// `dfi`-specific requirements (API, macros, tests, etc.)
|
||||
common::line("#define __DFI_PLUGIN_BITCOIN__");
|
||||
common::load(repo + "src/random.h");
|
||||
// ...add as needed
|
||||
|
||||
if (!arg.empty())
|
||||
common::line(arg);
|
||||
}
|
||||
|
||||
//! \brief Deinitialize this bitcoin plugin
|
||||
//! \details Bare-essential deinitializations, will require manual unloading for any other previously loaded functionality
|
||||
//! \warning Unloading certain bitcoin headers may result in Cling segfault due to bitcoin library design
|
||||
//! \ingroup cpp_plugin_impl
|
||||
//! \since docker-finance 1.1.0
|
||||
//! \todo It appears that, due to bitcoin design, unloading will result in
|
||||
//! Cling segfault "*** Break *** illegal instruction". With that said, it's
|
||||
//! best to exit `root` if you want a clean workspace (instead of unloading this plugin).
|
||||
void unload(const std::string& arg = {})
|
||||
{
|
||||
namespace common = ::dfi::common;
|
||||
|
||||
if (!arg.empty())
|
||||
common::line(arg);
|
||||
|
||||
const std::string repo{get_repo_path()};
|
||||
|
||||
// `dfi`-specific requirements (API, macros, tests, etc.)
|
||||
common::line("#undef __DFI_PLUGIN_BITCOIN__");
|
||||
common::unload(repo + "src/random.h");
|
||||
// ...add as needed
|
||||
|
||||
// Minimum requirements
|
||||
common::unload(repo + "src/kernel/bitcoinkernel_wrapper.h");
|
||||
common::line("#define NDEBUG");
|
||||
// TODO(unassigned): remove_include_dir()
|
||||
common::remove_linked_lib(repo + "build/lib/libbitcoinkernel.so");
|
||||
}
|
||||
} // namespace bitcoin
|
||||
} // namespace dfi::plugin
|
||||
|
||||
// # vim: sw=2 sts=2 si ai et
|
||||
@@ -105,6 +105,21 @@ using Random = ::dfi::crypto::libsodium::Random;
|
||||
auto g_Random = std::make_unique<Random>();
|
||||
} // namespace crypto::libsodium
|
||||
|
||||
#ifdef __DFI_PLUGIN_BITCOIN__
|
||||
//! \namespace dfi::macro::common::crypto::bitcoin
|
||||
//! \since docker-finance 1.1.0
|
||||
namespace crypto::bitcoin
|
||||
{
|
||||
//! \brief ROOT's bitcoin Random class
|
||||
//! \ingroup cpp_macro
|
||||
using Random = ::dfi::crypto::bitcoin::Random;
|
||||
|
||||
//! \brief ROOT's bitcoin Random instance
|
||||
//! \ingroup cpp_macro
|
||||
auto g_Random = std::make_unique<Random>();
|
||||
} // namespace crypto::bitcoin
|
||||
#endif
|
||||
|
||||
} // namespace common
|
||||
} // namespace macro
|
||||
} // namespace dfi
|
||||
|
||||
@@ -47,6 +47,9 @@ namespace common = ::dfi::macro::common;
|
||||
namespace libsodium = common::crypto::libsodium;
|
||||
namespace cryptopp = common::crypto::cryptopp;
|
||||
namespace botan = common::crypto::botan;
|
||||
#ifdef __DFI_PLUGIN_BITCOIN__
|
||||
namespace bitcoin = common::crypto::bitcoin;
|
||||
#endif
|
||||
|
||||
//! \brief CSPRNG macro
|
||||
class Random final
|
||||
@@ -110,6 +113,24 @@ class Random final
|
||||
return rng;
|
||||
}
|
||||
|
||||
#ifdef __DFI_PLUGIN_BITCOIN__
|
||||
//! \brief bitcon RNG
|
||||
//! \return t_rng Random map to print (label, num)
|
||||
static t_rng bitcoin_generate()
|
||||
{
|
||||
t_rng rng;
|
||||
|
||||
rng["int16_t (unsupported)"] = 0;
|
||||
rng["int32_t (unsupported)"] = 0;
|
||||
|
||||
rng["uint16_t (unsupported)"] = 0;
|
||||
rng["uint32_t"] = bitcoin::g_Random->generate<uint32_t>();
|
||||
rng["uint64_t"] = bitcoin::g_Random->generate<uint64_t>();
|
||||
|
||||
return rng;
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
//! \brief Print t_rng of CSPRNG numbers in CSV format
|
||||
static void generate()
|
||||
@@ -122,6 +143,9 @@ class Random final
|
||||
};
|
||||
|
||||
std::cout << "\nimpl,type,num\n";
|
||||
#ifdef __DFI_PLUGIN_BITCOIN__
|
||||
print("bitcoin::Random", Random::bitcoin_generate());
|
||||
#endif
|
||||
print("botan::Random", Random::botan_generate());
|
||||
print("cryptopp::Random", Random::cryptopp_generate());
|
||||
print("libsodium::Random", Random::libsodium_generate());
|
||||
|
||||
@@ -351,6 +351,15 @@ class Random final
|
||||
|
||||
const std::string timestamp{common::make_timestamp()};
|
||||
|
||||
#ifdef __DFI_PLUGIN_BITCOIN__
|
||||
data.title = "Bitcoin_FastRandomContext_32_RNG_" + timestamp;
|
||||
random(data, []() -> uint32_t {
|
||||
return common::crypto::bitcoin::g_Random->generate();
|
||||
});
|
||||
|
||||
// TODO(afiore): uint64_t (requires canvas-related refactor)
|
||||
#endif
|
||||
|
||||
data.title = "Botan_RNG_" + timestamp;
|
||||
random(data, []() -> uint32_t {
|
||||
return common::crypto::botan::g_Random->generate();
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
//! \author Aaron Fiore (Founder, Evergreen Crypto LLC)
|
||||
//! \note File intended to be loaded into ROOT.cern framework / Cling interpreter
|
||||
//! \since docker-finance 1.0.0
|
||||
//! \todo C++20 refactor
|
||||
|
||||
#ifndef CONTAINER_SRC_ROOT_SRC_INTERNAL_IMPL_RANDOM_HH_
|
||||
#define CONTAINER_SRC_ROOT_SRC_INTERNAL_IMPL_RANDOM_HH_
|
||||
@@ -259,6 +260,69 @@ class Random : public common::RandomImpl<libsodium::Random>
|
||||
};
|
||||
} // namespace libsodium
|
||||
|
||||
#ifdef __DFI_PLUGIN_BITCOIN__
|
||||
//! \namespace dfi::crypto::impl::bitcoin
|
||||
//! \since docker-finance 1.1.0
|
||||
namespace bitcoin
|
||||
{
|
||||
//! \concept dfi::crypto::impl::bitcoin::RType
|
||||
//! \brief Random number type
|
||||
//! \details Requirements include that "interface" specialization
|
||||
//! has not changed and that given type is supported by bitcoin.
|
||||
//! \since docker-finance 1.1.0
|
||||
template <typename t_random>
|
||||
concept RType =
|
||||
::dfi::internal::type::is_real_integral<t_random>::value
|
||||
&& (std::same_as<t_random, uint32_t> || std::same_as<t_random, uint64_t>);
|
||||
|
||||
//! \brief Implements Random API with bitcoin
|
||||
//! \ingroup cpp_API_impl
|
||||
//! \since docker-finance 1.1.0
|
||||
//! \todo span/bytes
|
||||
//! \todo reseed
|
||||
//! \todo insecure RNG option
|
||||
class Random : public common::RandomImpl<bitcoin::Random>
|
||||
{
|
||||
public:
|
||||
Random() = default;
|
||||
~Random() = default;
|
||||
|
||||
Random(const Random&) = delete;
|
||||
Random& operator=(const Random&) = delete;
|
||||
|
||||
Random(Random&&) = delete;
|
||||
Random& operator=(Random&&) = delete;
|
||||
|
||||
private:
|
||||
//! \brief Implements random number generator
|
||||
template <RType t_random>
|
||||
t_random generate_impl()
|
||||
{
|
||||
if constexpr (std::same_as<t_random, uint32_t>)
|
||||
{
|
||||
return m_ctx.rand32();
|
||||
}
|
||||
else if constexpr (std::same_as<t_random, uint64_t>)
|
||||
{
|
||||
return m_ctx.rand64();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
//! \brief Generate random number
|
||||
template <RType t_random>
|
||||
t_random generate()
|
||||
{
|
||||
return this->generate_impl<t_random>();
|
||||
}
|
||||
|
||||
private:
|
||||
//! \warning Bitcoin's RNG is not thread-safe (but dfi's CRTP provides external locks, by default)
|
||||
::FastRandomContext m_ctx;
|
||||
};
|
||||
} // namespace bitcoin
|
||||
#endif
|
||||
|
||||
} // namespace impl
|
||||
} // namespace crypto
|
||||
} // namespace dfi
|
||||
|
||||
@@ -118,6 +118,20 @@ namespace libsodium
|
||||
using Random = ::dfi::crypto::common::Random<impl::libsodium::Random>;
|
||||
} // namespace libsodium
|
||||
|
||||
#ifdef __DFI_PLUGIN_BITCOIN__
|
||||
//! \namespace dfi::crypto::bitcoin
|
||||
//! \brief Public-facing API namespace (bitcoin)
|
||||
//! \since docker-finance 1.1.0
|
||||
namespace bitcoin
|
||||
{
|
||||
//! \brief bitcoin Random API specialization ("interface" / implementation)
|
||||
//! \note For public consumption
|
||||
//! \ingroup cpp_API
|
||||
//! \since docker-finance 1.1.0
|
||||
using Random = ::dfi::crypto::common::Random<impl::bitcoin::Random>;
|
||||
} // namespace bitcoin
|
||||
#endif
|
||||
|
||||
} // namespace crypto
|
||||
} // namespace dfi
|
||||
|
||||
|
||||
@@ -128,6 +128,30 @@ BENCHMARK_F(RandomLibsodium, generate)(::benchmark::State& state) // NOLINT
|
||||
random.generate();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Bitcoin
|
||||
//
|
||||
|
||||
#ifdef __DFI_PLUGIN_BITCOIN__
|
||||
//! \brief Bitcoin Random fixture w/ real implementation
|
||||
//! \since docker-finance 1.1.0
|
||||
struct RandomBitcoin : public ::benchmark::Fixture,
|
||||
public tests::RandomBitcoin_Impl
|
||||
{
|
||||
void SetUp(const ::benchmark::State& state) {}
|
||||
void TearDown(const ::benchmark::State& state) {}
|
||||
};
|
||||
|
||||
BENCHMARK_F(RandomBitcoin, generate)(::benchmark::State& state) // NOLINT
|
||||
{
|
||||
for (auto st : state)
|
||||
{
|
||||
random.generate();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace benchmarks
|
||||
} // namespace tests
|
||||
} // namespace dfi
|
||||
|
||||
@@ -90,6 +90,18 @@ struct RandomLibsodium_Impl
|
||||
using Random = ::dfi::crypto::libsodium::Random;
|
||||
Random random;
|
||||
};
|
||||
|
||||
#ifdef __DFI_PLUGIN_BITCOIN__
|
||||
//! \brief Bitcoin random implementation fixture
|
||||
//! \since docker-finance 1.1.0
|
||||
struct RandomBitcoin_Impl
|
||||
{
|
||||
protected:
|
||||
using Random = ::dfi::crypto::bitcoin::Random;
|
||||
Random random;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace tests
|
||||
} // namespace dfi
|
||||
|
||||
|
||||
@@ -70,6 +70,11 @@ TEST_F(RandomInterface, generate_uint32_t)
|
||||
ASSERT_EQ(random.generate<uint32_t>(), std::numeric_limits<uint32_t>::max());
|
||||
}
|
||||
|
||||
TEST_F(RandomInterface, generate_uint64_t)
|
||||
{
|
||||
ASSERT_EQ(random.generate<uint64_t>(), std::numeric_limits<uint64_t>::max());
|
||||
}
|
||||
|
||||
TEST_F(RandomInterface, generate_int16_t)
|
||||
{
|
||||
ASSERT_EQ(random.generate<int16_t>(), std::numeric_limits<int16_t>::max());
|
||||
@@ -96,9 +101,13 @@ struct RandomFixture : public ::testing::Test, protected t_impl
|
||||
auto two = t_impl::random.template generate<t_random>();
|
||||
static_assert(std::is_same_v<decltype(two), t_random>);
|
||||
|
||||
// NOTE: t_random limits are implementation-specific
|
||||
ASSERT_NEAR(0, one, std::numeric_limits<t_random>::max());
|
||||
ASSERT_NEAR(0, two, std::numeric_limits<t_random>::max());
|
||||
// TODO(unassigned): gtest implicit conversion of uint64_t with ASSERT_NEAR
|
||||
if constexpr (!std::is_same_v<t_random, uint64_t>)
|
||||
{
|
||||
// NOTE: t_random limits are implementation-specific
|
||||
ASSERT_NEAR(0, one, std::numeric_limits<t_random>::max());
|
||||
ASSERT_NEAR(0, two, std::numeric_limits<t_random>::max());
|
||||
}
|
||||
|
||||
// Exceedingly rare (tests the obvious, but is not an accurate entropy test)
|
||||
// If fails, re-run tests to confirm
|
||||
@@ -176,6 +185,28 @@ TEST_F(RandomLibsodium, generate_uint32_t)
|
||||
ASSERT_NO_THROW(generate<uint32_t>());
|
||||
}
|
||||
|
||||
#ifdef __DFI_PLUGIN_BITCOIN__
|
||||
//
|
||||
// Bitcoin
|
||||
//
|
||||
|
||||
//! \brief Bitcoin random number fixture
|
||||
//! \since docker-finance 1.1.0
|
||||
struct RandomBitcoin : public RandomFixture<tests::RandomBitcoin_Impl>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_F(RandomBitcoin, generate_uint32_t)
|
||||
{
|
||||
ASSERT_NO_THROW(generate<uint32_t>());
|
||||
}
|
||||
|
||||
TEST_F(RandomBitcoin, generate_uint64_t)
|
||||
{
|
||||
ASSERT_NO_THROW(generate<uint64_t>());
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace unit
|
||||
} // namespace tests
|
||||
} // namespace dfi
|
||||
|
||||
Reference in New Issue
Block a user