Merge master into ublocks (#714)
* Fix typos (#683)
* Move to C++14
Replaces a single reset with make_unique to see if things compile in CI. Also reverts a CI-specific RPATH change which prevented the wallet from running on macOS dev machines
* Update CMakeLists.txt to support gtest linking for Windows
* Fix test for wallet_create_max to allow for utx database addition (#691)
* Remove unused code (#686)
* Fix docker boost url
* Revert nonWalletDbs
Revert to fix failing tests
* Improved error handling in message parser (#704)
* Replacing bool get_optional with get default values (#670)
* Revert "Watch only accounts"
This reverts commit 1b0809a3af
.
* Replacing bool get_optional with get default values
* RPC tests for optional bool values
* RPC tests for wallet_ledger & wallet_add_watch
* Improve account history RPC endpoint (#668)
* Checking ledger::forked_block preconditions which were asserting.
* Update README (#709)
* update docs to add guides and update "what is nano?" system
* add whitepaper to guides and docs
* update features list
* update what is nano header level
* Build of Boost Cleanup (#707)
* Updated to check the boost SHA256 when downloading
* Fixed invalid shell option
* Allow the user to request a minimal build of Boost
* Ensure boost build script exits on error
* Removed apparently unused "mkdir"
* Docker altnets (#708)
* Updated to check the boost SHA256 when downloading
* Fixed invalid shell option
* Allow the user to request a minimal build of Boost
* Ensure boost build script exits on error
* Removed apparently unused "mkdir"
* Updated Docker build for node to support altnets
* Allow user-supplied arguments to "docker build"
* Updated Docker auto deploy to build a live and beta image for each tag
* Print the correct image name when building the docker image
* Corrected typo for the test network
* Broadcasting active elections blocks to discovered representatives (#711)
* Broadcasting active elections blocks
* Improve formatting for clang
* Connecting to rai-beta for beta network.
* Specify beta network representatives (#712)
* Update the beta network configuration (#713)
* Specify beta network representatives
* Update beta network genesis block
* Use port 54000 for beta nodes
* Add history RPC raw support to ublocks
* Fix test for wallet_create_max to allow for utx database addition (#691)
This commit is contained in:
parent
f5c462aad0
commit
755dae8612
36 changed files with 1006 additions and 455 deletions
|
@ -7,12 +7,8 @@ set (CPACK_PACKAGE_VERSION_PATCH "1")
|
|||
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks")
|
||||
else()
|
||||
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib:\$ORIGIN/")
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
endif()
|
||||
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib:\$ORIGIN/")
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
|
||||
set (RAIBLOCKS_GUI OFF CACHE BOOL "")
|
||||
set (RAIBLOCKS_TEST OFF CACHE BOOL "")
|
||||
|
@ -70,7 +66,7 @@ endif (WIN32)
|
|||
if (WIN32)
|
||||
set (PLATFORM_CXX_FLAGS "/bigobj")
|
||||
else (WIN32)
|
||||
set (PLATFORM_CXX_FLAGS "-std=c++11")
|
||||
set (PLATFORM_CXX_FLAGS "-std=c++14")
|
||||
endif (WIN32)
|
||||
|
||||
if (WIN32)
|
||||
|
@ -146,6 +142,11 @@ else ()
|
|||
set (ARGON_CORE phc-winner-argon2/src/ref.c)
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
set (gtest_force_shared_crt ON)
|
||||
else ()
|
||||
set (gtest_force_shared_crt OFF)
|
||||
endif()
|
||||
add_subdirectory (gtest)
|
||||
include_directories ("gtest/include")
|
||||
|
||||
|
|
|
@ -925,7 +925,7 @@ function(_Boost_MISSING_DEPENDENCIES componentvar extravar)
|
|||
endfunction()
|
||||
|
||||
#
|
||||
# Some boost libraries may require particular set of compler features.
|
||||
# Some boost libraries may require particular set of compiler features.
|
||||
# The very first one was `boost::fiber` introduced in Boost 1.62.
|
||||
# One can check required compiler features of it in
|
||||
# `${Boost_ROOT}/libs/fiber/build/Jamfile.v2`.
|
||||
|
|
58
README.md
58
README.md
|
@ -1,33 +1,53 @@
|
|||
<hr />
|
||||
<div align="center">
|
||||
<img src="images/logo.svg" alt="Logo" width='300px' height='auto'/>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
[](https://travis-ci.org/nanocurrency/raiblocks)
|
||||
|
||||
# What is Nano?
|
||||
Nano is designed to be a feeless, instant, high throughput cryptocurrency.
|
||||
### What is Nano?
|
||||
|
||||
We've applied the philosophy of "do one thing and do it well", giving you performance and scalability unmatched by any other platform.
|
||||
---
|
||||
|
||||
### Key features
|
||||
* Nano utilizes a novel block-lattice architecture, unlike conventional blockchains used in many other cryptocurrencies.
|
||||
Nano's goal is to become _"a global currency with instantaneous transactions and zero fees over a secure, decentralized network."_
|
||||
|
||||
We've applied the philosophy of _"do one thing and do it well"_, we are focused on building the best medium for value exchange in the world.
|
||||
|
||||
---
|
||||
|
||||
### Key Features
|
||||
|
||||
* Nano utilizes a novel [block-lattice](https://github.com/nanocurrency/raiblocks/wiki/Block-lattice) architecture, unlike conventional blockchains used in many other cryptocurrencies.
|
||||
* The network requires minimal resources, no high-power mining hardware, and can process high transaction throughput.
|
||||
* Offers feeless, instantaneous transactions, as well as unlimited scalability, making Nano ideal for peer-to-peer transactions.
|
||||
* Offers instantaneous transactions with zero fees and unlimited scalability, making Nano an ideal solution for peer-to-peer transactions.
|
||||
* As of December 2017, the Nano network has processed over four million transactions with an unpruned ledger size of only 1.7GB.
|
||||
|
||||
For more information, see [Nano.org](https://nano.org/) or read the [whitepaper](https://nano.org/en/whitepaper).
|
||||
|
||||
### Resources
|
||||
- [Nano website](https://nano.org)
|
||||
- [Whitepaper](https://nano.org/en/whitepaper)
|
||||
- [Roadmap](https://raiblocks.net/media/raiblocks-roadmap-v2-en.png)
|
||||
- [Discord chat](https://chat.nano.org/)
|
||||
- [Reddit](https://reddit.com/r/nanocurrency)
|
||||
- [Medium](https://medium.com/@nanocurrency)
|
||||
- [Twitter](https://twitter.com/nanocurrency)
|
||||
- [Forum](https://forum.raiblocks.net/)
|
||||
- [GitHub wiki](https://github.com/nanocurrency/raiblocks/wiki)
|
||||
### Guides & Documentation
|
||||
|
||||
### Build instructions
|
||||
https://github.com/nanocurrency/raiblocks/wiki/Build-Instructions
|
||||
* [White Paper](https://nano.org/en/whitepaper)
|
||||
* [Build Instructions](https://github.com/nanocurrency/raiblocks/wiki/Build-Instructions)
|
||||
* [Command Line Interface](https://github.com/nanocurrency/raiblocks/wiki/Command-line-interface)
|
||||
* [RPC Protocol](https://github.com/nanocurrency/raiblocks/wiki/RPC-protocol)
|
||||
* [Wallet Design](https://github.com/nanocurrency/raiblocks/wiki/Wallet-design)
|
||||
* [Block Lattice](https://github.com/nanocurrency/raiblocks/wiki/Block-lattice)
|
||||
* [Design Features](https://github.com/nanocurrency/raiblocks/wiki/Design-features)
|
||||
|
||||
### Links & Resources
|
||||
|
||||
* [Nano Website](https://nano.org)
|
||||
* [Nano Roadmap](https://raiblocks.net/media/raiblocks-roadmap-v2-en.png)
|
||||
* [Discord Chat](https://chat.nano.org/)
|
||||
* [Reddit](https://reddit.com/r/nanocurrency)
|
||||
* [Medium](https://medium.com/@nanocurrency)
|
||||
* [Twitter](https://twitter.com/nanocurrency)
|
||||
* [Forum](https://forum.raiblocks.net/)
|
||||
* [GitHub wiki](https://github.com/nanocurrency/raiblocks/wiki)
|
||||
|
||||
### Want to Contribute?
|
||||
|
||||
### Want to contribute?
|
||||
Please see the [contributors guide](https://github.com/nanocurrency/raiblocks/wiki/Contributing).
|
||||
|
||||
### Contact us
|
||||
|
|
|
@ -1,18 +1,37 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -o unset
|
||||
set -o nounset
|
||||
set -o errexit
|
||||
set -o xtrace
|
||||
|
||||
bootstrapArgs=()
|
||||
while getopts 'm' OPT; do
|
||||
case "${OPT}" in
|
||||
m)
|
||||
bootstrapArgs+=('--with-libraries=atomic,chrono,thread,log,date_time,filesystem,program_options,regex')
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
BOOST_BASENAME=boost_1_66_0
|
||||
BOOST_ROOT=${BOOST_ROOT-/usr/local/boost}
|
||||
BOOST_URL=https://downloads.sourceforge.net/project/boost/boost/1.66.0/${BOOST_BASENAME}.tar.bz2
|
||||
BOOST_ARCHIVE="${BOOST_BASENAME}.tar.bz2"
|
||||
BOOST_ARCHIVE_SHA256='5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9'
|
||||
|
||||
wget --quiet -O ${BOOST_BASENAME}.tar.gz "${BOOST_URL}"
|
||||
tar xf ${BOOST_BASENAME}.tar.gz
|
||||
wget --quiet -O "${BOOST_ARCHIVE}.new" "${BOOST_URL}"
|
||||
checkHash="$(openssl dgst -sha256 "${BOOST_ARCHIVE}.new" | sed 's@^.*= *@@')"
|
||||
if [ "${checkHash}" != "${BOOST_ARCHIVE_SHA256}" ]; then
|
||||
echo "Checksum mismatch. Expected ${BOOST_ARCHIVE_SHA256}, got ${checkHash}" >&2
|
||||
|
||||
exit 1
|
||||
fi
|
||||
mv "${BOOST_ARCHIVE}.new" "${BOOST_ARCHIVE}"
|
||||
|
||||
tar xf "${BOOST_ARCHIVE}"
|
||||
cd ${BOOST_BASENAME}
|
||||
./bootstrap.sh
|
||||
./bootstrap.sh "${bootstrapArgs[@]}"
|
||||
./b2 -d0 --prefix=${BOOST_ROOT} link=static install
|
||||
cd ..
|
||||
rm -rf ${BOOST_BASENAME}
|
||||
rm -f ${BOOST_BASENAME}.tar.gz
|
||||
mkdir -p app
|
||||
rm -f "${BOOST_ARCHIVE}"
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
#!/bin/bash
|
||||
set -eu
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo 'Usage: build-docker-image.sh <dockerFile> <dockerImageTag> [<dockerBuildArgs>...]' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dockerFile="$1"
|
||||
dockerTag="$2"
|
||||
shift; shift
|
||||
|
||||
scripts="$(dirname "$0")"
|
||||
|
||||
"$scripts"/custom-timeout.sh 20 docker pull "$2" || true
|
||||
echo "Building $2"
|
||||
"$scripts"/custom-timeout.sh 30 docker build -f "$1" -t "$2" --cache-from "$2" .
|
||||
"$scripts"/custom-timeout.sh 20 docker pull "${dockerTag}" || true
|
||||
echo "Building $dockerTag"
|
||||
"$scripts"/custom-timeout.sh 30 docker build "$@" -f "${dockerFile}" -t "${dockerTag}" --cache-from "${dockerTag}" .
|
||||
|
|
|
@ -15,13 +15,23 @@ elif [ -n "$TRAVIS_TAG" ]; then
|
|||
tags+=("$TRAVIS_TAG" latest)
|
||||
fi
|
||||
|
||||
ci/build-docker-image.sh docker/node/Dockerfile nanocurrency/nano
|
||||
for tag in "${tags[@]}"; do
|
||||
# Sanitize docker tag
|
||||
# https://docs.docker.com/engine/reference/commandline/tag/
|
||||
tag="$(printf '%s' "$tag" | tr -c '[a-z][A-Z][0-9]_.-' -)"
|
||||
if [ "$tag" != "latest" ]; then
|
||||
docker tag nanocurrency/nano nanocurrency/nano:"$tag"
|
||||
for network in live beta; do
|
||||
if [ "${network}" = 'live' ]; then
|
||||
network_tag_suffix=''
|
||||
else
|
||||
network_tag_suffix="-${network}"
|
||||
fi
|
||||
"$scripts"/custom-timeout.sh 30 docker push nanocurrency/nano:"$tag"
|
||||
|
||||
docker_image_name="nanocurrency/nano${network_tag_suffix}"
|
||||
|
||||
ci/build-docker-image.sh docker/node/Dockerfile "$docker_image_name" --build-arg NETWORK="${network}"
|
||||
for tag in "${tags[@]}"; do
|
||||
# Sanitize docker tag
|
||||
# https://docs.docker.com/engine/reference/commandline/tag/
|
||||
tag="$(printf '%s' "$tag" | tr -c '[a-z][A-Z][0-9]_.-' -)"
|
||||
if [ "$tag" != "latest" ]; then
|
||||
docker tag "$docker_image_name" "${docker_image_name}:$tag"
|
||||
fi
|
||||
"$scripts"/custom-timeout.sh 30 docker push "${docker_image_name}:$tag"
|
||||
done
|
||||
done
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
FROM ubuntu:16.04
|
||||
|
||||
ENV BOOST_BASENAME=boost_1_66_0 \
|
||||
BOOST_URL=https://sourceforge.net/projects/boost/files/boost/1.66.0/boost_1_66_0.tar.gz/download
|
||||
BOOST_URL=https://netix.dl.sourceforge.net/project/boost/boost/1.66.0/boost_1_66_0.tar.gz
|
||||
|
||||
RUN apt-get update -qq && apt-get install -yqq \
|
||||
build-essential \
|
||||
|
|
|
@ -1,35 +1,31 @@
|
|||
FROM ubuntu:16.04
|
||||
|
||||
ENV BOOST_BASENAME=boost_1_66_0 \
|
||||
BOOST_ROOT=/tmp/boost_install \
|
||||
BOOST_URL=https://sourceforge.net/projects/boost/files/boost/1.66.0/boost_1_66_0.tar.gz/download
|
||||
ARG NETWORK=live
|
||||
|
||||
ENV BOOST_ROOT=/tmp/boost_install
|
||||
|
||||
ADD ci /tmp/ci
|
||||
|
||||
RUN apt-get update -qq && apt-get install -yqq \
|
||||
build-essential \
|
||||
cmake \
|
||||
g++ \
|
||||
wget && \
|
||||
wget -qO ${BOOST_BASENAME}.tar.gz ${BOOST_URL} && \
|
||||
tar xzf ${BOOST_BASENAME}.tar.gz && \
|
||||
cd ${BOOST_BASENAME} && \
|
||||
./bootstrap.sh && \
|
||||
./b2 -d0 --prefix=${BOOST_ROOT} link=static install && \
|
||||
rm -rf ${BOOST_BASENAME} && \
|
||||
rm -f ${BOOST_BASENAME}.tar.gz && \
|
||||
cd .. && \
|
||||
mkdir /usr/share/raiblocks/
|
||||
/tmp/ci/bootstrap_boost.sh -m
|
||||
|
||||
ADD ./ /tmp/src
|
||||
|
||||
RUN mkdir /tmp/build && \
|
||||
cd /tmp/build && \
|
||||
cmake /tmp/src -DBOOST_ROOT=${BOOST_ROOT} && \
|
||||
cmake /tmp/src -DBOOST_ROOT=${BOOST_ROOT} -DACTIVE_NETWORK=rai_${NETWORK}_network && \
|
||||
make rai_node && \
|
||||
cd ..
|
||||
cd .. && \
|
||||
echo ${NETWORK} > /etc/nano-network
|
||||
|
||||
FROM ubuntu:16.04
|
||||
COPY --from=0 /tmp/build/rai_node /usr/bin
|
||||
COPY --from=0 /etc/nano-network /etc
|
||||
COPY docker/node/entry.sh /entry.sh
|
||||
COPY docker/node/config.json /usr/share/raiblocks/config.json
|
||||
COPY docker/node/config /usr/share/raiblocks/config
|
||||
RUN chmod +x /entry.sh
|
||||
CMD ["/bin/bash", "/entry.sh"]
|
||||
|
|
|
@ -1,6 +1,42 @@
|
|||
#!/bin/bash
|
||||
|
||||
network='live'
|
||||
|
||||
print_usage() {
|
||||
echo 'build.sh [-h] [-n {live|beta|test}]'
|
||||
}
|
||||
|
||||
while getopts 'hn:' OPT; do
|
||||
case "${OPT}" in
|
||||
h)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
n)
|
||||
network="${OPTARG}"
|
||||
;;
|
||||
*)
|
||||
print_usage >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
case "${network}" in
|
||||
live)
|
||||
network_tag=''
|
||||
;;
|
||||
test|beta)
|
||||
network_tag="-${network}"
|
||||
;;
|
||||
*)
|
||||
echo "Invalid network: ${network}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
REPO_ROOT=`git rev-parse --show-toplevel`
|
||||
COMMIT_SHA=`git rev-parse --short HEAD`
|
||||
pushd $REPO_ROOT
|
||||
docker build -f docker/node/Dockerfile -t raiblocks-node:latest .
|
||||
docker build --build-arg NETWORK="${network}" -f docker/node/Dockerfile -t raiblocks-node${network_tag}:latest .
|
||||
popd
|
||||
|
|
60
docker/node/config/beta.json
Normal file
60
docker/node/config/beta.json
Normal file
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"version": "2",
|
||||
"rpc_enable": "true",
|
||||
"rpc": {
|
||||
"address": "::ffff:0.0.0.0",
|
||||
"port": "7076",
|
||||
"enable_control": "true",
|
||||
"frontier_request_limit": "16384",
|
||||
"chain_request_limit": "16384"
|
||||
},
|
||||
"node": {
|
||||
"version": "8",
|
||||
"peering_port": "54000",
|
||||
"bootstrap_fraction_numerator": "1",
|
||||
"receive_minimum": "1000000000000000000000000",
|
||||
"logging": {
|
||||
"version": "2",
|
||||
"ledger": "false",
|
||||
"ledger_duplicate": "false",
|
||||
"vote": "false",
|
||||
"network": "true",
|
||||
"network_message": "false",
|
||||
"network_publish": "false",
|
||||
"network_packet": "false",
|
||||
"network_keepalive": "false",
|
||||
"node_lifetime_tracing": "false",
|
||||
"insufficient_work": "true",
|
||||
"log_rpc": "true",
|
||||
"bulk_pull": "false",
|
||||
"work_generation_time": "true",
|
||||
"log_to_cerr": "false",
|
||||
"max_size": "16777216",
|
||||
"rotation_size": "4194304",
|
||||
"flush": "false"
|
||||
},
|
||||
"work_peers": "",
|
||||
"preconfigured_peers": [
|
||||
"rai-beta.raiblocks.net"
|
||||
],
|
||||
"preconfigured_representatives": [
|
||||
"xrb_3kbzg73bjsi85scbwnouj44iinrsqtdqphzay1x3pwmgmhkdwg8yjntxff33"
|
||||
],
|
||||
"inactive_supply": "0",
|
||||
"password_fanout": "1024",
|
||||
"io_threads": "4",
|
||||
"work_threads": "4",
|
||||
"enable_voting": "true",
|
||||
"bootstrap_connections": "16",
|
||||
"callback_address": "",
|
||||
"callback_port": "0",
|
||||
"callback_target": "",
|
||||
"lmdb_max_dbs": "128"
|
||||
},
|
||||
"opencl_enable": "false",
|
||||
"opencl": {
|
||||
"platform": "0",
|
||||
"device": "0",
|
||||
"threads": "1048576"
|
||||
}
|
||||
}
|
67
docker/node/config/test.json
Normal file
67
docker/node/config/test.json
Normal file
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"version": "2",
|
||||
"rpc_enable": "true",
|
||||
"rpc": {
|
||||
"address": "::ffff:0.0.0.0",
|
||||
"port": "7076",
|
||||
"enable_control": "true",
|
||||
"frontier_request_limit": "16384",
|
||||
"chain_request_limit": "16384"
|
||||
},
|
||||
"node": {
|
||||
"version": "8",
|
||||
"peering_port": "7075",
|
||||
"bootstrap_fraction_numerator": "1",
|
||||
"receive_minimum": "1000000000000000000000000",
|
||||
"logging": {
|
||||
"version": "2",
|
||||
"ledger": "false",
|
||||
"ledger_duplicate": "false",
|
||||
"vote": "false",
|
||||
"network": "true",
|
||||
"network_message": "false",
|
||||
"network_publish": "false",
|
||||
"network_packet": "false",
|
||||
"network_keepalive": "false",
|
||||
"node_lifetime_tracing": "false",
|
||||
"insufficient_work": "true",
|
||||
"log_rpc": "true",
|
||||
"bulk_pull": "false",
|
||||
"work_generation_time": "true",
|
||||
"log_to_cerr": "false",
|
||||
"max_size": "16777216",
|
||||
"rotation_size": "4194304",
|
||||
"flush": "false"
|
||||
},
|
||||
"work_peers": "",
|
||||
"preconfigured_peers": [
|
||||
"rai-test.raiblocks.net"
|
||||
],
|
||||
"preconfigured_representatives": [
|
||||
"xrb_3arg3asgtigae3xckabaaewkx3bzsh7nwz7jkmjos79ihyaxwphhm6qgjps4",
|
||||
"xrb_1stofnrxuz3cai7ze75o174bpm7scwj9jn3nxsn8ntzg784jf1gzn1jjdkou",
|
||||
"xrb_1q3hqecaw15cjt7thbtxu3pbzr1eihtzzpzxguoc37bj1wc5ffoh7w74gi6p",
|
||||
"xrb_3dmtrrws3pocycmbqwawk6xs7446qxa36fcncush4s1pejk16ksbmakis78m",
|
||||
"xrb_3hd4ezdgsp15iemx7h81in7xz5tpxi43b6b41zn3qmwiuypankocw3awes5k",
|
||||
"xrb_1awsn43we17c1oshdru4azeqjz9wii41dy8npubm4rg11so7dx3jtqgoeahy",
|
||||
"xrb_1anrzcuwe64rwxzcco8dkhpyxpi8kd7zsjc1oeimpc3ppca4mrjtwnqposrs",
|
||||
"xrb_1hza3f7wiiqa7ig3jczyxj5yo86yegcmqk3criaz838j91sxcckpfhbhhra1"
|
||||
],
|
||||
"inactive_supply": "0",
|
||||
"password_fanout": "1024",
|
||||
"io_threads": "4",
|
||||
"work_threads": "4",
|
||||
"enable_voting": "true",
|
||||
"bootstrap_connections": "16",
|
||||
"callback_address": "",
|
||||
"callback_port": "0",
|
||||
"callback_target": "",
|
||||
"lmdb_max_dbs": "128"
|
||||
},
|
||||
"opencl_enable": "false",
|
||||
"opencl": {
|
||||
"platform": "0",
|
||||
"device": "0",
|
||||
"threads": "1048576"
|
||||
}
|
||||
}
|
|
@ -1,10 +1,27 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
mkdir -p ~/RaiBlocks
|
||||
if [ ! -f ~/RaiBlocks/config.json ]; then
|
||||
echo "Config File not found, adding default."
|
||||
cp /usr/share/raiblocks/config.json ~/RaiBlocks/
|
||||
network="$(cat /etc/nano-network)"
|
||||
case "${network}" in
|
||||
live|'')
|
||||
network='live'
|
||||
dirSuffix=''
|
||||
;;
|
||||
beta)
|
||||
dirSuffix='Beta'
|
||||
;;
|
||||
test)
|
||||
dirSuffix='Test'
|
||||
;;
|
||||
esac
|
||||
|
||||
nanodir="${HOME}/RaiBlocks${dirSuffix}"
|
||||
mkdir -p "${nanodir}"
|
||||
if [ ! -f "${nanodir}/config.json" ]; then
|
||||
echo "Config File not found, adding default."
|
||||
cp "/usr/share/raiblocks/config/${network}.json" "${nanodir}/config.json"
|
||||
fi
|
||||
|
||||
/usr/bin/rai_node --daemon
|
||||
|
|
1
images/logo.svg
Normal file
1
images/logo.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216 29.4"><style>.st0{fill:#4a90e2}.st1{fill:#000034}</style><circle class="st0" cx="4.8" cy="24.4" r="4.8"/><path class="st0" d="M62 .6c-2.6 0-4.8 2.1-4.8 4.8 0 3.8-.6 4.8-4.8 4.8H52c-2.4.2-4.3 2.2-4.3 4.7v.1c0 3.7-.7 4.6-4.8 4.6-.2 0-.4 0-.5.1-2.4.3-4.3 2.3-4.3 4.7 0 2.6 2.1 4.8 4.8 4.8 2.5 0 4.6-2 4.7-4.4v-.4c0-3.4 1.1-4.7 4.7-4.8h.1c2.5 0 4.6-2 4.7-4.5v-.3c0-3.5 1.1-4.8 4.8-4.8 2.6 0 4.8-2.1 4.8-4.8 0-2.5-2.1-4.6-4.7-4.6zM33.8 10.2h-.4c-4.2 0-4.8-1-4.8-4.8 0-2.6-2.1-4.8-4.8-4.8C21.2.6 19 2.7 19 5.4c0 3.8-.6 4.7-4.8 4.7h-.4c-2.4.2-4.3 2.2-4.3 4.7 0 2.6 2.1 4.8 4.8 4.8 2.5 0 4.6-2 4.7-4.4v-.3c0-3.5 1.1-4.8 4.8-4.8 3.7 0 4.8 1.3 4.8 4.7 0 2.6 2.1 4.8 4.8 4.8s4.8-2.1 4.8-4.8c-.1-2.4-2-4.4-4.4-4.6z"/><g><path class="st1" d="M109.3.8c-.3 0-.6.1-.8.4-.2.2-.3.5-.3.9V25L90.7 1.4c-.3-.4-.6-.6-1-.6s-.7.1-.9.4c-.2.2-.3.5-.3.9v26c0 .4.1.7.3.9.2.2.5.3.9.3.3 0 .6-.1.8-.4.2-.2.3-.5.3-.9V5.2l17.5 23.6c.3.4.7.6 1.1.6.4 0 .7-.1.9-.4.2-.2.3-.5.3-.9v-26c0-.4-.1-.7-.3-.9-.3-.3-.6-.4-1-.4zm92-.8c-8.1 0-14.7 6.6-14.7 14.7s6.6 14.7 14.7 14.7S216 22.8 216 14.7 209.4 0 201.3 0zm0 27c-6.8 0-12.3-5.5-12.3-12.3s5.5-12.3 12.3-12.3 12.3 5.5 12.3 12.3S208.1 27 201.3 27zM177 .8c-.3 0-.6.1-.8.4-.2.2-.3.5-.3.9V25L158.4 1.4c-.3-.4-.6-.6-1-.6s-.7.1-.9.4c-.2.2-.3.5-.3.9v26c0 .4.1.7.3.9.2.2.5.3.9.3.3 0 .6-.1.8-.4.2-.2.3-.5.3-.9V5.2L176 28.8c.3.4.7.6 1.1.6.4 0 .7-.1.9-.4.2-.2.3-.5.3-.9v-26c0-.4-.1-.7-.3-.9-.3-.3-.6-.4-1-.4zm-42.3.8c-.1-.3-.3-.5-.5-.6-.3-.2-.5-.2-.8-.2-.6 0-1.1.3-1.3.9l-11.7 26.2c-.1.1-.1.3-.1.4 0 .3.1.6.3.8.2.2.5.3.8.3.5 0 .9-.3 1.1-.8l3.1-7h15.5l3 7c.1.2.3.4.5.6.2.1.4.2.6.2.3 0 .6-.1.8-.3.2-.2.4-.4.4-.7 0-.2 0-.3-.1-.5L134.7 1.6zm-8.2 17.9L133.3 4l6.8 15.5h-13.6z"/></g></svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -827,35 +827,6 @@ rai::block_counts rai::block_store::block_count (MDB_txn * transaction_a)
|
|||
return result;
|
||||
}
|
||||
|
||||
std::unordered_multimap<rai::block_hash, rai::block_hash> rai::block_store::block_dependencies (MDB_txn * transaction_a)
|
||||
{
|
||||
std::unordered_multimap<rai::block_hash, rai::block_hash> result;
|
||||
// For every block type
|
||||
for (auto type : { rai::block_type::send, rai::block_type::receive, rai::block_type::open, rai::block_type::change })
|
||||
{
|
||||
auto db (block_database (type));
|
||||
// For every block in that type's table
|
||||
for (auto i (rai::store_iterator (transaction_a, db)), n (rai::store_iterator (nullptr)); i != n; ++i)
|
||||
{
|
||||
rai::block_hash hash (i->first.uint256 ());
|
||||
auto block (block_get (transaction_a, hash));
|
||||
if (type != rai::block_type::open)
|
||||
{
|
||||
auto previous (block->previous ());
|
||||
assert (!previous.is_zero ());
|
||||
result.insert (std::make_pair (previous, hash));
|
||||
}
|
||||
if (type == rai::block_type::open || type == rai::block_type::receive)
|
||||
{
|
||||
auto source (block->source ());
|
||||
assert (!source.is_zero ());
|
||||
result.insert (std::make_pair (source, hash));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void rai::block_store::account_del (MDB_txn * transaction_a, rai::account const & account_a)
|
||||
{
|
||||
auto status (mdb_del (transaction_a, accounts, rai::mdb_val (account_a), nullptr));
|
||||
|
@ -1074,7 +1045,7 @@ void rai::block_store::unchecked_put (MDB_txn * transaction_a, rai::block_hash c
|
|||
exists = true;
|
||||
}
|
||||
}
|
||||
// Insering block if it wasn't found in database
|
||||
// Inserting block if it wasn't found in database
|
||||
if (!exists)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (cache_mutex);
|
||||
|
|
|
@ -60,7 +60,6 @@ public:
|
|||
void block_del (MDB_txn *, rai::block_hash const &);
|
||||
bool block_exists (MDB_txn *, rai::block_hash const &);
|
||||
rai::block_counts block_count (MDB_txn *);
|
||||
std::unordered_multimap<rai::block_hash, rai::block_hash> block_dependencies (MDB_txn *);
|
||||
|
||||
void frontier_put (MDB_txn *, rai::block_hash const &, rai::account const &);
|
||||
rai::account frontier_get (MDB_txn *, rai::block_hash const &);
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace
|
|||
{
|
||||
char const * test_private_key_data = "34F0A37AAD20F4A260F0A5B3CB3D7FB50673212263E58A380BC10474BB039CE4";
|
||||
char const * test_public_key_data = "B0311EA55708D6A53C75CDBF88300259C6D018522FE3D4D0A242E431F9E8B6D0"; // xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpiij4txtdo
|
||||
char const * beta_public_key_data = "9D3A5B66B478670455B241D6BAC3D3FE1CBB7E7B7EAA429FA036C2704C3DC0A4"; // xrb_39btdfmday591jcu6igpqd3x9ziwqfz9pzocacht1fp4g385ui76a87x6phk
|
||||
char const * beta_public_key_data = "0311B25E0D1E1D7724BBA5BD523954F1DBCFC01CB8671D55ED2D32C7549FB252"; // xrb_11rjpbh1t9ixgwkdqbfxcawobwgusz13sg595ocytdbkrxcbzekkcqkc3dn1
|
||||
char const * live_public_key_data = "E89208DD038FBB269987689621D52292AE9C35941A7484756ECCED92A65093BA"; // xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3
|
||||
char const * test_genesis_data = R"%%%({
|
||||
"type": "open",
|
||||
|
@ -29,11 +29,11 @@ char const * test_genesis_data = R"%%%({
|
|||
|
||||
char const * beta_genesis_data = R"%%%({
|
||||
"type": "open",
|
||||
"source": "9D3A5B66B478670455B241D6BAC3D3FE1CBB7E7B7EAA429FA036C2704C3DC0A4",
|
||||
"representative": "xrb_39btdfmday591jcu6igpqd3x9ziwqfz9pzocacht1fp4g385ui76a87x6phk",
|
||||
"account": "xrb_39btdfmday591jcu6igpqd3x9ziwqfz9pzocacht1fp4g385ui76a87x6phk",
|
||||
"work": "6eb12d4c42dba31e",
|
||||
"signature": "BD0D374FCEB33EAABDF728E9B4DCDBF3B226DA97EEAB8EA5B7EDE286B1282C24D6EB544644FE871235E4F58CD94DF66D9C555309895F67A7D1F922AAC12CE907"
|
||||
"source": "0311B25E0D1E1D7724BBA5BD523954F1DBCFC01CB8671D55ED2D32C7549FB252",
|
||||
"representative": "xrb_11rjpbh1t9ixgwkdqbfxcawobwgusz13sg595ocytdbkrxcbzekkcqkc3dn1",
|
||||
"account": "xrb_11rjpbh1t9ixgwkdqbfxcawobwgusz13sg595ocytdbkrxcbzekkcqkc3dn1",
|
||||
"work": "869e17b2bfa36639",
|
||||
"signature": "34DF447C7F185673128C3516A657DFEC7906F16C68FB5A8879432E2E4FB908C8ED0DD24BBECFAB3C7852898231544A421DC8CB636EF66C82E1245083EB08EA0F"
|
||||
})%%%";
|
||||
|
||||
char const * live_genesis_data = R"%%%({
|
||||
|
@ -63,7 +63,7 @@ public:
|
|||
burn_account (0)
|
||||
{
|
||||
CryptoPP::AutoSeededRandomPool random_pool;
|
||||
// Randomly generating these mean no two nodes will ever have the same sentinal values which protects against some insecure algorithms
|
||||
// Randomly generating these mean no two nodes will ever have the same sentinel values which protects against some insecure algorithms
|
||||
random_pool.GenerateBlock (not_a_block.bytes.data (), not_a_block.bytes.size ());
|
||||
random_pool.GenerateBlock (not_an_account.bytes.data (), not_an_account.bytes.size ());
|
||||
}
|
||||
|
@ -410,56 +410,6 @@ std::string rai::vote::to_json () const
|
|||
return stream.str ();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class root_visitor : public rai::block_visitor
|
||||
{
|
||||
public:
|
||||
root_visitor (rai::block_store & store_a) :
|
||||
store (store_a)
|
||||
{
|
||||
}
|
||||
virtual ~root_visitor () = default;
|
||||
void send_block (rai::send_block const & block_a) override
|
||||
{
|
||||
result = block_a.previous ();
|
||||
}
|
||||
void receive_block (rai::receive_block const & block_a) override
|
||||
{
|
||||
result = block_a.previous ();
|
||||
}
|
||||
// Open blocks have no previous () so we use the account number
|
||||
void open_block (rai::open_block const & block_a) override
|
||||
{
|
||||
rai::transaction transaction (store.environment, nullptr, false);
|
||||
auto hash (block_a.source ());
|
||||
auto source (store.block_get (transaction, hash));
|
||||
if (source != nullptr)
|
||||
{
|
||||
auto send (dynamic_cast<rai::send_block *> (source.get ()));
|
||||
if (send != nullptr)
|
||||
{
|
||||
result = send->hashables.destination;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.clear ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.clear ();
|
||||
}
|
||||
}
|
||||
void change_block (rai::change_block const & block_a) override
|
||||
{
|
||||
result = block_a.previous ();
|
||||
}
|
||||
rai::block_store & store;
|
||||
rai::block_hash result;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
rai::amount_visitor::amount_visitor (MDB_txn * transaction_a, rai::block_store & store_a) :
|
||||
transaction (transaction_a),
|
||||
store (store_a)
|
||||
|
|
|
@ -12,7 +12,7 @@ TEST (ledger, store_error)
|
|||
rai::ledger ledger (store);
|
||||
}
|
||||
|
||||
// Ledger can be initialized and retuns a basic query for an empty account
|
||||
// Ledger can be initialized and returns a basic query for an empty account
|
||||
TEST (ledger, empty)
|
||||
{
|
||||
bool init (false);
|
||||
|
|
|
@ -74,14 +74,14 @@ TEST (message_parser, exact_confirm_ack_size)
|
|||
message.serialize (stream);
|
||||
}
|
||||
ASSERT_EQ (0, visitor.confirm_ack_count);
|
||||
ASSERT_FALSE (parser.error);
|
||||
ASSERT_EQ (parser.status, rai::message_parser::parse_status::success);
|
||||
parser.deserialize_confirm_ack (bytes.data (), bytes.size ());
|
||||
ASSERT_EQ (1, visitor.confirm_ack_count);
|
||||
ASSERT_FALSE (parser.error);
|
||||
ASSERT_EQ (parser.status, rai::message_parser::parse_status::success);
|
||||
bytes.push_back (0);
|
||||
parser.deserialize_confirm_ack (bytes.data (), bytes.size ());
|
||||
ASSERT_EQ (1, visitor.confirm_ack_count);
|
||||
ASSERT_TRUE (parser.error);
|
||||
ASSERT_NE (parser.status, rai::message_parser::parse_status::success);
|
||||
}
|
||||
|
||||
TEST (message_parser, exact_confirm_req_size)
|
||||
|
@ -97,14 +97,14 @@ TEST (message_parser, exact_confirm_req_size)
|
|||
message.serialize (stream);
|
||||
}
|
||||
ASSERT_EQ (0, visitor.confirm_req_count);
|
||||
ASSERT_FALSE (parser.error);
|
||||
ASSERT_EQ (parser.status, rai::message_parser::parse_status::success);
|
||||
parser.deserialize_confirm_req (bytes.data (), bytes.size ());
|
||||
ASSERT_EQ (1, visitor.confirm_req_count);
|
||||
ASSERT_FALSE (parser.error);
|
||||
ASSERT_EQ (parser.status, rai::message_parser::parse_status::success);
|
||||
bytes.push_back (0);
|
||||
parser.deserialize_confirm_req (bytes.data (), bytes.size ());
|
||||
ASSERT_EQ (1, visitor.confirm_req_count);
|
||||
ASSERT_TRUE (parser.error);
|
||||
ASSERT_NE (parser.status, rai::message_parser::parse_status::success);
|
||||
}
|
||||
|
||||
TEST (message_parser, exact_publish_size)
|
||||
|
@ -120,14 +120,14 @@ TEST (message_parser, exact_publish_size)
|
|||
message.serialize (stream);
|
||||
}
|
||||
ASSERT_EQ (0, visitor.publish_count);
|
||||
ASSERT_FALSE (parser.error);
|
||||
ASSERT_EQ (parser.status, rai::message_parser::parse_status::success);
|
||||
parser.deserialize_publish (bytes.data (), bytes.size ());
|
||||
ASSERT_EQ (1, visitor.publish_count);
|
||||
ASSERT_FALSE (parser.error);
|
||||
ASSERT_EQ (parser.status, rai::message_parser::parse_status::success);
|
||||
bytes.push_back (0);
|
||||
parser.deserialize_publish (bytes.data (), bytes.size ());
|
||||
ASSERT_EQ (1, visitor.publish_count);
|
||||
ASSERT_TRUE (parser.error);
|
||||
ASSERT_NE (parser.status, rai::message_parser::parse_status::success);
|
||||
}
|
||||
|
||||
TEST (message_parser, exact_keepalive_size)
|
||||
|
@ -142,12 +142,12 @@ TEST (message_parser, exact_keepalive_size)
|
|||
message.serialize (stream);
|
||||
}
|
||||
ASSERT_EQ (0, visitor.keepalive_count);
|
||||
ASSERT_FALSE (parser.error);
|
||||
ASSERT_EQ (parser.status, rai::message_parser::parse_status::success);
|
||||
parser.deserialize_keepalive (bytes.data (), bytes.size ());
|
||||
ASSERT_EQ (1, visitor.keepalive_count);
|
||||
ASSERT_FALSE (parser.error);
|
||||
ASSERT_EQ (parser.status, rai::message_parser::parse_status::success);
|
||||
bytes.push_back (0);
|
||||
parser.deserialize_keepalive (bytes.data (), bytes.size ());
|
||||
ASSERT_EQ (1, visitor.keepalive_count);
|
||||
ASSERT_TRUE (parser.error);
|
||||
ASSERT_NE (parser.status, rai::message_parser::parse_status::success);
|
||||
}
|
||||
|
|
|
@ -206,7 +206,7 @@ TEST (network, send_valid_confirm_ack)
|
|||
++iterations;
|
||||
ASSERT_LT (iterations, 200);
|
||||
}
|
||||
// Make sure the balance has decreased after procssing the block.
|
||||
// Make sure the balance has decreased after processing the block.
|
||||
ASSERT_EQ (50, system.nodes[1]->balance (rai::test_genesis_key.pub));
|
||||
}
|
||||
|
||||
|
|
|
@ -379,7 +379,6 @@ TEST (rpc, wallet_add)
|
|||
rai::keypair key1;
|
||||
std::string key_text;
|
||||
key1.prv.data.encode_hex (key_text);
|
||||
system.wallet (0)->insert_adhoc (key1.prv);
|
||||
boost::property_tree::ptree request;
|
||||
std::string wallet;
|
||||
system.nodes[0]->wallets.items.begin ()->first.encode_hex (wallet);
|
||||
|
@ -394,6 +393,7 @@ TEST (rpc, wallet_add)
|
|||
ASSERT_EQ (200, response.status);
|
||||
std::string account_text1 (response.json.get<std::string> ("account"));
|
||||
ASSERT_EQ (account_text1, key1.pub.to_account ());
|
||||
ASSERT_TRUE (system.wallet (0)->exists (key1.pub));
|
||||
}
|
||||
|
||||
TEST (rpc, wallet_password_valid)
|
||||
|
@ -1337,6 +1337,8 @@ TEST (rpc, pending)
|
|||
rai::uint128_union amount;
|
||||
amount.decode_dec (i->second.get<std::string> (""));
|
||||
blocks[hash] = amount;
|
||||
boost::optional<std::string> source (i->second.get_optional<std::string> ("source"));
|
||||
ASSERT_FALSE (source.is_initialized ());
|
||||
}
|
||||
ASSERT_EQ (blocks[block1->hash ()], 100);
|
||||
request.put ("threshold", "101");
|
||||
|
@ -2265,6 +2267,8 @@ TEST (rpc, accounts_pending)
|
|||
rai::uint128_union amount;
|
||||
amount.decode_dec (i->second.get<std::string> (""));
|
||||
blocks[hash] = amount;
|
||||
boost::optional<std::string> source (i->second.get_optional<std::string> ("source"));
|
||||
ASSERT_FALSE (source.is_initialized ());
|
||||
}
|
||||
}
|
||||
ASSERT_EQ (blocks[block1->hash ()], 100);
|
||||
|
@ -2465,6 +2469,8 @@ TEST (rpc, wallet_pending)
|
|||
rai::uint128_union amount;
|
||||
amount.decode_dec (i->second.get<std::string> (""));
|
||||
blocks[hash] = amount;
|
||||
boost::optional<std::string> source (i->second.get_optional<std::string> ("source"));
|
||||
ASSERT_FALSE (source.is_initialized ());
|
||||
}
|
||||
}
|
||||
ASSERT_EQ (blocks[block1->hash ()], 100);
|
||||
|
@ -2780,6 +2786,27 @@ TEST (rpc, account_info)
|
|||
ASSERT_TRUE (time - stol (modified_timestamp) < 5);
|
||||
std::string block_count (response.json.get<std::string> ("block_count"));
|
||||
ASSERT_EQ ("2", block_count);
|
||||
boost::optional<std::string> weight (response.json.get_optional<std::string> ("weight"));
|
||||
ASSERT_FALSE (weight.is_initialized ());
|
||||
boost::optional<std::string> pending (response.json.get_optional<std::string> ("pending"));
|
||||
ASSERT_FALSE (pending.is_initialized ());
|
||||
boost::optional<std::string> representative (response.json.get_optional<std::string> ("representative"));
|
||||
ASSERT_FALSE (representative.is_initialized ());
|
||||
// Test for optional values
|
||||
request.put ("weight", "true");
|
||||
request.put ("pending", "1");
|
||||
request.put ("representative", "1");
|
||||
test_response response2 (request, rpc, system.service);
|
||||
while (response2.status == 0)
|
||||
{
|
||||
system.poll ();
|
||||
}
|
||||
std::string weight2 (response2.json.get<std::string> ("weight"));
|
||||
ASSERT_EQ ("100", weight2);
|
||||
std::string pending2 (response2.json.get<std::string> ("pending"));
|
||||
ASSERT_EQ ("0", pending2);
|
||||
std::string representative2 (response2.json.get<std::string> ("representative"));
|
||||
ASSERT_EQ (rai::test_genesis_key.pub.to_account (), representative2);
|
||||
}
|
||||
|
||||
TEST (rpc, blocks_info)
|
||||
|
@ -2810,6 +2837,26 @@ TEST (rpc, blocks_info)
|
|||
ASSERT_EQ (rai::genesis_amount.convert_to<std::string> (), amount_text);
|
||||
std::string blocks_text (blocks.second.get<std::string> ("contents"));
|
||||
ASSERT_FALSE (blocks_text.empty ());
|
||||
boost::optional<std::string> pending (blocks.second.get_optional<std::string> ("pending"));
|
||||
ASSERT_FALSE (pending.is_initialized ());
|
||||
boost::optional<std::string> source (blocks.second.get_optional<std::string> ("source_account"));
|
||||
ASSERT_FALSE (source.is_initialized ());
|
||||
}
|
||||
// Test for optional values
|
||||
request.put ("source", "true");
|
||||
request.put ("pending", "1");
|
||||
test_response response2 (request, rpc, system.service);
|
||||
while (response2.status == 0)
|
||||
{
|
||||
system.poll ();
|
||||
}
|
||||
ASSERT_EQ (200, response2.status);
|
||||
for (auto & blocks : response2.json.get_child ("blocks"))
|
||||
{
|
||||
std::string source (blocks.second.get<std::string> ("source_account"));
|
||||
ASSERT_EQ ("0", source);
|
||||
std::string pending (blocks.second.get<std::string> ("pending"));
|
||||
ASSERT_EQ ("0", pending);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2940,6 +2987,33 @@ TEST (rpc, ledger)
|
|||
ASSERT_EQ (std::to_string (time), modified_timestamp);
|
||||
std::string block_count (accounts.second.get<std::string> ("block_count"));
|
||||
ASSERT_EQ ("1", block_count);
|
||||
boost::optional<std::string> weight (accounts.second.get_optional<std::string> ("weight"));
|
||||
ASSERT_FALSE (weight.is_initialized ());
|
||||
boost::optional<std::string> pending (accounts.second.get_optional<std::string> ("pending"));
|
||||
ASSERT_FALSE (pending.is_initialized ());
|
||||
boost::optional<std::string> representative (accounts.second.get_optional<std::string> ("representative"));
|
||||
ASSERT_FALSE (representative.is_initialized ());
|
||||
}
|
||||
// Test for optional values
|
||||
request.put ("weight", "1");
|
||||
request.put ("pending", "1");
|
||||
request.put ("representative", "true");
|
||||
test_response response2 (request, rpc, system.service);
|
||||
while (response2.status == 0)
|
||||
{
|
||||
system.poll ();
|
||||
}
|
||||
for (auto & accounts : response2.json.get_child ("accounts"))
|
||||
{
|
||||
boost::optional<std::string> weight (accounts.second.get_optional<std::string> ("weight"));
|
||||
ASSERT_TRUE (weight.is_initialized ());
|
||||
ASSERT_EQ ("0", weight.get ());
|
||||
boost::optional<std::string> pending (accounts.second.get_optional<std::string> ("pending"));
|
||||
ASSERT_TRUE (pending.is_initialized ());
|
||||
ASSERT_EQ ("0", pending.get ());
|
||||
boost::optional<std::string> representative (accounts.second.get_optional<std::string> ("representative"));
|
||||
ASSERT_TRUE (representative.is_initialized ());
|
||||
ASSERT_EQ (rai::test_genesis_key.pub.to_account (), representative.get ());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3193,3 +3267,99 @@ TEST (rpc, wallet_create_fail)
|
|||
}
|
||||
ASSERT_EQ ("Failed to create wallet. Increase lmdb_max_dbs in node config.", response.json.get<std::string> ("error"));
|
||||
}
|
||||
|
||||
TEST (rpc, wallet_ledger)
|
||||
{
|
||||
rai::system system (24000, 1);
|
||||
rai::keypair key;
|
||||
rai::genesis genesis;
|
||||
system.wallet (0)->insert_adhoc (key.prv);
|
||||
auto & node1 (*system.nodes[0]);
|
||||
auto latest (system.nodes[0]->latest (rai::test_genesis_key.pub));
|
||||
rai::send_block send (latest, key.pub, 100, rai::test_genesis_key.prv, rai::test_genesis_key.pub, node1.generate_work (latest));
|
||||
system.nodes[0]->process (send);
|
||||
rai::open_block open (send.hash (), rai::test_genesis_key.pub, key.pub, key.prv, key.pub, node1.generate_work (key.pub));
|
||||
ASSERT_EQ (rai::process_result::progress, system.nodes[0]->process (open).code);
|
||||
auto time (rai::seconds_since_epoch ());
|
||||
rai::rpc rpc (system.service, *system.nodes[0], rai::rpc_config (true));
|
||||
rpc.start ();
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "wallet_ledger");
|
||||
request.put ("wallet", system.nodes[0]->wallets.items.begin ()->first.to_string ());
|
||||
request.put ("sorting", "1");
|
||||
request.put ("count", "1");
|
||||
test_response response (request, rpc, system.service);
|
||||
while (response.status == 0)
|
||||
{
|
||||
system.poll ();
|
||||
}
|
||||
for (auto & accounts : response.json.get_child ("accounts"))
|
||||
{
|
||||
std::string account_text (accounts.first);
|
||||
ASSERT_EQ (key.pub.to_account (), account_text);
|
||||
std::string frontier (accounts.second.get<std::string> ("frontier"));
|
||||
ASSERT_EQ (open.hash ().to_string (), frontier);
|
||||
std::string open_block (accounts.second.get<std::string> ("open_block"));
|
||||
ASSERT_EQ (open.hash ().to_string (), open_block);
|
||||
std::string representative_block (accounts.second.get<std::string> ("representative_block"));
|
||||
ASSERT_EQ (open.hash ().to_string (), representative_block);
|
||||
std::string balance_text (accounts.second.get<std::string> ("balance"));
|
||||
ASSERT_EQ ("340282366920938463463374607431768211355", balance_text);
|
||||
std::string modified_timestamp (accounts.second.get<std::string> ("modified_timestamp"));
|
||||
ASSERT_EQ (std::to_string (time), modified_timestamp);
|
||||
std::string block_count (accounts.second.get<std::string> ("block_count"));
|
||||
ASSERT_EQ ("1", block_count);
|
||||
boost::optional<std::string> weight (accounts.second.get_optional<std::string> ("weight"));
|
||||
ASSERT_FALSE (weight.is_initialized ());
|
||||
boost::optional<std::string> pending (accounts.second.get_optional<std::string> ("pending"));
|
||||
ASSERT_FALSE (pending.is_initialized ());
|
||||
boost::optional<std::string> representative (accounts.second.get_optional<std::string> ("representative"));
|
||||
ASSERT_FALSE (representative.is_initialized ());
|
||||
}
|
||||
// Test for optional values
|
||||
request.put ("weight", "true");
|
||||
request.put ("pending", "1");
|
||||
request.put ("representative", "false");
|
||||
test_response response2 (request, rpc, system.service);
|
||||
while (response2.status == 0)
|
||||
{
|
||||
system.poll ();
|
||||
}
|
||||
for (auto & accounts : response2.json.get_child ("accounts"))
|
||||
{
|
||||
boost::optional<std::string> weight (accounts.second.get_optional<std::string> ("weight"));
|
||||
ASSERT_TRUE (weight.is_initialized ());
|
||||
ASSERT_EQ ("0", weight.get ());
|
||||
boost::optional<std::string> pending (accounts.second.get_optional<std::string> ("pending"));
|
||||
ASSERT_TRUE (pending.is_initialized ());
|
||||
ASSERT_EQ ("0", pending.get ());
|
||||
boost::optional<std::string> representative (accounts.second.get_optional<std::string> ("representative"));
|
||||
ASSERT_FALSE (representative.is_initialized ());
|
||||
}
|
||||
}
|
||||
|
||||
TEST (rpc, wallet_add_watch)
|
||||
{
|
||||
rai::system system (24000, 1);
|
||||
rai::rpc rpc (system.service, *system.nodes[0], rai::rpc_config (true));
|
||||
rpc.start ();
|
||||
boost::property_tree::ptree request;
|
||||
std::string wallet;
|
||||
system.nodes[0]->wallets.items.begin ()->first.encode_hex (wallet);
|
||||
request.put ("wallet", wallet);
|
||||
request.put ("action", "wallet_add_watch");
|
||||
boost::property_tree::ptree entry;
|
||||
boost::property_tree::ptree peers_l;
|
||||
entry.put ("", rai::test_genesis_key.pub.to_account ());
|
||||
peers_l.push_back (std::make_pair ("", entry));
|
||||
request.add_child ("accounts", peers_l);
|
||||
test_response response (request, rpc, system.service);
|
||||
while (response.status == 0)
|
||||
{
|
||||
system.poll ();
|
||||
}
|
||||
ASSERT_EQ (200, response.status);
|
||||
std::string success (response.json.get<std::string> ("success"));
|
||||
ASSERT_TRUE (success.empty ());
|
||||
ASSERT_TRUE (system.wallet (0)->exists (rai::test_genesis_key.pub));
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ TEST (wallets, wallet_create_max)
|
|||
rai::system system (24000, 1);
|
||||
bool error (false);
|
||||
rai::wallets wallets (error, *system.nodes[0]);
|
||||
const int nonWalletDbs = 16;
|
||||
const int nonWalletDbs = 17;
|
||||
for (int i = 0; i < system.nodes[0]->config.lmdb_max_dbs - nonWalletDbs; i++)
|
||||
{
|
||||
rai::keypair key;
|
||||
|
|
|
@ -29,7 +29,7 @@ int xrb_valid_address (const char * account);
|
|||
|
||||
// Create a new random number in to 'destination'
|
||||
void xrb_generate_random (xrb_uint256 destination);
|
||||
// Retrieve the detereministic private key for 'seed' at 'index'
|
||||
// Retrieve the deterministic private key for 'seed' at 'index'
|
||||
void xrb_seed_key (const xrb_uint256 seed, int index, xrb_uint256);
|
||||
// Derive the public key 'pub' from 'key'
|
||||
void xrb_key_account (xrb_uint256 key, xrb_uint256 pub);
|
||||
|
|
|
@ -988,55 +988,58 @@ void rai::bootstrap_attempt::process_fork (MDB_txn * transaction_a, std::shared_
|
|||
void rai::bootstrap_attempt::try_resolve_fork (MDB_txn * transaction_a, std::shared_ptr<rai::block> block_a, bool from_processor)
|
||||
{
|
||||
std::weak_ptr<rai::bootstrap_attempt> this_w (shared_from_this ());
|
||||
std::shared_ptr<rai::block> ledger_block (node->ledger.forked_block (transaction_a, *block_a));
|
||||
if (ledger_block)
|
||||
if (!node->store.block_exists (transaction_a, block_a->hash ()) && node->store.block_exists (transaction_a, block_a->root ()))
|
||||
{
|
||||
node->active.start (transaction_a, ledger_block, [this_w, block_a](std::shared_ptr<rai::block>, bool resolved) {
|
||||
if (auto this_l = this_w.lock ())
|
||||
{
|
||||
if (resolved)
|
||||
std::shared_ptr<rai::block> ledger_block (node->ledger.forked_block (transaction_a, *block_a));
|
||||
if (ledger_block)
|
||||
{
|
||||
node->active.start (transaction_a, ledger_block, [this_w, block_a](std::shared_ptr<rai::block>, bool resolved) {
|
||||
if (auto this_l = this_w.lock ())
|
||||
{
|
||||
if (resolved)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (this_l->mutex);
|
||||
this_l->unresolved_forks.erase (block_a->hash ());
|
||||
this_l->condition.notify_all ();
|
||||
}
|
||||
rai::transaction transaction (this_l->node->store.environment, nullptr, false);
|
||||
auto account (this_l->node->ledger.store.frontier_get (transaction, block_a->root ()));
|
||||
if (!account.is_zero ())
|
||||
{
|
||||
this_l->requeue_pull (rai::pull_info (account, block_a->root (), block_a->root ()));
|
||||
}
|
||||
else if (this_l->node->ledger.store.account_exists (transaction, block_a->root ()))
|
||||
{
|
||||
this_l->requeue_pull (rai::pull_info (block_a->root (), rai::block_hash (0), rai::block_hash (0)));
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (this_l->mutex);
|
||||
this_l->unresolved_forks.erase (block_a->hash ());
|
||||
this_l->condition.notify_all ();
|
||||
}
|
||||
rai::transaction transaction (this_l->node->store.environment, nullptr, false);
|
||||
auto account (this_l->node->ledger.store.frontier_get (transaction, block_a->root ()));
|
||||
if (!account.is_zero ())
|
||||
{
|
||||
this_l->requeue_pull (rai::pull_info (account, block_a->root (), block_a->root ()));
|
||||
}
|
||||
else if (this_l->node->ledger.store.account_exists (transaction, block_a->root ()))
|
||||
{
|
||||
this_l->requeue_pull (rai::pull_info (block_a->root (), rai::block_hash (0), rai::block_hash (0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
auto hash = block_a->hash ();
|
||||
bool exists = true;
|
||||
if (from_processor)
|
||||
{
|
||||
// Only add the block to the unresolved fork tracker if it's the first time we've seen it (i.e. this call came from the block processor).
|
||||
std::unique_lock<std::mutex> lock (mutex);
|
||||
exists = unresolved_forks.find (hash) != unresolved_forks.end ();
|
||||
if (!exists)
|
||||
{
|
||||
unresolved_forks[hash] = block_a;
|
||||
}
|
||||
}
|
||||
|
||||
auto hash = block_a->hash ();
|
||||
bool exists = true;
|
||||
if (from_processor)
|
||||
{
|
||||
// Only add the block to the unresolved fork tracker if it's the first time we've seen it (i.e. this call came from the block processor).
|
||||
std::unique_lock<std::mutex> lock (mutex);
|
||||
exists = unresolved_forks.find (hash) != unresolved_forks.end ();
|
||||
if (!exists)
|
||||
{
|
||||
unresolved_forks[hash] = block_a;
|
||||
BOOST_LOG (node->log) << boost::str (boost::format ("While bootstrappping, fork between our block: %1% and block %2% both with root %3%") % ledger_block->hash ().to_string () % hash.to_string () % block_a->root ().to_string ());
|
||||
}
|
||||
if (!exists || !from_processor)
|
||||
{
|
||||
// Only broadcast if it's a new fork, or if the request is coming from the retry loop.
|
||||
node->network.broadcast_confirm_req (ledger_block);
|
||||
node->network.broadcast_confirm_req (block_a);
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
BOOST_LOG (node->log) << boost::str (boost::format ("While bootstrappping, fork between our block: %1% and block %2% both with root %3%") % ledger_block->hash ().to_string () % hash.to_string () % block_a->root ().to_string ());
|
||||
}
|
||||
if (!exists || !from_processor)
|
||||
{
|
||||
// Only broadcast if it's a new fork, or if the request is coming from the retry loop.
|
||||
node->network.broadcast_confirm_req (ledger_block);
|
||||
node->network.broadcast_confirm_req (block_a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
#include <rai/node/common.hpp>
|
||||
|
||||
#include <rai/lib/work.hpp>
|
||||
|
@ -73,14 +74,13 @@ bool rai::message::read_header (rai::stream & stream_a, uint8_t & version_max_a,
|
|||
rai::message_parser::message_parser (rai::message_visitor & visitor_a, rai::work_pool & pool_a) :
|
||||
visitor (visitor_a),
|
||||
pool (pool_a),
|
||||
error (false),
|
||||
insufficient_work (false)
|
||||
status (parse_status::success)
|
||||
{
|
||||
}
|
||||
|
||||
void rai::message_parser::deserialize_buffer (uint8_t const * buffer_a, size_t size_a)
|
||||
{
|
||||
error = false;
|
||||
status = parse_status::success;
|
||||
rai::bufferstream header_stream (buffer_a, size_a);
|
||||
uint8_t version_max;
|
||||
uint8_t version_using;
|
||||
|
@ -113,14 +113,14 @@ void rai::message_parser::deserialize_buffer (uint8_t const * buffer_a, size_t s
|
|||
}
|
||||
default:
|
||||
{
|
||||
error = true;
|
||||
status = parse_status::invalid_message_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
status = parse_status::invalid_header;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,7 @@ void rai::message_parser::deserialize_keepalive (uint8_t const * buffer_a, size_
|
|||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
status = parse_status::invalid_keepalive_message;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,12 +152,12 @@ void rai::message_parser::deserialize_publish (uint8_t const * buffer_a, size_t
|
|||
}
|
||||
else
|
||||
{
|
||||
insufficient_work = true;
|
||||
status = parse_status::insufficient_work;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
status = parse_status::invalid_publish_message;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,12 +174,12 @@ void rai::message_parser::deserialize_confirm_req (uint8_t const * buffer_a, siz
|
|||
}
|
||||
else
|
||||
{
|
||||
insufficient_work = true;
|
||||
status = parse_status::insufficient_work;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
status = parse_status::invalid_confirm_req_message;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,12 +196,12 @@ void rai::message_parser::deserialize_confirm_ack (uint8_t const * buffer_a, siz
|
|||
}
|
||||
else
|
||||
{
|
||||
insufficient_work = true;
|
||||
status = parse_status::insufficient_work;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
status = parse_status::invalid_confirm_ack_message;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,18 +241,23 @@ void rai::keepalive::serialize (rai::stream & stream_a)
|
|||
|
||||
bool rai::keepalive::deserialize (rai::stream & stream_a)
|
||||
{
|
||||
auto result (read_header (stream_a, version_max, version_using, version_min, type, extensions));
|
||||
assert (!result);
|
||||
auto error (read_header (stream_a, version_max, version_using, version_min, type, extensions));
|
||||
assert (!error);
|
||||
assert (type == rai::message_type::keepalive);
|
||||
for (auto i (peers.begin ()), j (peers.end ()); i != j; ++i)
|
||||
for (auto i (peers.begin ()), j (peers.end ()); i != j && !error; ++i)
|
||||
{
|
||||
std::array<uint8_t, 16> address;
|
||||
uint16_t port;
|
||||
read (stream_a, address);
|
||||
read (stream_a, port);
|
||||
*i = rai::endpoint (boost::asio::ip::address_v6 (address), port);
|
||||
if (!read (stream_a, address) && !read (stream_a, port))
|
||||
{
|
||||
*i = rai::endpoint (boost::asio::ip::address_v6 (address), port);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return error;
|
||||
}
|
||||
|
||||
bool rai::keepalive::operator== (rai::keepalive const & other_a) const
|
||||
|
|
|
@ -130,6 +130,17 @@ class work_pool;
|
|||
class message_parser
|
||||
{
|
||||
public:
|
||||
enum class parse_status
|
||||
{
|
||||
success,
|
||||
insufficient_work,
|
||||
invalid_header,
|
||||
invalid_message_type,
|
||||
invalid_keepalive_message,
|
||||
invalid_publish_message,
|
||||
invalid_confirm_req_message,
|
||||
invalid_confirm_ack_message
|
||||
};
|
||||
message_parser (rai::message_visitor &, rai::work_pool &);
|
||||
void deserialize_buffer (uint8_t const *, size_t);
|
||||
void deserialize_keepalive (uint8_t const *, size_t);
|
||||
|
@ -139,8 +150,7 @@ public:
|
|||
bool at_end (rai::bufferstream &);
|
||||
rai::message_visitor & visitor;
|
||||
rai::work_pool & pool;
|
||||
bool error;
|
||||
bool insufficient_work;
|
||||
parse_status status;
|
||||
};
|
||||
class keepalive : public message
|
||||
{
|
||||
|
|
|
@ -254,7 +254,7 @@ void rai::network::broadcast_confirm_req (std::shared_ptr<rai::block> block_a)
|
|||
}
|
||||
if (node.config.logging.network_logging ())
|
||||
{
|
||||
BOOST_LOG (node.log) << boost::str (boost::format ("Broadcasted confirm req to %1% representatives") % list.size ());
|
||||
BOOST_LOG (node.log) << boost::str (boost::format ("Broadcasted confirm req for block %1% to %2% representatives") % block_a->hash ().to_string () % list.size ());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,17 +419,65 @@ void rai::network::receive_action (boost::system::error_code const & error, size
|
|||
network_message_visitor visitor (node, remote);
|
||||
rai::message_parser parser (visitor, node.work);
|
||||
parser.deserialize_buffer (buffer.data (), size_a);
|
||||
if (parser.error)
|
||||
if (parser.status != rai::message_parser::parse_status::success)
|
||||
{
|
||||
++error_count;
|
||||
}
|
||||
else if (parser.insufficient_work)
|
||||
{
|
||||
if (node.config.logging.insufficient_work_logging ())
|
||||
|
||||
if (parser.status == rai::message_parser::parse_status::insufficient_work)
|
||||
{
|
||||
BOOST_LOG (node.log) << "Insufficient work in message";
|
||||
if (node.config.logging.insufficient_work_logging ())
|
||||
{
|
||||
BOOST_LOG (node.log) << "Insufficient work in message";
|
||||
}
|
||||
|
||||
++insufficient_work_count;
|
||||
}
|
||||
else if (parser.status == rai::message_parser::parse_status::invalid_message_type)
|
||||
{
|
||||
if (node.config.logging.network_logging ())
|
||||
{
|
||||
BOOST_LOG (node.log) << "Invalid message type in message";
|
||||
}
|
||||
}
|
||||
else if (parser.status == rai::message_parser::parse_status::invalid_header)
|
||||
{
|
||||
if (node.config.logging.network_logging ())
|
||||
{
|
||||
BOOST_LOG (node.log) << "Invalid header in message";
|
||||
}
|
||||
}
|
||||
else if (parser.status == rai::message_parser::parse_status::invalid_keepalive_message)
|
||||
{
|
||||
if (node.config.logging.network_logging ())
|
||||
{
|
||||
BOOST_LOG (node.log) << "Invalid keepalive message";
|
||||
}
|
||||
}
|
||||
else if (parser.status == rai::message_parser::parse_status::invalid_publish_message)
|
||||
{
|
||||
if (node.config.logging.network_logging ())
|
||||
{
|
||||
BOOST_LOG (node.log) << "Invalid publish message";
|
||||
}
|
||||
}
|
||||
else if (parser.status == rai::message_parser::parse_status::invalid_confirm_req_message)
|
||||
{
|
||||
if (node.config.logging.network_logging ())
|
||||
{
|
||||
BOOST_LOG (node.log) << "Invalid confirm_req message";
|
||||
}
|
||||
}
|
||||
else if (parser.status == rai::message_parser::parse_status::invalid_confirm_ack_message)
|
||||
{
|
||||
if (node.config.logging.network_logging ())
|
||||
{
|
||||
BOOST_LOG (node.log) << "Invalid confirm_ack message";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_LOG (node.log) << "Could not deserialize buffer";
|
||||
}
|
||||
++insufficient_work_count;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -763,11 +811,8 @@ lmdb_max_dbs (128)
|
|||
preconfigured_representatives.push_back (rai::genesis_account);
|
||||
break;
|
||||
case rai::rai_networks::rai_beta_network:
|
||||
preconfigured_peers.push_back ("rai.raiblocks.net");
|
||||
preconfigured_representatives.push_back (rai::account ("59750C057F42806F40C5D9EAA1E0263E9DB48FE385BD0172BFC573BD37EEC4A7"));
|
||||
preconfigured_representatives.push_back (rai::account ("8B05C9B160DE9B006FA27DD6A368D7CA122A2EE7537C308CF22EFD3ABF5B36C3"));
|
||||
preconfigured_representatives.push_back (rai::account ("91D51BF05F02698EBB4649FB06D1BBFD2E4AE2579660E8D784A002D9C0CB1BD2"));
|
||||
preconfigured_representatives.push_back (rai::account ("CB35ED23D47E1A16667EDE415CD4CD05961481D7D23A43958FAE81FC12FA49FF"));
|
||||
preconfigured_peers.push_back ("rai-beta.raiblocks.net");
|
||||
preconfigured_representatives.push_back (rai::account ("5DF352F3E7367A17F2ADB52B8123959602F8D94C2F295B23F6BDFFFC5FEFCA5E"));
|
||||
break;
|
||||
case rai::rai_networks::rai_live_network:
|
||||
preconfigured_peers.push_back ("rai.raiblocks.net");
|
||||
|
@ -1518,6 +1563,15 @@ block_processor_thread ([this]() { this->block_processor.process_blocks (); })
|
|||
if (peers.rep_response (endpoint_a, weight_l))
|
||||
{
|
||||
BOOST_LOG (log) << boost::str (boost::format ("Found a representative at %1%") % endpoint_a);
|
||||
// Rebroadcasting all active votes to new representative
|
||||
auto blocks (active.list_blocks ());
|
||||
for (auto i (blocks.begin ()), n (blocks.end ()); i != n; ++i)
|
||||
{
|
||||
if (*i != nullptr)
|
||||
{
|
||||
this->network.send_confirm_req (endpoint_a, *i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -2534,16 +2588,18 @@ void rai::peer_container::rep_request (rai::endpoint const & endpoint_a)
|
|||
|
||||
bool rai::peer_container::reachout (rai::endpoint const & endpoint_a)
|
||||
{
|
||||
auto result (false);
|
||||
// Don't contact invalid IPs
|
||||
result |= not_a_peer (endpoint_a);
|
||||
// Don't keepalive to nodes that already sent us something
|
||||
result |= known_peer (endpoint_a);
|
||||
std::lock_guard<std::mutex> lock (mutex);
|
||||
auto existing (attempts.find (endpoint_a));
|
||||
result |= existing != attempts.end ();
|
||||
attempts.insert ({ endpoint_a, std::chrono::steady_clock::now () });
|
||||
return result;
|
||||
bool error = not_a_peer (endpoint_a);
|
||||
if (!error)
|
||||
{
|
||||
// Don't keepalive to nodes that already sent us something
|
||||
error |= known_peer (endpoint_a);
|
||||
std::lock_guard<std::mutex> lock (mutex);
|
||||
auto existing (attempts.find (endpoint_a));
|
||||
error |= existing != attempts.end ();
|
||||
attempts.insert ({ endpoint_a, std::chrono::steady_clock::now () });
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
bool rai::peer_container::insert (rai::endpoint const & endpoint_a, unsigned version_a)
|
||||
|
@ -2761,7 +2817,7 @@ rai::uint128_t rai::election::quorum_threshold (MDB_txn * transaction_a, rai::le
|
|||
|
||||
rai::uint128_t rai::election::minimum_threshold (MDB_txn * transaction_a, rai::ledger & ledger_a)
|
||||
{
|
||||
// Minimum number of votes needed to change our ledger, underwhich we're probably disconnected
|
||||
// Minimum number of votes needed to change our ledger, under which we're probably disconnected
|
||||
return ledger_a.supply (transaction_a) / 16;
|
||||
}
|
||||
|
||||
|
@ -2854,7 +2910,7 @@ void rai::active_transactions::announce_votes ()
|
|||
{
|
||||
auto election_l (i->election);
|
||||
node.background ([election_l]() { election_l->broadcast_winner (); });
|
||||
if (i->announcements >= contigious_announcements - 1)
|
||||
if (i->announcements >= contiguous_announcements - 1)
|
||||
{
|
||||
// These blocks have reached the confirmation interval for forks
|
||||
i->election->confirm_cutoff (transaction);
|
||||
|
@ -2939,6 +2995,18 @@ bool rai::active_transactions::active (rai::block const & block_a)
|
|||
return roots.find (block_a.root ()) != roots.end ();
|
||||
}
|
||||
|
||||
// List of active blocks in elections
|
||||
std::deque<std::shared_ptr<rai::block>> rai::active_transactions::list_blocks ()
|
||||
{
|
||||
std::deque<std::shared_ptr<rai::block>> result;
|
||||
std::lock_guard<std::mutex> lock (mutex);
|
||||
for (auto i (roots.begin ()), n (roots.end ()); i != n; ++i)
|
||||
{
|
||||
result.push_back (i->election->last_winner);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
rai::active_transactions::active_transactions (rai::node & node_a) :
|
||||
node (node_a)
|
||||
{
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
// Number of announcements in a row for this fork
|
||||
unsigned announcements;
|
||||
};
|
||||
// Core class for determining concensus
|
||||
// Core class for determining consensus
|
||||
// Holds all active blocks i.e. recently added blocks that need confirmation
|
||||
class active_transactions
|
||||
{
|
||||
|
@ -83,6 +83,7 @@ public:
|
|||
// Is the root of this block in the roots container
|
||||
bool active (rai::block const &);
|
||||
void announce_votes ();
|
||||
std::deque<std::shared_ptr<rai::block>> list_blocks ();
|
||||
void stop ();
|
||||
boost::multi_index_container<
|
||||
rai::conflict_info,
|
||||
|
@ -94,7 +95,7 @@ public:
|
|||
// Maximum number of conflicts to vote on per interval, lowest root hash first
|
||||
static unsigned constexpr announcements_per_interval = 32;
|
||||
// After this many successive vote announcements, block is confirmed
|
||||
static unsigned constexpr contigious_announcements = 4;
|
||||
static unsigned constexpr contiguous_announcements = 4;
|
||||
static unsigned constexpr announce_interval_ms = (rai::rai_network == rai::rai_networks::rai_test_network) ? 10 : 16000;
|
||||
};
|
||||
class operation
|
||||
|
@ -247,7 +248,7 @@ public:
|
|||
void refresh_devices ();
|
||||
// Refresh when the lease ends
|
||||
void refresh_mapping ();
|
||||
// Refresh ocassionally in case router loses mapping
|
||||
// Refresh occasionally in case router loses mapping
|
||||
void check_mapping_loop ();
|
||||
int check_mapping ();
|
||||
bool has_address ();
|
||||
|
@ -428,7 +429,7 @@ public:
|
|||
rai::vote_result vote (std::shared_ptr<rai::vote>, rai::endpoint);
|
||||
rai::node & node;
|
||||
};
|
||||
// The network is crawled for representatives by ocassionally sending a unicast confirm_req for a specific block and watching to see if it's acknowledged with a vote.
|
||||
// The network is crawled for representatives by occasionally sending a unicast confirm_req for a specific block and watching to see if it's acknowledged with a vote.
|
||||
class rep_crawler
|
||||
{
|
||||
public:
|
||||
|
|
498
rai/node/rpc.cpp
498
rai/node/rpc.cpp
|
@ -282,12 +282,7 @@ void rai::rpc_handler::account_create ()
|
|||
auto existing (node.wallets.items.find (wallet));
|
||||
if (existing != node.wallets.items.end ())
|
||||
{
|
||||
bool generate_work (true);
|
||||
boost::optional<bool> work (request.get_optional<bool> ("work"));
|
||||
if (work.is_initialized ())
|
||||
{
|
||||
generate_work = work.get ();
|
||||
}
|
||||
const bool generate_work = request.get<bool> ("work", true);
|
||||
rai::account new_key (existing->second->deterministic_insert (generate_work));
|
||||
if (!new_key.is_zero ())
|
||||
{
|
||||
|
@ -340,24 +335,9 @@ void rai::rpc_handler::account_info ()
|
|||
auto error (account.decode_account (account_text));
|
||||
if (!error)
|
||||
{
|
||||
bool representative (false);
|
||||
boost::optional<bool> representative_optional (request.get_optional<bool> ("representative"));
|
||||
if (representative_optional.is_initialized ())
|
||||
{
|
||||
representative = representative_optional.get ();
|
||||
}
|
||||
bool weight (false);
|
||||
boost::optional<bool> weight_optional (request.get_optional<bool> ("weight"));
|
||||
if (weight_optional.is_initialized ())
|
||||
{
|
||||
weight = weight_optional.get ();
|
||||
}
|
||||
bool pending (false);
|
||||
boost::optional<bool> pending_optional (request.get_optional<bool> ("pending"));
|
||||
if (pending_optional.is_initialized ())
|
||||
{
|
||||
pending = pending_optional.get ();
|
||||
}
|
||||
const bool representative = request.get<bool> ("representative", false);
|
||||
const bool weight = request.get<bool> ("weight", false);
|
||||
const bool pending = request.get<bool> ("pending", false);
|
||||
rai::transaction transaction (node.store.environment, nullptr, false);
|
||||
rai::account_info info;
|
||||
if (!node.store.account_get (transaction, account, info))
|
||||
|
@ -742,12 +722,7 @@ void rai::rpc_handler::accounts_create ()
|
|||
auto existing (node.wallets.items.find (wallet));
|
||||
if (existing != node.wallets.items.end ())
|
||||
{
|
||||
bool generate_work (true);
|
||||
boost::optional<bool> work (request.get_optional<bool> ("work"));
|
||||
if (work.is_initialized ())
|
||||
{
|
||||
generate_work = work.get ();
|
||||
}
|
||||
const bool generate_work = request.get<bool> ("work", true);
|
||||
boost::property_tree::ptree response_l;
|
||||
boost::property_tree::ptree accounts;
|
||||
for (auto i (0); accounts.size () < count; ++i)
|
||||
|
@ -815,7 +790,6 @@ void rai::rpc_handler::accounts_pending ()
|
|||
{
|
||||
uint64_t count (std::numeric_limits<uint64_t>::max ());
|
||||
rai::uint128_union threshold (0);
|
||||
bool source (false);
|
||||
boost::optional<std::string> count_text (request.get_optional<std::string> ("count"));
|
||||
if (count_text.is_initialized ())
|
||||
{
|
||||
|
@ -834,11 +808,7 @@ void rai::rpc_handler::accounts_pending ()
|
|||
error_response (response, "Bad threshold number");
|
||||
}
|
||||
}
|
||||
boost::optional<bool> source_optional (request.get_optional<bool> ("source"));
|
||||
if (source_optional.is_initialized ())
|
||||
{
|
||||
source = source_optional.get ();
|
||||
}
|
||||
const bool source = request.get<bool> ("source", false);
|
||||
boost::property_tree::ptree response_l;
|
||||
boost::property_tree::ptree pending;
|
||||
rai::transaction transaction (node.store.environment, nullptr, false);
|
||||
|
@ -965,18 +935,8 @@ void rai::rpc_handler::blocks ()
|
|||
|
||||
void rai::rpc_handler::blocks_info ()
|
||||
{
|
||||
bool pending (false);
|
||||
boost::optional<bool> pending_optional (request.get_optional<bool> ("pending"));
|
||||
if (pending_optional.is_initialized ())
|
||||
{
|
||||
pending = pending_optional.get ();
|
||||
}
|
||||
bool source (false);
|
||||
boost::optional<bool> source_optional (request.get_optional<bool> ("source"));
|
||||
if (source_optional.is_initialized ())
|
||||
{
|
||||
source = source_optional.get ();
|
||||
}
|
||||
const bool pending = request.get<bool> ("pending", false);
|
||||
const bool source = request.get<bool> ("source", false);
|
||||
std::vector<std::string> hashes;
|
||||
boost::property_tree::ptree response_l;
|
||||
boost::property_tree::ptree blocks;
|
||||
|
@ -1622,7 +1582,8 @@ namespace
|
|||
class history_visitor : public rai::block_visitor
|
||||
{
|
||||
public:
|
||||
history_visitor (rai::rpc_handler & handler_a, rai::transaction & transaction_a, boost::property_tree::ptree & tree_a, rai::block_hash const & hash_a) :
|
||||
history_visitor (rai::rpc_handler & handler_a, bool raw_a, rai::transaction & transaction_a, boost::property_tree::ptree & tree_a, rai::block_hash const & hash_a) :
|
||||
raw (raw_a),
|
||||
handler (handler_a),
|
||||
transaction (transaction_a),
|
||||
tree (tree_a),
|
||||
|
@ -1637,6 +1598,11 @@ public:
|
|||
tree.put ("account", account);
|
||||
auto amount (handler.node.ledger.amount (transaction, hash).convert_to<std::string> ());
|
||||
tree.put ("amount", amount);
|
||||
if (raw)
|
||||
{
|
||||
tree.put ("destination", account);
|
||||
tree.put ("balance", block_a.hashables.balance.to_string_dec ());
|
||||
}
|
||||
}
|
||||
void receive_block (rai::receive_block const & block_a)
|
||||
{
|
||||
|
@ -1645,11 +1611,25 @@ public:
|
|||
tree.put ("account", account);
|
||||
auto amount (handler.node.ledger.amount (transaction, hash).convert_to<std::string> ());
|
||||
tree.put ("amount", amount);
|
||||
if (raw)
|
||||
{
|
||||
tree.put ("source", block_a.hashables.source.to_string ());
|
||||
}
|
||||
}
|
||||
void open_block (rai::open_block const & block_a)
|
||||
{
|
||||
// Report opens as a receive
|
||||
tree.put ("type", "receive");
|
||||
if (raw)
|
||||
{
|
||||
tree.put ("type", "open");
|
||||
tree.put ("representative", block_a.hashables.representative.to_account ());
|
||||
tree.put ("source", block_a.hashables.source.to_string ());
|
||||
tree.put ("opened", block_a.hashables.account.to_account ());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Report opens as a receive
|
||||
tree.put ("type", "receive");
|
||||
}
|
||||
if (block_a.hashables.source != rai::genesis_account)
|
||||
{
|
||||
tree.put ("account", handler.node.ledger.account (transaction, block_a.hashables.source).to_account ());
|
||||
|
@ -1661,17 +1641,34 @@ public:
|
|||
tree.put ("amount", rai::genesis_amount.convert_to<std::string> ());
|
||||
}
|
||||
}
|
||||
void change_block (rai::change_block const &)
|
||||
void change_block (rai::change_block const & block_a)
|
||||
{
|
||||
// Don't report change blocks
|
||||
if (raw)
|
||||
{
|
||||
tree.put ("type", "change");
|
||||
tree.put ("representative", block_a.hashables.representative.to_account ());
|
||||
}
|
||||
}
|
||||
void utx_block (rai::utx_block const & block_a)
|
||||
{
|
||||
if (raw)
|
||||
{
|
||||
tree.put ("type", "utx");
|
||||
tree.put ("representative", block_a.hashables.representative.to_account ());
|
||||
tree.put ("link", block_a.hashables.link.to_string ());
|
||||
}
|
||||
auto balance (block_a.hashables.balance.number ());
|
||||
auto previous_balance (handler.node.ledger.balance (transaction, block_a.hashables.previous));
|
||||
if (balance < previous_balance)
|
||||
{
|
||||
tree.put ("type", "send");
|
||||
if (raw)
|
||||
{
|
||||
tree.put ("subtype", "send");
|
||||
}
|
||||
else
|
||||
{
|
||||
tree.put ("type", "send");
|
||||
}
|
||||
tree.put ("account", block_a.hashables.account.to_account ());
|
||||
tree.put ("amount", (previous_balance - balance).convert_to<std::string> ());
|
||||
}
|
||||
|
@ -1679,107 +1676,121 @@ public:
|
|||
{
|
||||
if (block_a.hashables.link.is_zero ())
|
||||
{
|
||||
// Don't report change blocks
|
||||
if (raw)
|
||||
{
|
||||
tree.put ("subtype", "change");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tree.put ("type", "receive");
|
||||
if (raw)
|
||||
{
|
||||
tree.put ("subtype", "receive");
|
||||
}
|
||||
else
|
||||
{
|
||||
tree.put ("type", "receive");
|
||||
}
|
||||
tree.put ("account", block_a.hashables.account.to_account ());
|
||||
tree.put ("amount", (balance - previous_balance).convert_to<std::string> ());
|
||||
}
|
||||
}
|
||||
}
|
||||
rai::rpc_handler & handler;
|
||||
bool raw;
|
||||
rai::transaction & transaction;
|
||||
boost::property_tree::ptree & tree;
|
||||
rai::block_hash const & hash;
|
||||
};
|
||||
}
|
||||
|
||||
void rai::rpc_handler::history ()
|
||||
void rai::rpc_handler::account_history ()
|
||||
{
|
||||
std::string hash_text (request.get<std::string> ("hash"));
|
||||
std::string count_text (request.get<std::string> ("count"));
|
||||
bool output_raw (request.get_optional<bool> ("raw") == true);
|
||||
auto error (false);
|
||||
rai::block_hash hash;
|
||||
if (!hash.decode_hex (hash_text))
|
||||
auto head_str (request.get_optional<std::string> ("head"));
|
||||
rai::transaction transaction (node.store.environment, nullptr, false);
|
||||
if (head_str)
|
||||
{
|
||||
uint64_t count;
|
||||
if (!decode_unsigned (count_text, count))
|
||||
error = hash.decode_hex (*head_str);
|
||||
if (error)
|
||||
{
|
||||
boost::property_tree::ptree response_l;
|
||||
boost::property_tree::ptree history;
|
||||
rai::transaction transaction (node.store.environment, nullptr, false);
|
||||
auto block (node.store.block_get (transaction, hash));
|
||||
while (block != nullptr && count > 0)
|
||||
{
|
||||
boost::property_tree::ptree entry;
|
||||
history_visitor visitor (*this, transaction, entry, hash);
|
||||
block->visit (visitor);
|
||||
if (!entry.empty ())
|
||||
{
|
||||
entry.put ("hash", hash.to_string ());
|
||||
history.push_back (std::make_pair ("", entry));
|
||||
}
|
||||
hash = block->previous ();
|
||||
block = node.store.block_get (transaction, hash);
|
||||
--count;
|
||||
}
|
||||
response_l.add_child ("history", history);
|
||||
response (response_l);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "Invalid count limit");
|
||||
error_response (response, "Invalid block hash");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "Invalid block hash");
|
||||
std::string account_text (request.get<std::string> ("account"));
|
||||
rai::uint256_union account;
|
||||
error = account.decode_account (account_text);
|
||||
if (!error)
|
||||
{
|
||||
hash = node.ledger.latest (transaction, account);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "Bad account number");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rai::rpc_handler::account_history ()
|
||||
{
|
||||
std::string account_text (request.get<std::string> ("account"));
|
||||
std::string count_text (request.get<std::string> ("count"));
|
||||
rai::uint256_union account;
|
||||
auto error (account.decode_account (account_text));
|
||||
if (!error)
|
||||
{
|
||||
uint64_t count;
|
||||
if (!decode_unsigned (count_text, count))
|
||||
{
|
||||
boost::property_tree::ptree response_l;
|
||||
boost::property_tree::ptree history;
|
||||
rai::transaction transaction (node.store.environment, nullptr, false);
|
||||
auto hash (node.ledger.latest (transaction, account));
|
||||
auto block (node.store.block_get (transaction, hash));
|
||||
while (block != nullptr && count > 0)
|
||||
uint64_t offset = 0;
|
||||
auto offset_text (request.get_optional<std::string> ("offset"));
|
||||
if (!offset_text || !decode_unsigned (*offset_text, offset))
|
||||
{
|
||||
boost::property_tree::ptree entry;
|
||||
history_visitor visitor (*this, transaction, entry, hash);
|
||||
block->visit (visitor);
|
||||
if (!entry.empty ())
|
||||
boost::property_tree::ptree response_l;
|
||||
boost::property_tree::ptree history;
|
||||
if (!error)
|
||||
{
|
||||
entry.put ("hash", hash.to_string ());
|
||||
history.push_back (std::make_pair ("", entry));
|
||||
auto block (node.store.block_get (transaction, hash));
|
||||
while (block != nullptr && count > 0)
|
||||
{
|
||||
if (offset > 0)
|
||||
{
|
||||
--offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::property_tree::ptree entry;
|
||||
history_visitor visitor (*this, output_raw, transaction, entry, hash);
|
||||
block->visit (visitor);
|
||||
if (!entry.empty ())
|
||||
{
|
||||
entry.put ("hash", hash.to_string ());
|
||||
history.push_back (std::make_pair ("", entry));
|
||||
}
|
||||
--count;
|
||||
}
|
||||
hash = block->previous ();
|
||||
block = node.store.block_get (transaction, hash);
|
||||
}
|
||||
response_l.add_child ("history", history);
|
||||
if (!hash.is_zero ())
|
||||
{
|
||||
response_l.put ("previous", hash.to_string ());
|
||||
}
|
||||
response (response_l);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "Failed to decode head block hash");
|
||||
}
|
||||
hash = block->previous ();
|
||||
block = node.store.block_get (transaction, hash);
|
||||
--count;
|
||||
}
|
||||
response_l.add_child ("history", history);
|
||||
response (response_l);
|
||||
else
|
||||
{
|
||||
error_response (response, "Invalid offset");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "Invalid count limit");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "Bad account number");
|
||||
}
|
||||
}
|
||||
|
||||
void rai::rpc_handler::keepalive ()
|
||||
|
@ -1843,7 +1854,6 @@ void rai::rpc_handler::ledger ()
|
|||
{
|
||||
rai::account start (0);
|
||||
uint64_t count (std::numeric_limits<uint64_t>::max ());
|
||||
bool sorting (false);
|
||||
boost::optional<std::string> account_text (request.get_optional<std::string> ("account"));
|
||||
if (account_text.is_initialized ())
|
||||
{
|
||||
|
@ -1862,29 +1872,16 @@ void rai::rpc_handler::ledger ()
|
|||
error_response (response, "Invalid count limit");
|
||||
}
|
||||
}
|
||||
boost::optional<bool> sorting_optional (request.get_optional<bool> ("sorting"));
|
||||
if (sorting_optional.is_initialized ())
|
||||
uint64_t modified_since (0);
|
||||
boost::optional<std::string> modified_since_text (request.get_optional<std::string> ("modified_since"));
|
||||
if (modified_since_text.is_initialized ())
|
||||
{
|
||||
sorting = sorting_optional.get ();
|
||||
}
|
||||
bool representative (false);
|
||||
boost::optional<bool> representative_optional (request.get_optional<bool> ("representative"));
|
||||
if (representative_optional.is_initialized ())
|
||||
{
|
||||
representative = representative_optional.get ();
|
||||
}
|
||||
bool weight (false);
|
||||
boost::optional<bool> weight_optional (request.get_optional<bool> ("weight"));
|
||||
if (weight_optional.is_initialized ())
|
||||
{
|
||||
weight = weight_optional.get ();
|
||||
}
|
||||
bool pending (false);
|
||||
boost::optional<bool> pending_optional (request.get_optional<bool> ("pending"));
|
||||
if (pending_optional.is_initialized ())
|
||||
{
|
||||
pending = pending_optional.get ();
|
||||
modified_since = strtoul (modified_since_text.get ().c_str (), NULL, 10);
|
||||
}
|
||||
const bool sorting = request.get<bool> ("sorting", false);
|
||||
const bool representative = request.get<bool> ("representative", false);
|
||||
const bool weight = request.get<bool> ("weight", false);
|
||||
const bool pending = request.get<bool> ("pending", false);
|
||||
boost::property_tree::ptree response_a;
|
||||
boost::property_tree::ptree response_l;
|
||||
boost::property_tree::ptree accounts;
|
||||
|
@ -1894,33 +1891,36 @@ void rai::rpc_handler::ledger ()
|
|||
for (auto i (node.store.latest_begin (transaction, start)), n (node.store.latest_end ()); i != n && accounts.size () < count; ++i)
|
||||
{
|
||||
rai::account_info info (i->second);
|
||||
rai::account account (i->first.uint256 ());
|
||||
boost::property_tree::ptree response_l;
|
||||
response_l.put ("frontier", info.head.to_string ());
|
||||
response_l.put ("open_block", info.open_block.to_string ());
|
||||
response_l.put ("representative_block", info.rep_block.to_string ());
|
||||
std::string balance;
|
||||
rai::uint128_union (info.balance).encode_dec (balance);
|
||||
response_l.put ("balance", balance);
|
||||
response_l.put ("modified_timestamp", std::to_string (info.modified));
|
||||
response_l.put ("block_count", std::to_string (info.block_count));
|
||||
if (representative)
|
||||
if (info.modified >= modified_since)
|
||||
{
|
||||
auto block (node.store.block_get (transaction, info.rep_block));
|
||||
assert (block != nullptr);
|
||||
response_l.put ("representative", block->representative ().to_account ());
|
||||
rai::account account (i->first.uint256 ());
|
||||
boost::property_tree::ptree response_l;
|
||||
response_l.put ("frontier", info.head.to_string ());
|
||||
response_l.put ("open_block", info.open_block.to_string ());
|
||||
response_l.put ("representative_block", info.rep_block.to_string ());
|
||||
std::string balance;
|
||||
rai::uint128_union (info.balance).encode_dec (balance);
|
||||
response_l.put ("balance", balance);
|
||||
response_l.put ("modified_timestamp", std::to_string (info.modified));
|
||||
response_l.put ("block_count", std::to_string (info.block_count));
|
||||
if (representative)
|
||||
{
|
||||
auto block (node.store.block_get (transaction, info.rep_block));
|
||||
assert (block != nullptr);
|
||||
response_l.put ("representative", block->representative ().to_account ());
|
||||
}
|
||||
if (weight)
|
||||
{
|
||||
auto account_weight (node.ledger.weight (transaction, account));
|
||||
response_l.put ("weight", account_weight.convert_to<std::string> ());
|
||||
}
|
||||
if (pending)
|
||||
{
|
||||
auto account_pending (node.ledger.account_pending (transaction, account));
|
||||
response_l.put ("pending", account_pending.convert_to<std::string> ());
|
||||
}
|
||||
accounts.push_back (std::make_pair (account.to_account (), response_l));
|
||||
}
|
||||
if (weight)
|
||||
{
|
||||
auto account_weight (node.ledger.weight (transaction, account));
|
||||
response_l.put ("weight", account_weight.convert_to<std::string> ());
|
||||
}
|
||||
if (pending)
|
||||
{
|
||||
auto account_pending (node.ledger.account_pending (transaction, account));
|
||||
response_l.put ("pending", account_pending.convert_to<std::string> ());
|
||||
}
|
||||
accounts.push_back (std::make_pair (account.to_account (), response_l));
|
||||
}
|
||||
}
|
||||
else // Sorting
|
||||
|
@ -1928,8 +1928,12 @@ void rai::rpc_handler::ledger ()
|
|||
std::vector<std::pair<rai::uint128_union, rai::account>> ledger_l;
|
||||
for (auto i (node.store.latest_begin (transaction, start)), n (node.store.latest_end ()); i != n; ++i)
|
||||
{
|
||||
rai::uint128_union balance (rai::account_info (i->second).balance);
|
||||
ledger_l.push_back (std::make_pair (balance, rai::account (i->first.uint256 ())));
|
||||
rai::account_info info (i->second);
|
||||
rai::uint128_union balance (info.balance);
|
||||
if (info.modified >= modified_since)
|
||||
{
|
||||
ledger_l.push_back (std::make_pair (balance, rai::account (i->first.uint256 ())));
|
||||
}
|
||||
}
|
||||
std::sort (ledger_l.begin (), ledger_l.end ());
|
||||
std::reverse (ledger_l.begin (), ledger_l.end ());
|
||||
|
@ -2175,7 +2179,6 @@ void rai::rpc_handler::pending ()
|
|||
{
|
||||
uint64_t count (std::numeric_limits<uint64_t>::max ());
|
||||
rai::uint128_union threshold (0);
|
||||
bool source (false);
|
||||
boost::optional<std::string> count_text (request.get_optional<std::string> ("count"));
|
||||
if (count_text.is_initialized ())
|
||||
{
|
||||
|
@ -2194,11 +2197,7 @@ void rai::rpc_handler::pending ()
|
|||
error_response (response, "Bad threshold number");
|
||||
}
|
||||
}
|
||||
boost::optional<bool> source_optional (request.get_optional<bool> ("source"));
|
||||
if (source_optional.is_initialized ())
|
||||
{
|
||||
source = source_optional.get ();
|
||||
}
|
||||
const bool source = request.get<bool> ("source", false);
|
||||
boost::property_tree::ptree response_l;
|
||||
boost::property_tree::ptree peers_l;
|
||||
{
|
||||
|
@ -2761,7 +2760,6 @@ void rai::rpc_handler::receive_minimum_set ()
|
|||
void rai::rpc_handler::representatives ()
|
||||
{
|
||||
uint64_t count (std::numeric_limits<uint64_t>::max ());
|
||||
bool sorting (false);
|
||||
boost::optional<std::string> count_text (request.get_optional<std::string> ("count"));
|
||||
if (count_text.is_initialized ())
|
||||
{
|
||||
|
@ -2771,11 +2769,7 @@ void rai::rpc_handler::representatives ()
|
|||
error_response (response, "Invalid count limit");
|
||||
}
|
||||
}
|
||||
boost::optional<bool> sorting_optional (request.get_optional<bool> ("sorting"));
|
||||
if (sorting_optional.is_initialized ())
|
||||
{
|
||||
sorting = sorting_optional.get ();
|
||||
}
|
||||
const bool sorting = request.get<bool> ("sorting", false);
|
||||
boost::property_tree::ptree response_l;
|
||||
boost::property_tree::ptree representatives;
|
||||
rai::transaction transaction (node.store.environment, nullptr, false);
|
||||
|
@ -3265,12 +3259,7 @@ void rai::rpc_handler::wallet_add ()
|
|||
auto existing (node.wallets.items.find (wallet));
|
||||
if (existing != node.wallets.items.end ())
|
||||
{
|
||||
bool generate_work (true);
|
||||
boost::optional<bool> work (request.get_optional<bool> ("work"));
|
||||
if (work.is_initialized ())
|
||||
{
|
||||
generate_work = work.get ();
|
||||
}
|
||||
const bool generate_work = request.get<bool> ("work", true);
|
||||
auto pub (existing->second->insert_adhoc (key, generate_work));
|
||||
if (!pub.is_zero ())
|
||||
{
|
||||
|
@ -3304,6 +3293,60 @@ void rai::rpc_handler::wallet_add ()
|
|||
}
|
||||
}
|
||||
|
||||
void rai::rpc_handler::wallet_add_watch ()
|
||||
{
|
||||
if (rpc.config.enable_control)
|
||||
{
|
||||
std::string wallet_text (request.get<std::string> ("wallet"));
|
||||
rai::uint256_union wallet;
|
||||
auto error (wallet.decode_hex (wallet_text));
|
||||
if (!error)
|
||||
{
|
||||
auto existing (node.wallets.items.find (wallet));
|
||||
if (existing != node.wallets.items.end ())
|
||||
{
|
||||
rai::transaction transaction (node.store.environment, nullptr, true);
|
||||
if (existing->second->store.valid_password (transaction))
|
||||
{
|
||||
for (auto & accounts : request.get_child ("accounts"))
|
||||
{
|
||||
std::string account_text = accounts.second.data ();
|
||||
rai::uint256_union account;
|
||||
auto error (account.decode_account (account_text));
|
||||
if (!error)
|
||||
{
|
||||
existing->second->insert_watch (transaction, account);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "Bad account number");
|
||||
}
|
||||
}
|
||||
boost::property_tree::ptree response_l;
|
||||
response_l.put ("success", "");
|
||||
response (response_l);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "Wallet locked");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "Wallet not found");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "Bad wallet number");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "RPC control is disabled");
|
||||
}
|
||||
}
|
||||
|
||||
void rai::rpc_handler::wallet_balance_total ()
|
||||
{
|
||||
std::string wallet_text (request.get<std::string> ("wallet"));
|
||||
|
@ -3636,6 +3679,79 @@ void rai::rpc_handler::wallet_key_valid ()
|
|||
}
|
||||
}
|
||||
|
||||
void rai::rpc_handler::wallet_ledger ()
|
||||
{
|
||||
const bool representative = request.get<bool> ("representative", false);
|
||||
const bool weight = request.get<bool> ("weight", false);
|
||||
const bool pending = request.get<bool> ("pending", false);
|
||||
uint64_t modified_since (0);
|
||||
boost::optional<std::string> modified_since_text (request.get_optional<std::string> ("modified_since"));
|
||||
if (modified_since_text.is_initialized ())
|
||||
{
|
||||
modified_since = strtoul (modified_since_text.get ().c_str (), NULL, 10);
|
||||
}
|
||||
std::string wallet_text (request.get<std::string> ("wallet"));
|
||||
rai::uint256_union wallet;
|
||||
auto error (wallet.decode_hex (wallet_text));
|
||||
if (!error)
|
||||
{
|
||||
auto existing (node.wallets.items.find (wallet));
|
||||
if (existing != node.wallets.items.end ())
|
||||
{
|
||||
boost::property_tree::ptree response_l;
|
||||
boost::property_tree::ptree accounts;
|
||||
rai::transaction transaction (node.store.environment, nullptr, false);
|
||||
for (auto i (existing->second->store.begin (transaction)), n (existing->second->store.end ()); i != n; ++i)
|
||||
{
|
||||
rai::account account (i->first.uint256 ());
|
||||
rai::account_info info;
|
||||
if (!node.store.account_get (transaction, account, info))
|
||||
{
|
||||
if (info.modified >= modified_since)
|
||||
{
|
||||
boost::property_tree::ptree entry;
|
||||
entry.put ("frontier", info.head.to_string ());
|
||||
entry.put ("open_block", info.open_block.to_string ());
|
||||
entry.put ("representative_block", info.rep_block.to_string ());
|
||||
std::string balance;
|
||||
rai::uint128_union (info.balance).encode_dec (balance);
|
||||
entry.put ("balance", balance);
|
||||
entry.put ("modified_timestamp", std::to_string (info.modified));
|
||||
entry.put ("block_count", std::to_string (info.block_count));
|
||||
if (representative)
|
||||
{
|
||||
auto block (node.store.block_get (transaction, info.rep_block));
|
||||
assert (block != nullptr);
|
||||
entry.put ("representative", block->representative ().to_account ());
|
||||
}
|
||||
if (weight)
|
||||
{
|
||||
auto account_weight (node.ledger.weight (transaction, account));
|
||||
entry.put ("weight", account_weight.convert_to<std::string> ());
|
||||
}
|
||||
if (pending)
|
||||
{
|
||||
auto account_pending (node.ledger.account_pending (transaction, account));
|
||||
entry.put ("pending", account_pending.convert_to<std::string> ());
|
||||
}
|
||||
accounts.push_back (std::make_pair (account.to_account (), entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
response_l.add_child ("accounts", accounts);
|
||||
response (response_l);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "Wallet not found");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response, "Bad wallet number");
|
||||
}
|
||||
}
|
||||
|
||||
void rai::rpc_handler::wallet_lock ()
|
||||
{
|
||||
if (rpc.config.enable_control)
|
||||
|
@ -3683,7 +3799,6 @@ void rai::rpc_handler::wallet_pending ()
|
|||
{
|
||||
uint64_t count (std::numeric_limits<uint64_t>::max ());
|
||||
rai::uint128_union threshold (0);
|
||||
bool source (false);
|
||||
boost::optional<std::string> count_text (request.get_optional<std::string> ("count"));
|
||||
if (count_text.is_initialized ())
|
||||
{
|
||||
|
@ -3702,11 +3817,7 @@ void rai::rpc_handler::wallet_pending ()
|
|||
error_response (response, "Bad threshold number");
|
||||
}
|
||||
}
|
||||
boost::optional<bool> source_optional (request.get_optional<bool> ("source"));
|
||||
if (source_optional.is_initialized ())
|
||||
{
|
||||
source = source_optional.get ();
|
||||
}
|
||||
const bool source = request.get<bool> ("source", false);
|
||||
boost::property_tree::ptree response_l;
|
||||
boost::property_tree::ptree pending;
|
||||
rai::transaction transaction (node.store.environment, nullptr, false);
|
||||
|
@ -4453,7 +4564,8 @@ void rai::rpc_handler::process_request ()
|
|||
}
|
||||
else if (action == "history")
|
||||
{
|
||||
history ();
|
||||
request.put ("head", request.get<std::string> ("hash"));
|
||||
account_history ();
|
||||
}
|
||||
else if (action == "keepalive")
|
||||
{
|
||||
|
@ -4603,6 +4715,10 @@ void rai::rpc_handler::process_request ()
|
|||
{
|
||||
wallet_add ();
|
||||
}
|
||||
else if (action == "wallet_add_watch")
|
||||
{
|
||||
wallet_add_watch ();
|
||||
}
|
||||
else if (action == "wallet_balance_total")
|
||||
{
|
||||
wallet_balance_total ();
|
||||
|
@ -4639,6 +4755,10 @@ void rai::rpc_handler::process_request ()
|
|||
{
|
||||
wallet_key_valid ();
|
||||
}
|
||||
else if (action == "wallet_ledger")
|
||||
{
|
||||
wallet_ledger ();
|
||||
}
|
||||
else if (action == "wallet_lock")
|
||||
{
|
||||
wallet_lock ();
|
||||
|
|
|
@ -185,6 +185,7 @@ public:
|
|||
void validate_account_number ();
|
||||
void version ();
|
||||
void wallet_add ();
|
||||
void wallet_add_watch ();
|
||||
void wallet_balance_total ();
|
||||
void wallet_balances ();
|
||||
void wallet_change_seed ();
|
||||
|
@ -194,6 +195,7 @@ public:
|
|||
void wallet_export ();
|
||||
void wallet_frontiers ();
|
||||
void wallet_key_valid ();
|
||||
void wallet_ledger ();
|
||||
void wallet_lock ();
|
||||
void wallet_pending ();
|
||||
void wallet_representative ();
|
||||
|
|
|
@ -410,13 +410,13 @@ void rai::landing::write_store ()
|
|||
|
||||
rai::uint128_t rai::landing::distribution_amount (uint64_t interval)
|
||||
{
|
||||
// Halfing period ~= Exponent of 2 in secounds approixmately 1 year = 2^25 = 33554432
|
||||
// Halving period ~= Exponent of 2 in seconds approximately 1 year = 2^25 = 33554432
|
||||
// Interval = Exponent of 2 in seconds approximately 1 minute = 2^10 = 64
|
||||
uint64_t intervals_per_period (1 << (25 - interval_exponent));
|
||||
rai::uint128_t result;
|
||||
if (interval < intervals_per_period * 1)
|
||||
{
|
||||
// Total supply / 2^halfing period / intervals per period
|
||||
// Total supply / 2^halving period / intervals per period
|
||||
// 2^128 / 2^1 / (2^25 / 2^10)
|
||||
result = rai::uint128_t (1) << (127 - (25 - interval_exponent)); // 50%
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ using vectorstream = boost::iostreams::stream_buffer<boost::iostreams::back_inse
|
|||
boost::filesystem::path working_path ();
|
||||
// Get a unique path within the home directory, used for testing
|
||||
boost::filesystem::path unique_path ();
|
||||
// C++ stream are absolutely horrible so I need this helper function to do the most basic operation of creating a file if it doesn't exist or truntacing it.
|
||||
// C++ stream are absolutely horrible so I need this helper function to do the most basic operation of creating a file if it doesn't exist or truncating it.
|
||||
void open_or_create (std::fstream &, std::string const &);
|
||||
// Reads a json object from the stream and if was changed, write the object back to the stream
|
||||
template <typename T>
|
||||
|
|
|
@ -252,7 +252,7 @@ unsigned const rai::wallet_store::version_3 (3);
|
|||
unsigned const rai::wallet_store::version_current (version_3);
|
||||
// Wallet version number
|
||||
rai::uint256_union const rai::wallet_store::version_special (0);
|
||||
// Random number used to salt private key encription
|
||||
// Random number used to salt private key encryption
|
||||
rai::uint256_union const rai::wallet_store::salt_special (1);
|
||||
// Key used to encrypt wallet keys, encrypted itself by the user password
|
||||
rai::uint256_union const rai::wallet_store::wallet_key_special (2);
|
||||
|
@ -420,6 +420,11 @@ rai::public_key rai::wallet_store::insert_adhoc (MDB_txn * transaction_a, rai::r
|
|||
return pub;
|
||||
}
|
||||
|
||||
void rai::wallet_store::insert_watch (MDB_txn * transaction_a, rai::public_key const & pub)
|
||||
{
|
||||
entry_put_raw (transaction_a, pub, rai::wallet_value (rai::uint256_union (0), 0));
|
||||
}
|
||||
|
||||
void rai::wallet_store::erase (MDB_txn * transaction_a, rai::public_key const & pub)
|
||||
{
|
||||
auto status (mdb_del (transaction_a, handle, rai::mdb_val (pub), nullptr));
|
||||
|
@ -790,6 +795,11 @@ rai::public_key rai::wallet::insert_adhoc (rai::raw_key const & account_a, bool
|
|||
return result;
|
||||
}
|
||||
|
||||
void rai::wallet::insert_watch (MDB_txn * transaction_a, rai::public_key const & pub_a)
|
||||
{
|
||||
store.insert_watch (transaction_a, pub_a);
|
||||
}
|
||||
|
||||
bool rai::wallet::exists (rai::public_key const & account_a)
|
||||
{
|
||||
rai::transaction transaction (store.environment, nullptr, false);
|
||||
|
@ -1159,7 +1169,11 @@ public:
|
|||
{
|
||||
for (auto i (wallet_a->store.begin (transaction_a)), n (wallet_a->store.end ()); i != n; ++i)
|
||||
{
|
||||
keys.insert (i->first.uint256 ());
|
||||
// Don't search pending for watch-only accounts
|
||||
if (!rai::wallet_value (i->second).key.is_zero ())
|
||||
{
|
||||
keys.insert (i->first.uint256 ());
|
||||
}
|
||||
}
|
||||
}
|
||||
void run ()
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
rai::account representative (MDB_txn *);
|
||||
void representative_set (MDB_txn *, rai::account const &);
|
||||
rai::public_key insert_adhoc (MDB_txn *, rai::raw_key const &);
|
||||
void insert_watch (MDB_txn *, rai::public_key const &);
|
||||
void erase (MDB_txn *, rai::public_key const &);
|
||||
rai::wallet_value entry_get_raw (MDB_txn *, rai::public_key const &);
|
||||
void entry_put_raw (MDB_txn *, rai::public_key const &, rai::wallet_value const &);
|
||||
|
@ -132,6 +133,7 @@ public:
|
|||
bool enter_password (std::string const &);
|
||||
rai::public_key insert_adhoc (rai::raw_key const &, bool = true);
|
||||
rai::public_key insert_adhoc (MDB_txn *, rai::raw_key const &, bool = true);
|
||||
void insert_watch (MDB_txn *, rai::public_key const &);
|
||||
rai::public_key deterministic_insert (MDB_txn *, bool = true);
|
||||
rai::public_key deterministic_insert (bool = true);
|
||||
bool exists (rai::public_key const &);
|
||||
|
|
|
@ -1394,7 +1394,7 @@ wallet (wallet_a)
|
|||
auto block (this->wallet.wallet_m->change_sync (this->wallet.account, representative_l));
|
||||
change_rep->setEnabled (true);
|
||||
show_button_success (*change_rep);
|
||||
change_rep->setText ("Represenative was changed");
|
||||
change_rep->setText ("Representative was changed");
|
||||
current_representative->setText (QString (representative_l.to_account_split ().c_str ()));
|
||||
new_representative->clear ();
|
||||
this->wallet.node.alarm.add (std::chrono::steady_clock::now () + std::chrono::seconds (5), [this]() {
|
||||
|
|
|
@ -124,7 +124,7 @@ void rai_daemon::daemon::run (boost::filesystem::path const & data_path)
|
|||
{
|
||||
rpc->start ();
|
||||
}
|
||||
runner.reset (new rai::thread_runner (service, node->config.io_threads));
|
||||
runner = std::make_unique<rai::thread_runner> (service, node->config.io_threads);
|
||||
runner->join ();
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue