Compare commits

..

12 commits

Author SHA1 Message Date
Davor Hirunda
61d491d59e Revert "Merge branch 'develop' into feature/libbitcoin-son"
This reverts commit 1a16027523
2022-09-23 23:20:54 +00:00
Davor Hirunda
8fbe62b4cf Merge branch 'revert-f7aab6a8' into 'feature/libbitcoin-son'
Revert "Back importmulti for bitcoind"

See merge request PBSA/peerplays!155
2022-09-23 23:19:31 +00:00
Davor Hirunda
68e944f89a Revert "Back importmulti for bitcoind" 2022-09-23 23:19:31 +00:00
hirunda
f7aab6a8b8 Back importmulti for bitcoind 2022-09-23 01:16:51 +02:00
hirunda
1a16027523 Merge branch 'develop' into feature/libbitcoin-son 2022-09-22 22:49:55 +02:00
hirunda
7b2a3fab97 Libbitcoin client 2022-09-22 21:21:08 +02:00
hirunda
9b047ae703 Resolving bug with vout wrong sequence 2022-09-22 01:21:15 +02:00
hirunda
6b67fe76a8 libbitcoin client and bitcoind 2022-09-20 01:06:33 +02:00
hirunda
6aee0c6f82 Moving json transaction parsing
Moving json transaction parsing in

getrawtransaction and forming btc_tx object
2022-09-09 00:07:53 +02:00
hirunda
a47498f642 libbitcoin client work in progress 2022-09-06 14:12:01 +02:00
serkixenos
789c0547cf Merge branch 'feature/417/Add_support_in_bitcoin_for_P2SH-P2WSH_address_format' into 'feature/libbitcoin-son'
Add support for P2SH-P2WSH address format

See merge request PBSA/peerplays!140
2022-09-05 13:27:27 +00:00
Davor Hirunda
3e0a21bde7 Add support for P2SH-P2WSH address format 2022-09-05 13:27:26 +00:00
128 changed files with 2844 additions and 8800 deletions

View file

@ -9,8 +9,6 @@ stages:
- build
- test
- dockerize
- python-test
- deploy
build-mainnet:
stage: build
@ -50,7 +48,6 @@ dockerize-mainnet:
IMAGE: $CI_REGISTRY_IMAGE/mainnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
before_script:
- docker info
- docker builder prune -a -f
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script:
- docker build --no-cache -t $IMAGE .
@ -59,6 +56,8 @@ dockerize-mainnet:
- docker rmi $IMAGE
tags:
- builder
when:
manual
timeout:
3h
@ -79,27 +78,12 @@ build-testnet:
- build/libraries/
- build/programs/
- build/tests/
when: manual
tags:
- builder
deploy-testnet:
stage: deploy
dependencies:
- build-testnet
script:
- sudo systemctl stop witness
- rm $WORK_DIR/peerplays/witness_node || true
- cp build/programs/witness_node/witness_node $WORK_DIR/peerplays/
- sudo systemctl restart witness
rules:
- if: $CI_COMMIT_BRANCH == "master"
when: always
environment:
name: devnet
url: $DEVNET_URL
tags:
- devnet
when:
manual
timeout:
3h
test-testnet:
stage: test
@ -135,37 +119,3 @@ dockerize-testnet:
manual
timeout:
3h
test-e2e:
stage: python-test
variables:
IMAGE: $CI_REGISTRY_IMAGE/mainnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
before_script:
- docker info
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script:
- git clone https://gitlab.com/PBSA/tools-libs/peerplays-utils.git
- cd peerplays-utils/peerplays-qa-environment
- git checkout origin/feature/python-e2e-tests-for-CI
- cd e2e-tests/
- python3 -m venv venv
- source venv/bin/activate
- pip3 install -r requirements.txt
- docker-compose down --remove-orphans
- docker ps -a
- docker pull $IMAGE
- docker tag $IMAGE peerplays-base:latest
- docker image ls -a
- docker-compose build
- python3 main.py --start all
- docker ps -a
- python3 -m pytest test_btc_init_state.py test_hive_inital_state.py test_pp_inital_state.py
- python3 main.py --stop
- deactivate
- docker ps -a
after_script:
- docker rmi $(docker images -a | grep -v 'hive-for-peerplays\|ethereum-for-peerplays\|bitcoin-for-peerplays\|ubuntu-for-peerplays' | awk '{print $3}')
tags:
- python-tests
when:
manual

View file

@ -1,4 +1,5 @@
FROM ubuntu:20.04
MAINTAINER Peerplays Blockchain Standards Association
#===============================================================================
# Ubuntu setup
@ -10,14 +11,15 @@ RUN \
apt-utils \
autoconf \
bash \
bison \
build-essential \
ca-certificates \
cmake \
dnsutils \
doxygen \
expect \
flex \
git \
graphviz \
libboost-all-dev \
libbz2-dev \
libcurl4-openssl-dev \
libncurses-dev \
@ -33,6 +35,7 @@ RUN \
ntp \
openssh-server \
pkg-config \
perl \
python3 \
python3-jinja2 \
sudo \
@ -50,120 +53,35 @@ RUN echo 'peerplays:peerplays' | chpasswd
# SSH
EXPOSE 22
WORKDIR /home/peerplays/src
#===============================================================================
# Boost setup
#===============================================================================
RUN \
wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \
tar -xzf boost_1_72_0.tar.gz && \
cd boost_1_72_0 && \
./bootstrap.sh && \
./b2 install && \
ldconfig && \
rm -rf /home/peerplays/src/*
#===============================================================================
# cmake setup
#===============================================================================
RUN \
wget https://github.com/Kitware/CMake/releases/download/v3.24.2/cmake-3.24.2-linux-x86_64.sh && \
chmod 755 ./cmake-3.24.2-linux-x86_64.sh && \
./cmake-3.24.2-linux-x86_64.sh --prefix=/usr --skip-license && \
cmake --version && \
rm -rf /home/peerplays/src/*
#===============================================================================
# libzmq setup
#===============================================================================
WORKDIR /home/peerplays/
RUN \
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.tar.gz && \
tar -xzvf v4.3.4.tar.gz && \
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip && \
unzip v4.3.4.zip && \
cd libzmq-4.3.4 && \
mkdir build && \
cd build && \
cmake .. && \
make -j$(nproc) && \
make install && \
ldconfig && \
rm -rf /home/peerplays/src/*
#===============================================================================
# cppzmq setup
#===============================================================================
RUN \
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.9.0.tar.gz && \
tar -xzvf v4.9.0.tar.gz && \
cd cppzmq-4.9.0 && \
mkdir build && \
cd build && \
cmake .. && \
make -j$(nproc) && \
make install && \
ldconfig && \
rm -rf /home/peerplays/src/*
#===============================================================================
# gsl setup
#===============================================================================
RUN \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
libpcre3-dev
RUN \
wget https://github.com/imatix/gsl/archive/refs/tags/v4.1.4.tar.gz && \
tar -xzvf v4.1.4.tar.gz && \
cd gsl-4.1.4 && \
make -j$(nproc) && \
make install && \
rm -rf /home/peerplays/src/*
#===============================================================================
# libbitcoin-build setup
# libbitcoin-explorer setup
#===============================================================================
RUN \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
libsodium-dev
RUN \
git clone --branch version3.8.0 --depth 1 https://gitlab.com/PBSA/peerplays-1.0/libbitcoin-explorer.git && \
cd libbitcoin-explorer && \
./install.sh && \
ldconfig && \
rm -rf /home/peerplays/src/*
#===============================================================================
# Doxygen setup
#===============================================================================
RUN \
sudo apt install -y bison flex && \
wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \
tar -xvf Release_1_8_17.tar.gz && \
cd doxygen-Release_1_8_17 && \
mkdir build && \
cd build && \
cmake .. && \
make -j$(nproc) install && \
ldconfig
#===============================================================================
# Perl setup
# cppzmq setup
#===============================================================================
WORKDIR /home/peerplays/
RUN \
wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \
tar -xvf v5.30.0.tar.gz && \
cd perl5-5.30.0 && \
./Configure -des && \
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip && \
unzip v4.8.1.zip && \
cd cppzmq-4.8.1 && \
mkdir build && \
cd build && \
cmake .. && \
make -j$(nproc) install && \
ldconfig
@ -171,6 +89,8 @@ RUN \
# Peerplays setup
#===============================================================================
WORKDIR /home/peerplays/
## Clone Peerplays
#RUN \
# git clone https://gitlab.com/PBSA/peerplays.git && \
@ -186,8 +106,6 @@ ADD . peerplays
# Configure Peerplays
RUN \
cd peerplays && \
git submodule update --init --recursive && \
git log --oneline -n 5 && \
mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release ..
@ -201,8 +119,8 @@ WORKDIR /home/peerplays/peerplays-network
# Setup Peerplays runimage
RUN \
ln -s /home/peerplays/src/peerplays/build/programs/cli_wallet/cli_wallet ./ && \
ln -s /home/peerplays/src/peerplays/build/programs/witness_node/witness_node ./
ln -s /home/peerplays/peerplays/build/programs/cli_wallet/cli_wallet ./ && \
ln -s /home/peerplays/peerplays/build/programs/witness_node/witness_node ./
RUN ./witness_node --create-genesis-json genesis.json && \
rm genesis.json

View file

@ -1,4 +1,5 @@
FROM ubuntu:18.04
MAINTAINER Peerplays Blockchain Standards Association
#===============================================================================
# Ubuntu setup
@ -10,12 +11,11 @@ RUN \
apt-utils \
autoconf \
bash \
bison \
build-essential \
ca-certificates \
dnsutils \
doxygen \
expect \
flex \
git \
graphviz \
libbz2-dev \
@ -33,6 +33,7 @@ RUN \
ntp \
openssh-server \
pkg-config \
perl \
python3 \
python3-jinja2 \
sudo \
@ -50,120 +51,60 @@ RUN echo 'peerplays:peerplays' | chpasswd
# SSH
EXPOSE 22
WORKDIR /home/peerplays/src
#===============================================================================
# Boost setup
#===============================================================================
WORKDIR /home/peerplays/
RUN \
wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \
tar -xzf boost_1_72_0.tar.gz && \
cd boost_1_72_0 && \
wget -c 'https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.bz2' -O boost_1_71_0.tar.bz2 && \
tar xjf boost_1_71_0.tar.bz2 && \
cd boost_1_71_0/ && \
./bootstrap.sh && \
./b2 install && \
ldconfig && \
rm -rf /home/peerplays/src/*
./b2 install
#===============================================================================
# cmake setup
#===============================================================================
WORKDIR /home/peerplays/
RUN \
wget https://github.com/Kitware/CMake/releases/download/v3.24.2/cmake-3.24.2-linux-x86_64.sh && \
chmod 755 ./cmake-3.24.2-linux-x86_64.sh && \
./cmake-3.24.2-linux-x86_64.sh --prefix=/usr --skip-license && \
cmake --version && \
rm -rf /home/peerplays/src/*
wget -c 'https://cmake.org/files/v3.23/cmake-3.23.1-linux-x86_64.sh' -O cmake-3.23.1-linux-x86_64.sh && \
chmod 755 ./cmake-3.23.1-linux-x86_64.sh && \
./cmake-3.23.1-linux-x86_64.sh --prefix=/usr/ --skip-license && \
cmake --version
#===============================================================================
# libzmq setup
#===============================================================================
WORKDIR /home/peerplays/
RUN \
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.tar.gz && \
tar -xzvf v4.3.4.tar.gz && \
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip && \
unzip v4.3.4.zip && \
cd libzmq-4.3.4 && \
mkdir build && \
cd build && \
cmake .. && \
make -j$(nproc) && \
make install && \
ldconfig && \
rm -rf /home/peerplays/src/*
#===============================================================================
# cppzmq setup
#===============================================================================
RUN \
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.9.0.tar.gz && \
tar -xzvf v4.9.0.tar.gz && \
cd cppzmq-4.9.0 && \
mkdir build && \
cd build && \
cmake .. && \
make -j$(nproc) && \
make install && \
ldconfig && \
rm -rf /home/peerplays/src/*
#===============================================================================
# gsl setup
#===============================================================================
RUN \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
libpcre3-dev
RUN \
wget https://github.com/imatix/gsl/archive/refs/tags/v4.1.4.tar.gz && \
tar -xzvf v4.1.4.tar.gz && \
cd gsl-4.1.4 && \
make -j$(nproc) && \
make install && \
rm -rf /home/peerplays/src/*
#===============================================================================
# libbitcoin-build setup
# libbitcoin-explorer setup
#===============================================================================
RUN \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
libsodium-dev
RUN \
git clone --branch version3.8.0 --depth 1 https://gitlab.com/PBSA/peerplays-1.0/libbitcoin-explorer.git && \
cd libbitcoin-explorer && \
./install.sh && \
ldconfig && \
rm -rf /home/peerplays/src/*
#===============================================================================
# Doxygen setup
#===============================================================================
RUN \
sudo apt install -y bison flex && \
wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \
tar -xvf Release_1_8_17.tar.gz && \
cd doxygen-Release_1_8_17 && \
mkdir build && \
cd build && \
cmake .. && \
make -j$(nproc) install && \
ldconfig
#===============================================================================
# Perl setup
# cppzmq setup
#===============================================================================
WORKDIR /home/peerplays/
RUN \
wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \
tar -xvf v5.30.0.tar.gz && \
cd perl5-5.30.0 && \
./Configure -des && \
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip && \
unzip v4.8.1.zip && \
cd cppzmq-4.8.1 && \
mkdir build && \
cd build && \
cmake .. && \
make -j$(nproc) install && \
ldconfig
@ -171,6 +112,8 @@ RUN \
# Peerplays setup
#===============================================================================
WORKDIR /home/peerplays/
## Clone Peerplays
#RUN \
# git clone https://gitlab.com/PBSA/peerplays.git && \
@ -186,9 +129,6 @@ ADD . peerplays
# Configure Peerplays
RUN \
cd peerplays && \
git submodule update --init --recursive && \
git symbolic-ref --short HEAD && \
git log --oneline -n 5 && \
mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release ..
@ -202,8 +142,8 @@ WORKDIR /home/peerplays/peerplays-network
# Setup Peerplays runimage
RUN \
ln -s /home/peerplays/src/peerplays/build/programs/cli_wallet/cli_wallet ./ && \
ln -s /home/peerplays/src/peerplays/build/programs/witness_node/witness_node ./
ln -s /home/peerplays/peerplays/build/programs/cli_wallet/cli_wallet ./ && \
ln -s /home/peerplays/peerplays/build/programs/witness_node/witness_node ./
RUN ./witness_node --create-genesis-json genesis.json && \
rm genesis.json

166
README.md
View file

@ -8,41 +8,23 @@ This is a quick introduction to get new developers and witnesses up to speed on
Officially supported OS are Ubuntu 20.04 and Ubuntu 18.04.
## Ubuntu 20.04 and 18.04
## Ubuntu 20.04
Following dependencies are needed for a clean install of Ubuntu 20.04 and Ubuntu 18.04:
Following dependencies are needed for a clean install of Ubuntu 20.04:
```
sudo apt-get install \
autoconf bash bison build-essential ca-certificates dnsutils expect flex git \
graphviz libbz2-dev libcurl4-openssl-dev libncurses-dev libpcre3-dev \
libsnappy-dev libsodium-dev libssl-dev libtool libzip-dev locales lsb-release \
mc nano net-tools ntp openssh-server pkg-config python3 python3-jinja2 sudo \
apt-utils autoconf bash build-essential ca-certificates clang-format cmake \
dnsutils doxygen expect git graphviz libboost-all-dev libbz2-dev \
libcurl4-openssl-dev libncurses-dev libsnappy-dev \
libssl-dev libtool libzip-dev locales lsb-release mc nano net-tools ntp \
openssh-server pkg-config perl python3 python3-jinja2 sudo \
systemd-coredump wget
```
Boost libraries setup:
Install libzmq from source:
```
wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz
tar -xzf boost_1_72_0.tar.gz boost_1_72_0
cd boost_1_72_0
./bootstrap.sh
./b2
sudo ./b2 install
sudo ldconfig
```
cmake setup:
```
wget https://github.com/Kitware/CMake/releases/download/v3.24.2/cmake-3.24.2-linux-x86_64.sh
chmod 755 ./cmake-3.24.2-linux-x86_64.sh
sudo ./cmake-3.24.2-linux-x86_64.sh --prefix=/usr --skip-license
cmake --version
```
libzmq setup:
```
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.tar.gz
tar -xzvf v4.3.4.tar.gz
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip
unzip v4.3.4.zip
cd libzmq-4.3.4
mkdir build
cd build
@ -52,11 +34,11 @@ sudo make install
sudo ldconfig
```
cppzmq setup:
Install cppzmq from source:
```
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.9.0.tar.gz
tar -xzvf v4.9.0.tar.gz
cd cppzmq-4.9.0
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip
unzip v4.8.1.zip
cd cppzmq-4.8.1
mkdir build
cd build
cmake ..
@ -65,48 +47,6 @@ sudo make install
sudo ldconfig
```
gsl setup:
```
wget https://github.com/imatix/gsl/archive/refs/tags/v4.1.4.tar.gz
tar -xzvf v4.1.4.tar.gz
cd gsl-4.1.4
make -j$(nproc)
sudo make install
sudo ldconfig
```
libbitcoin-explorer setup:
```
git clone --branch version3.8.0 --depth 1 https://gitlab.com/PBSA/peerplays-1.0/libbitcoin-explorer.git
cd libbitcoin-explorer
sudo ./install.sh
sudo ldconfig
```
Doxygen setup:
```
wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz
tar -xvf Release_1_8_17.tar.gz
cd doxygen-Release_1_8_17
mkdir build
cd build
cmake ..
make -j$(nproc)
sudo make install
sudo ldconfig
```
Perl setup:
```
wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz
tar -xvf v5.30.0.tar.gz
cd perl5-5.30.0
./Configure -des
make -j$(nproc)
sudo make install
sudo ldconfig
```
Building Peerplays
```
git clone https://gitlab.com/PBSA/peerplays.git
@ -129,6 +69,84 @@ make -j$(nproc)
sudo make install # this can install the executable files under /usr/local
```
## Ubuntu 18.04
Following dependencies are needed for a clean install of Ubuntu 18.04:
```
sudo apt-get install \
apt-utils autoconf bash build-essential ca-certificates clang-format \
dnsutils doxygen expect git graphviz libbz2-dev \
libcurl4-openssl-dev libncurses-dev libsnappy-dev \
libssl-dev libtool libzip-dev locales lsb-release mc nano net-tools ntp \
openssh-server pkg-config perl python3 python3-jinja2 sudo \
systemd-coredump wget
```
Install Boost libraries from source
```
wget -c 'https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.bz2' -O boost_1_71_0.tar.bz2
tar xjf boost_1_71_0.tar.bz2
cd boost_1_71_0/
./bootstrap.sh
sudo ./b2 install
```
Install cmake
```
wget -c 'https://cmake.org/files/v3.23/cmake-3.23.1-linux-x86_64.sh' -O cmake-3.23.1-linux-x86_64.sh
chmod 755 ./cmake-3.23.1-linux-x86_64.sh
sudo ./cmake-3.23.1-linux-x86_64.sh --prefix=/usr/ --skip-license
```
Install libzmq from source:
```
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip
unzip v4.3.4.zip
cd libzmq-4.3.4
mkdir build
cd build
cmake ..
make -j$(nproc)
sudo make install
sudo ldconfig
```
Install cppzmq from source:
```
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip
unzip v4.8.1.zip
cd cppzmq-4.8.1
mkdir build
cd build
cmake ..
make -j$(nproc)
sudo make install
sudo ldconfig
```
Building Peerplays
```
git clone https://gitlab.com/PBSA/peerplays.git
cd peerplays
git submodule update --init --recursive
# If you want to build Mainnet node
cmake -DCMAKE_BUILD_TYPE=Release
# If you want to build Testnet node
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_PEERPLAYS_TESTNET=1
# Update -j flag depending on your current system specs;
# Recommended 4GB of RAM per 1 CPU core
# make -j2 for 8GB RAM
# make -j4 for 16GB RAM
# make -j8 for 32GB RAM
make -j$(nproc)
sudo make install # this can install the executable files under /usr/local
```
## Docker images
Install docker, and add current user to docker group.

View file

@ -5,7 +5,6 @@ add_subdirectory( egenesis )
add_subdirectory( fc )
add_subdirectory( net )
add_subdirectory( plugins )
add_subdirectory( sha3 )
add_subdirectory( time )
add_subdirectory( utilities )
add_subdirectory( wallet )

View file

@ -210,8 +210,8 @@ network_node_api::network_node_api(application &a) :
}
/*
* Remove expired transactions from pending_transactions
*/
* Remove expired transactions from pending_transactions
*/
for (const auto &transaction : _pending_transactions) {
if (transaction.second.expiration < block.timestamp) {
auto transaction_it = _pending_transactions.find(transaction.second.id());

View file

@ -391,8 +391,8 @@ public:
}
/**
* If delegate has the item, the network has no need to fetch it.
*/
* If delegate has the item, the network has no need to fetch it.
*/
virtual bool has_item(const net::item_id &id) override {
try {
if (id.item_type == graphene::net::block_message_type)
@ -404,13 +404,13 @@ public:
}
/**
* @brief allows the application to validate an item prior to broadcasting to peers.
*
* @param sync_mode true if the message was fetched through the sync process, false during normal operation
* @returns true if this message caused the blockchain to switch forks, false if it did not
*
* @throws exception if error validating the item, otherwise the item is safe to broadcast on.
*/
* @brief allows the application to validate an item prior to broadcasting to peers.
*
* @param sync_mode true if the message was fetched through the sync process, false during normal operation
* @returns true if this message caused the blockchain to switch forks, false if it did not
*
* @throws exception if error validating the item, otherwise the item is safe to broadcast on.
*/
virtual bool handle_block(const graphene::net::block_message &blk_msg, bool sync_mode,
std::vector<fc::uint160_t> &contained_transaction_message_ids) override {
@ -498,14 +498,14 @@ public:
}
/**
* Assuming all data elements are ordered in some way, this method should
* return up to limit ids that occur *after* the last ID in synopsis that
* we recognize.
*
* On return, remaining_item_count will be set to the number of items
* in our blockchain after the last item returned in the result,
* or 0 if the result contains the last item in the blockchain
*/
* Assuming all data elements are ordered in some way, this method should
* return up to limit ids that occur *after* the last ID in synopsis that
* we recognize.
*
* On return, remaining_item_count will be set to the number of items
* in our blockchain after the last item returned in the result,
* or 0 if the result contains the last item in the blockchain
*/
virtual std::vector<item_hash_t> get_block_ids(const std::vector<item_hash_t> &blockchain_synopsis,
uint32_t &remaining_item_count,
uint32_t limit) override {
@ -552,8 +552,8 @@ public:
}
/**
* Given the hash of the requested data, fetch the body.
*/
* Given the hash of the requested data, fetch the body.
*/
virtual message get_item(const item_id &id) override {
try {
// ilog("Request for item ${id}", ("id", id));
@ -576,63 +576,63 @@ public:
}
/**
* Returns a synopsis of the blockchain used for syncing. This consists of a list of
* block hashes at intervals exponentially increasing towards the genesis block.
* When syncing to a peer, the peer uses this data to determine if we're on the same
* fork as they are, and if not, what blocks they need to send us to get us on their
* fork.
*
* In the over-simplified case, this is a straighforward synopsis of our current
* preferred blockchain; when we first connect up to a peer, this is what we will be sending.
* It looks like this:
* If the blockchain is empty, it will return the empty list.
* If the blockchain has one block, it will return a list containing just that block.
* If it contains more than one block:
* the first element in the list will be the hash of the highest numbered block that
* we cannot undo
* the second element will be the hash of an item at the half way point in the undoable
* segment of the blockchain
* the third will be ~3/4 of the way through the undoable segment of the block chain
* the fourth will be at ~7/8...
* &c.
* the last item in the list will be the hash of the most recent block on our preferred chain
* so if the blockchain had 26 blocks labeled a - z, the synopsis would be:
* a n u x z
* the idea being that by sending a small (<30) number of block ids, we can summarize a huge
* blockchain. The block ids are more dense near the end of the chain where because we are
* more likely to be almost in sync when we first connect, and forks are likely to be short.
* If the peer we're syncing with in our example is on a fork that started at block 'v',
* then they will reply to our synopsis with a list of all blocks starting from block 'u',
* the last block they know that we had in common.
*
* In the real code, there are several complications.
*
* First, as an optimization, we don't usually send a synopsis of the entire blockchain, we
* send a synopsis of only the segment of the blockchain that we have undo data for. If their
* fork doesn't build off of something in our undo history, we would be unable to switch, so there's
* no reason to fetch the blocks.
*
* Second, when a peer replies to our initial synopsis and gives us a list of the blocks they think
* we are missing, they only send a chunk of a few thousand blocks at once. After we get those
* block ids, we need to request more blocks by sending another synopsis (we can't just say "send me
* the next 2000 ids" because they may have switched forks themselves and they don't track what
* they've sent us). For faster performance, we want to get a fairly long list of block ids first,
* then start downloading the blocks.
* The peer doesn't handle these follow-up block id requests any different from the initial request;
* it treats the synopsis we send as our blockchain and bases its response entirely off that. So to
* get the response we want (the next chunk of block ids following the last one they sent us, or,
* failing that, the shortest fork off of the last list of block ids they sent), we need to construct
* a synopsis as if our blockchain was made up of:
* 1. the blocks in our block chain up to the fork point (if there is a fork) or the head block (if no fork)
* 2. the blocks we've already pushed from their fork (if there's a fork)
* 3. the block ids they've previously sent us
* Segment 3 is handled in the p2p code, it just tells us the number of blocks it has (in
* number_of_blocks_after_reference_point) so we can leave space in the synopsis for them.
* We're responsible for constructing the synopsis of Segments 1 and 2 from our active blockchain and
* fork database. The reference_point parameter is the last block from that peer that has been
* successfully pushed to the blockchain, so that tells us whether the peer is on a fork or on
* the main chain.
*/
* Returns a synopsis of the blockchain used for syncing. This consists of a list of
* block hashes at intervals exponentially increasing towards the genesis block.
* When syncing to a peer, the peer uses this data to determine if we're on the same
* fork as they are, and if not, what blocks they need to send us to get us on their
* fork.
*
* In the over-simplified case, this is a straighforward synopsis of our current
* preferred blockchain; when we first connect up to a peer, this is what we will be sending.
* It looks like this:
* If the blockchain is empty, it will return the empty list.
* If the blockchain has one block, it will return a list containing just that block.
* If it contains more than one block:
* the first element in the list will be the hash of the highest numbered block that
* we cannot undo
* the second element will be the hash of an item at the half way point in the undoable
* segment of the blockchain
* the third will be ~3/4 of the way through the undoable segment of the block chain
* the fourth will be at ~7/8...
* &c.
* the last item in the list will be the hash of the most recent block on our preferred chain
* so if the blockchain had 26 blocks labeled a - z, the synopsis would be:
* a n u x z
* the idea being that by sending a small (<30) number of block ids, we can summarize a huge
* blockchain. The block ids are more dense near the end of the chain where because we are
* more likely to be almost in sync when we first connect, and forks are likely to be short.
* If the peer we're syncing with in our example is on a fork that started at block 'v',
* then they will reply to our synopsis with a list of all blocks starting from block 'u',
* the last block they know that we had in common.
*
* In the real code, there are several complications.
*
* First, as an optimization, we don't usually send a synopsis of the entire blockchain, we
* send a synopsis of only the segment of the blockchain that we have undo data for. If their
* fork doesn't build off of something in our undo history, we would be unable to switch, so there's
* no reason to fetch the blocks.
*
* Second, when a peer replies to our initial synopsis and gives us a list of the blocks they think
* we are missing, they only send a chunk of a few thousand blocks at once. After we get those
* block ids, we need to request more blocks by sending another synopsis (we can't just say "send me
* the next 2000 ids" because they may have switched forks themselves and they don't track what
* they've sent us). For faster performance, we want to get a fairly long list of block ids first,
* then start downloading the blocks.
* The peer doesn't handle these follow-up block id requests any different from the initial request;
* it treats the synopsis we send as our blockchain and bases its response entirely off that. So to
* get the response we want (the next chunk of block ids following the last one they sent us, or,
* failing that, the shortest fork off of the last list of block ids they sent), we need to construct
* a synopsis as if our blockchain was made up of:
* 1. the blocks in our block chain up to the fork point (if there is a fork) or the head block (if no fork)
* 2. the blocks we've already pushed from their fork (if there's a fork)
* 3. the block ids they've previously sent us
* Segment 3 is handled in the p2p code, it just tells us the number of blocks it has (in
* number_of_blocks_after_reference_point) so we can leave space in the synopsis for them.
* We're responsible for constructing the synopsis of Segments 1 and 2 from our active blockchain and
* fork database. The reference_point parameter is the last block from that peer that has been
* successfully pushed to the blockchain, so that tells us whether the peer is on a fork or on
* the main chain.
*/
virtual std::vector<item_hash_t> get_blockchain_synopsis(const item_hash_t &reference_point,
uint32_t number_of_blocks_after_reference_point) override {
try {
@ -733,26 +733,26 @@ public:
low_block_num += (true_high_block_num - low_block_num + 2) / 2;
} while (low_block_num <= high_block_num);
// idump((synopsis));
//idump((synopsis));
return synopsis;
}
FC_CAPTURE_AND_RETHROW()
}
/**
* Call this after the call to handle_message succeeds.
*
* @param item_type the type of the item we're synchronizing, will be the same as item passed to the sync_from() call
* @param item_count the number of items known to the node that haven't been sent to handle_item() yet.
* After `item_count` more calls to handle_item(), the node will be in sync
*/
* Call this after the call to handle_message succeeds.
*
* @param item_type the type of the item we're synchronizing, will be the same as item passed to the sync_from() call
* @param item_count the number of items known to the node that haven't been sent to handle_item() yet.
* After `item_count` more calls to handle_item(), the node will be in sync
*/
virtual void sync_status(uint32_t item_type, uint32_t item_count) override {
// any status reports to GUI go here
}
/**
* Call any time the number of connected peers changes.
*/
* Call any time the number of connected peers changes.
*/
virtual void connection_count_changed(uint32_t c) override {
// any status reports to GUI go here
}
@ -769,9 +769,9 @@ public:
}
/**
* Returns the time a block was produced (if block_id = 0, returns genesis time).
* If we don't know about the block, returns time_point_sec::min()
*/
* Returns the time a block was produced (if block_id = 0, returns genesis time).
* If we don't know about the block, returns time_point_sec::min()
*/
virtual fc::time_point_sec get_block_time(const item_hash_t &block_id) override {
try {
auto opt_block = _chain_db->fetch_block_by_id(block_id);
@ -917,8 +917,7 @@ void application::initialize(const fc::path &data_dir, const boost::program_opti
wanted.insert("accounts_list");
wanted.insert("affiliate_stats");
}
if (!wanted.count("delayed_node") && !wanted.count("debug_witness") && !wanted.count("witness")) // explicitly requested delayed_node or debug_witness functionality suppresses witness functions
wanted.insert("witness");
wanted.insert("witness");
wanted.insert("bookie");
int es_ah_conflict_counter = 0;
@ -950,7 +949,7 @@ void application::startup() {
}
std::shared_ptr<abstract_plugin> application::get_plugin(const string &name) const {
return is_plugin_enabled(name) ? my->_active_plugins[name] : nullptr;
return my->_active_plugins[name];
}
bool application::is_plugin_enabled(const string &name) const {

View file

@ -71,17 +71,6 @@ std::string object_id_to_string(object_id_type id) {
return object_id;
}
signed_block_with_info::signed_block_with_info(){};
signed_block_with_info::signed_block_with_info(const signed_block &block) :
signed_block(block) {
block_id = id();
signing_key = signee();
transaction_ids.reserve(transactions.size());
for (const processed_transaction &tx : transactions)
transaction_ids.push_back(tx.id());
}
class database_api_impl : public std::enable_shared_from_this<database_api_impl> {
public:
database_api_impl(graphene::chain::database &db);
@ -100,7 +89,6 @@ public:
optional<block_header> get_block_header(uint32_t block_num) const;
map<uint32_t, optional<block_header>> get_block_header_batch(const vector<uint32_t> block_nums) const;
optional<signed_block> get_block(uint32_t block_num) const;
optional<signed_block_with_info> get_block2(uint32_t block_num) const;
vector<optional<signed_block>> get_blocks(uint32_t block_num_from, uint32_t block_num_to) const;
processed_transaction get_transaction(uint32_t block_num, uint32_t trx_in_block) const;
@ -196,10 +184,6 @@ public:
fc::optional<son_object> get_son_by_account(const std::string account_id_or_name) const;
map<string, son_id_type> lookup_son_accounts(const string &lower_bound_name, uint32_t limit) const;
uint64_t get_son_count() const;
flat_map<sidechain_type, vector<son_sidechain_info>> get_active_sons();
vector<son_sidechain_info> get_active_sons_by_sidechain(sidechain_type sidechain);
map<sidechain_type, map<son_id_type, string>> get_son_network_status();
map<son_id_type, string> get_son_network_status_by_sidechain(sidechain_type sidechain);
// SON wallets
optional<son_wallet_object> get_active_son_wallet();
@ -281,9 +265,8 @@ public:
uint64_t nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const;
nft_object nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const;
nft_object nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const;
vector<nft_object> nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const;
vector<nft_object> nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const;
vector<nft_metadata_object> nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const;
vector<nft_object> nft_get_all_tokens() const;
vector<nft_object> nft_get_tokens_by_owner(const account_id_type owner) const;
// Marketplace
vector<offer_object> list_offers(const offer_id_type lower_id, uint32_t limit) const;
@ -304,7 +287,6 @@ public:
uint32_t api_limit_get_limit_orders_by_account = 101;
uint32_t api_limit_get_order_book = 50;
uint32_t api_limit_all_offers_count = 100;
uint32_t api_limit_nft_tokens = 100;
uint32_t api_limit_lookup_accounts = 1000;
uint32_t api_limit_lookup_witness_accounts = 1000;
uint32_t api_limit_lookup_committee_member_accounts = 1000;
@ -313,7 +295,7 @@ public:
uint32_t api_limit_get_trade_history = 100;
uint32_t api_limit_get_trade_history_by_sequence = 100;
// private:
//private:
const account_object *get_account_from_string(const std::string &name_or_id,
bool throw_if_not_found = true) const;
const asset_object *get_asset_from_string(const std::string &symbol_or_id,
@ -470,7 +452,7 @@ void database_api::set_subscribe_callback(std::function<void(const variant &)> c
}
void database_api_impl::set_subscribe_callback(std::function<void(const variant &)> cb, bool notify_remove_create) {
// edump((clear_filter));
//edump((clear_filter));
_subscribe_callback = cb;
_notify_remove_create = notify_remove_create;
_subscribed_accounts.clear();
@ -544,17 +526,6 @@ optional<signed_block> database_api_impl::get_block(uint32_t block_num) const {
return _db.fetch_block_by_number(block_num);
}
optional<signed_block_with_info> database_api::get_block2(uint32_t block_num) const {
return my->get_block2(block_num);
}
optional<signed_block_with_info> database_api_impl::get_block2(uint32_t block_num) const {
auto result = _db.fetch_block_by_number(block_num);
if (result)
return signed_block_with_info(*result);
return {};
}
vector<optional<signed_block>> database_api::get_blocks(uint32_t block_num_from, uint32_t block_num_to) const {
return my->get_blocks(block_num_from, block_num_to);
}
@ -1877,80 +1848,6 @@ uint64_t database_api_impl::get_son_count() const {
return _db.get_index_type<son_index>().indices().size();
}
flat_map<sidechain_type, vector<son_sidechain_info>> database_api::get_active_sons() {
return my->get_active_sons();
}
flat_map<sidechain_type, vector<son_sidechain_info>> database_api_impl::get_active_sons() {
return get_global_properties().active_sons;
}
vector<son_sidechain_info> database_api::get_active_sons_by_sidechain(sidechain_type sidechain) {
return my->get_active_sons_by_sidechain(sidechain);
}
vector<son_sidechain_info> database_api_impl::get_active_sons_by_sidechain(sidechain_type sidechain) {
const global_property_object &gpo = get_global_properties();
vector<son_sidechain_info> result;
if (gpo.active_sons.find(sidechain) != gpo.active_sons.end()) {
result = gpo.active_sons.at(sidechain);
}
return result;
}
map<sidechain_type, map<son_id_type, string>> database_api::get_son_network_status() {
return my->get_son_network_status();
}
map<sidechain_type, map<son_id_type, string>> database_api_impl::get_son_network_status() {
map<sidechain_type, map<son_id_type, string>> result;
for (auto active_sidechain_type : active_sidechain_types(_db.head_block_time())) {
result[active_sidechain_type] = get_son_network_status_by_sidechain(active_sidechain_type);
}
return result;
}
map<son_id_type, string> database_api::get_son_network_status_by_sidechain(sidechain_type sidechain) {
return my->get_son_network_status_by_sidechain(sidechain);
}
map<son_id_type, string> database_api_impl::get_son_network_status_by_sidechain(sidechain_type sidechain) {
const global_property_object &gpo = get_global_properties();
map<son_id_type, string> result;
if (gpo.active_sons.find(sidechain) != gpo.active_sons.end()) {
for (const auto si : gpo.active_sons.at(sidechain)) {
const auto son_obj = si.son_id(_db);
const auto sso = son_obj.statistics(_db);
string status;
if (sso.last_active_timestamp.find(sidechain) != sso.last_active_timestamp.end()) {
if (time_point_sec(sso.last_active_timestamp.at(sidechain) + fc::seconds(gpo.parameters.son_heartbeat_frequency())) > _db.head_block_time()) {
status = "OK, regular SON heartbeat";
} else {
if (time_point_sec(sso.last_active_timestamp.at(sidechain) + fc::seconds(gpo.parameters.son_down_time())) > _db.head_block_time()) {
status = "OK, irregular SON heartbeat, but not triggering SON down proposal";
} else {
status = "NOT OK, irregular SON heartbeat, triggering SON down proposal";
}
}
} else {
status = "No heartbeats sent";
}
result[si.son_id] = status;
}
}
return result;
}
//////////////////////////////////////////////////////////////////////
// //
// SON Wallets //
@ -2188,7 +2085,6 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
const auto &against_worker_idx = _db.get_index_type<worker_index>().indices().get<by_vote_against>();
const auto &son_bictoin_idx = _db.get_index_type<son_index>().indices().get<by_vote_id_bitcoin>();
const auto &son_hive_idx = _db.get_index_type<son_index>().indices().get<by_vote_id_hive>();
const auto &son_ethereum_idx = _db.get_index_type<son_index>().indices().get<by_vote_id_ethereum>();
vector<variant> result;
result.reserve(votes.size());
@ -2197,7 +2093,7 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
case vote_id_type::committee: {
auto itr = committee_idx.find(id);
if (itr != committee_idx.end())
result.emplace_back(variant(*itr, 2)); // Depth of committee_member_object is 1, add 1 to be safe
result.emplace_back(variant(*itr, 1));
else
result.emplace_back(variant());
break;
@ -2205,7 +2101,7 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
case vote_id_type::witness: {
auto itr = witness_idx.find(id);
if (itr != witness_idx.end())
result.emplace_back(variant(*itr, 2)); // Depth of witness_object is 1, add 1 here to be safe
result.emplace_back(variant(*itr, 1));
else
result.emplace_back(variant());
break;
@ -2213,15 +2109,11 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
case vote_id_type::worker: {
auto itr = for_worker_idx.find(id);
if (itr != for_worker_idx.end()) {
result.emplace_back(variant(*itr, 4)); // Depth of worker_object is 3, add 1 here to be safe.
// If we want to extract the balance object inside,
// need to increase this value
result.emplace_back(variant(*itr, 1));
} else {
auto itr = against_worker_idx.find(id);
if (itr != against_worker_idx.end()) {
result.emplace_back(variant(*itr, 4)); // Depth of worker_object is 3, add 1 here to be safe.
// If we want to extract the balance object inside,
// need to increase this value
result.emplace_back(variant(*itr, 1));
} else {
result.emplace_back(variant());
}
@ -2244,14 +2136,6 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
result.emplace_back(variant());
break;
}
case vote_id_type::son_ethereum: {
auto itr = son_ethereum_idx.find(id);
if (itr != son_ethereum_idx.end())
result.emplace_back(variant(*itr, 5));
else
result.emplace_back(variant());
break;
}
case vote_id_type::VOTE_TYPE_COUNT:
break; // supress unused enum value warnings
default:
@ -2289,9 +2173,6 @@ votes_info database_api_impl::get_votes(const string &account_name_or_id) const
const auto son_hive_ids = get_votes_objects<son_index, by_vote_id_hive>(votes_ids, 5);
if (!son_hive_ids.empty())
son_ids[sidechain_type::hive] = std::move(son_hive_ids);
const auto son_ethereum_ids = get_votes_objects<son_index, by_vote_id_ethereum>(votes_ids, 5);
if (!son_ethereum_ids.empty())
son_ids[sidechain_type::ethereum] = std::move(son_ethereum_ids);
return son_ids;
}();
@ -2344,9 +2225,7 @@ votes_info database_api_impl::get_votes(const string &account_name_or_id) const
votes_for_sons[sidechain].reserve(sidechain_ids.size());
for (const auto &son : sidechain_ids) {
const auto &son_obj = son.as<son_object>(6);
if (son_obj.get_sidechain_vote_id(sidechain).valid()) {
votes_for_sons[sidechain].emplace_back(votes_info_object{*son_obj.get_sidechain_vote_id(sidechain), son_obj.id});
}
votes_for_sons[sidechain].emplace_back(votes_info_object{son_obj.get_sidechain_vote_id(sidechain), son_obj.id});
}
}
result.votes_for_sons = std::move(votes_for_sons);
@ -2907,7 +2786,7 @@ graphene::app::gpos_info database_api::get_gpos_info(const account_id_type accou
}
graphene::app::gpos_info database_api_impl::get_gpos_info(const account_id_type account) const {
FC_ASSERT(_db.head_block_time() > HARDFORK_GPOS_TIME); // Can be deleted after GPOS hardfork time
FC_ASSERT(_db.head_block_time() > HARDFORK_GPOS_TIME); //Can be deleted after GPOS hardfork time
gpos_info result;
result.vesting_factor = _db.calculate_vesting_factor(account(_db));
@ -3133,61 +3012,30 @@ nft_object database_api_impl::nft_token_of_owner_by_index(const nft_metadata_id_
return {};
}
vector<nft_object> database_api::nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const {
return my->nft_get_all_tokens(lower_id, limit);
vector<nft_object> database_api::nft_get_all_tokens() const {
return my->nft_get_all_tokens();
}
vector<nft_object> database_api_impl::nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const {
FC_ASSERT(limit <= api_limit_nft_tokens,
"Number of queried nft tokens can not be greater than ${configured_limit}",
("configured_limit", api_limit_nft_tokens));
vector<nft_object> database_api_impl::nft_get_all_tokens() const {
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_id>();
vector<nft_object> result;
result.reserve(limit);
auto itr = idx_nft.lower_bound(lower_id);
while (limit-- && itr != idx_nft.end())
result.emplace_back(*itr++);
for (auto itr = idx_nft.begin(); itr != idx_nft.end(); ++itr) {
result.push_back(*itr);
}
return result;
}
vector<nft_object> database_api::nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const {
return my->nft_get_tokens_by_owner(owner, lower_id, limit);
vector<nft_object> database_api::nft_get_tokens_by_owner(const account_id_type owner) const {
return my->nft_get_tokens_by_owner(owner);
}
vector<nft_object> database_api_impl::nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const {
FC_ASSERT(limit <= api_limit_nft_tokens,
"Number of queried nft tokens can not be greater than ${configured_limit}",
("configured_limit", api_limit_nft_tokens));
vector<nft_object> database_api_impl::nft_get_tokens_by_owner(const account_id_type owner) const {
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_owner>();
auto idx_nft_range = idx_nft.equal_range(owner);
vector<nft_object> result;
result.reserve(limit);
auto itr = std::find_if(idx_nft_range.first, idx_nft_range.second, [&lower_id](const nft_object &obj) {
return !(obj.id.instance() < lower_id.instance);
});
while (limit-- && itr != idx_nft_range.second)
result.emplace_back(*itr++);
return result;
}
vector<nft_metadata_object> database_api::nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const {
return my->nft_get_metadata_by_owner(owner, lower_id, limit);
}
vector<nft_metadata_object> database_api_impl::nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const {
FC_ASSERT(limit <= api_limit_nft_tokens,
"Number of queried nft metadata objects can not be greater than ${configured_limit}",
("configured_limit", api_limit_nft_tokens));
const auto &idx_nft = _db.get_index_type<nft_metadata_index>().indices().get<by_owner>();
auto idx_nft_range = idx_nft.equal_range(owner);
vector<nft_metadata_object> result;
result.reserve(limit);
auto itr = std::find_if(idx_nft_range.first, idx_nft_range.second, [&lower_id](const nft_metadata_object &obj) {
return !(obj.id.instance() < lower_id.instance);
});
while (limit-- && itr != idx_nft_range.second)
result.emplace_back(*itr++);
for (auto itr = idx_nft_range.first; itr != idx_nft_range.second; ++itr) {
result.push_back(*itr);
}
return result;
}
@ -3554,9 +3402,9 @@ void database_api_impl::handle_object_changed(bool force_notify, bool full_objec
/// pushing the future back / popping the prior future if it is complete.
/// if a connection hangs then this could get backed up and result in
/// a failure to exit cleanly.
// fc::async([capture_this,this,updates,market_broadcast_queue](){
// if( _subscribe_callback )
// _subscribe_callback( updates );
//fc::async([capture_this,this,updates,market_broadcast_queue](){
//if( _subscribe_callback )
// _subscribe_callback( updates );
for (auto id : ids) {
if (id.is<call_order_object>()) {

View file

@ -85,10 +85,10 @@ struct asset_holders {
};
/**
* @brief The history_api class implements the RPC API for account history
*
* This API contains methods to access account histories
*/
* @brief The history_api class implements the RPC API for account history
*
* This API contains methods to access account histories
*/
class history_api {
public:
history_api(application &app) :
@ -97,27 +97,27 @@ public:
}
/**
* @brief Get operations relevant to the specificed account
* @param account_id_or_name The account ID or name whose history should be queried
* @param stop ID of the earliest operation to retrieve
* @param limit Maximum number of operations to retrieve (must not exceed 100)
* @param start ID of the most recent operation to retrieve
* @return A list of operations performed by account, ordered from most recent to oldest.
*/
* @brief Get operations relevant to the specificed account
* @param account_id_or_name The account ID or name whose history should be queried
* @param stop ID of the earliest operation to retrieve
* @param limit Maximum number of operations to retrieve (must not exceed 100)
* @param start ID of the most recent operation to retrieve
* @return A list of operations performed by account, ordered from most recent to oldest.
*/
vector<operation_history_object> get_account_history(const std::string account_id_or_name,
operation_history_id_type stop = operation_history_id_type(),
unsigned limit = 100,
operation_history_id_type start = operation_history_id_type()) const;
/**
* @brief Get only asked operations relevant to the specified account
* @param account_id_or_name The account ID or name whose history should be queried
* @param operation_id The ID of the operation we want to get operations in the account( 0 = transfer , 1 = limit order create, ...)
* @param stop ID of the earliest operation to retrieve
* @param limit Maximum number of operations to retrieve (must not exceed 100)
* @param start ID of the most recent operation to retrieve
* @return A list of operations performed by account, ordered from most recent to oldest.
*/
* @brief Get only asked operations relevant to the specified account
* @param account_id_or_name The account ID or name whose history should be queried
* @param operation_id The ID of the operation we want to get operations in the account( 0 = transfer , 1 = limit order create, ...)
* @param stop ID of the earliest operation to retrieve
* @param limit Maximum number of operations to retrieve (must not exceed 100)
* @param start ID of the most recent operation to retrieve
* @return A list of operations performed by account, ordered from most recent to oldest.
*/
vector<operation_history_object> get_account_history_operations(const std::string account_id_or_name,
int operation_id,
operation_history_id_type start = operation_history_id_type(),
@ -125,17 +125,17 @@ public:
unsigned limit = 100) const;
/**
* @breif Get operations relevant to the specified account referenced
* by an event numbering specific to the account. The current number of operations
* for the account can be found in the account statistics (or use 0 for start).
* @param account_id_or_name The account ID or name whose history should be queried
* @param stop Sequence number of earliest operation. 0 is default and will
* query 'limit' number of operations.
* @param limit Maximum number of operations to retrieve (must not exceed 100)
* @param start Sequence number of the most recent operation to retrieve.
* 0 is default, which will start querying from the most recent operation.
* @return A list of operations performed by account, ordered from most recent to oldest.
*/
* @breif Get operations relevant to the specified account referenced
* by an event numbering specific to the account. The current number of operations
* for the account can be found in the account statistics (or use 0 for start).
* @param account_id_or_name The account ID or name whose history should be queried
* @param stop Sequence number of earliest operation. 0 is default and will
* query 'limit' number of operations.
* @param limit Maximum number of operations to retrieve (must not exceed 100)
* @param start Sequence number of the most recent operation to retrieve.
* 0 is default, which will start querying from the most recent operation.
* @return A list of operations performed by account, ordered from most recent to oldest.
*/
vector<operation_history_object> get_relative_account_history(const std::string account_id_or_name,
uint32_t stop = 0,
unsigned limit = 100,
@ -156,8 +156,8 @@ private:
};
/**
* @brief Block api
*/
* @brief Block api
*/
class block_api {
public:
block_api(graphene::chain::database &db);
@ -170,8 +170,8 @@ private:
};
/**
* @brief The network_broadcast_api class allows broadcasting of transactions.
*/
* @brief The network_broadcast_api class allows broadcasting of transactions.
*/
class network_broadcast_api : public std::enable_shared_from_this<network_broadcast_api> {
public:
network_broadcast_api(application &a);
@ -186,36 +186,36 @@ public:
typedef std::function<void(variant /*transaction_confirmation*/)> confirmation_callback;
/**
* @brief Broadcast a transaction to the network
* @param trx The transaction to broadcast
*
* The transaction will be checked for validity in the local database prior to broadcasting. If it fails to
* apply locally, an error will be thrown and the transaction will not be broadcast.
*/
* @brief Broadcast a transaction to the network
* @param trx The transaction to broadcast
*
* The transaction will be checked for validity in the local database prior to broadcasting. If it fails to
* apply locally, an error will be thrown and the transaction will not be broadcast.
*/
void broadcast_transaction(const signed_transaction &trx);
/** this version of broadcast transaction registers a callback method that will be called when the transaction is
* included into a block. The callback method includes the transaction id, block number, and transaction number in the
* block.
*/
* included into a block. The callback method includes the transaction id, block number, and transaction number in the
* block.
*/
void broadcast_transaction_with_callback(confirmation_callback cb, const signed_transaction &trx);
/** this version of broadcast transaction registers a callback method that will be called when the transaction is
* included into a block. The callback method includes the transaction id, block number, and transaction number in the
* block.
*/
* included into a block. The callback method includes the transaction id, block number, and transaction number in the
* block.
*/
fc::variant broadcast_transaction_synchronous(const signed_transaction &trx);
void broadcast_block(const signed_block &block);
/**
* @brief Not reflected, thus not accessible to API clients.
*
* This function is registered to receive the applied_block
* signal from the chain database when a block is received.
* It then dispatches callbacks to clients who have requested
* to be notified when a particular txid is included in a block.
*/
* @brief Not reflected, thus not accessible to API clients.
*
* This function is registered to receive the applied_block
* signal from the chain database when a block is received.
* It then dispatches callbacks to clients who have requested
* to be notified when a particular txid is included in a block.
*/
void on_applied_block(const signed_block &b);
private:
@ -225,60 +225,60 @@ private:
};
/**
* @brief The network_node_api class allows maintenance of p2p connections.
*/
* @brief The network_node_api class allows maintenance of p2p connections.
*/
class network_node_api {
public:
network_node_api(application &a);
/**
* @brief Return general network information, such as p2p port
*/
* @brief Return general network information, such as p2p port
*/
fc::variant_object get_info() const;
/**
* @brief add_node Connect to a new peer
* @param ep The IP/Port of the peer to connect to
*/
* @brief add_node Connect to a new peer
* @param ep The IP/Port of the peer to connect to
*/
void add_node(const fc::ip::endpoint &ep);
/**
* @brief Get status of all current connections to peers
*/
* @brief Get status of all current connections to peers
*/
std::vector<net::peer_status> get_connected_peers() const;
/**
* @brief Get advanced node parameters, such as desired and max
* number of connections
*/
* @brief Get advanced node parameters, such as desired and max
* number of connections
*/
fc::variant_object get_advanced_node_parameters() const;
/**
* @brief Set advanced node parameters, such as desired and max
* number of connections
* @param params a JSON object containing the name/value pairs for the parameters to set
*/
* @brief Set advanced node parameters, such as desired and max
* number of connections
* @param params a JSON object containing the name/value pairs for the parameters to set
*/
void set_advanced_node_parameters(const fc::variant_object &params);
/**
* @brief Return list of potential peers
*/
* @brief Return list of potential peers
*/
std::vector<net::potential_peer_record> get_potential_peers() const;
/**
* @brief Return list of pending transactions.
*/
* @brief Return list of pending transactions.
*/
map<transaction_id_type, signed_transaction> list_pending_transactions() const;
/**
* @brief Subscribes caller for notifications about pending transactions.
* @param callback a functional object which will be called when new transaction is created.
*/
* @brief Subscribes caller for notifications about pending transactions.
* @param callback a functional object which will be called when new transaction is created.
*/
void subscribe_to_pending_transactions(std::function<void(const variant &)> callback);
/**
* @brief Unsubscribes caller from notifications about pending transactions.
*/
* @brief Unsubscribes caller from notifications about pending transactions.
*/
void unsubscribe_from_pending_transactions();
private:
@ -290,33 +290,33 @@ private:
};
/**
* @brief
*/
* @brief
*/
class asset_api {
public:
asset_api(graphene::app::application &app);
~asset_api();
/**
* @brief Get asset holders for a specific asset
* @param asset The specific asset id or symbol
* @param start The start index
* @param limit Maximum limit must not exceed 100
* @return A list of asset holders for the specified asset
*/
* @brief Get asset holders for a specific asset
* @param asset The specific asset id or symbol
* @param start The start index
* @param limit Maximum limit must not exceed 100
* @return A list of asset holders for the specified asset
*/
vector<account_asset_balance> get_asset_holders(std::string asset, uint32_t start, uint32_t limit) const;
/**
* @brief Get asset holders count for a specific asset
* @param asset The specific asset id or symbol
* @return Holders count for the specified asset
*/
* @brief Get asset holders count for a specific asset
* @param asset The specific asset id or symbol
* @return Holders count for the specified asset
*/
int get_asset_holders_count(std::string asset) const;
/**
* @brief Get all asset holders
* @return A list of all asset holders
*/
* @brief Get all asset holders
* @return A list of all asset holders
*/
vector<asset_holders> get_all_asset_holders() const;
uint32_t api_limit_get_asset_holders = 100;
@ -337,24 +337,24 @@ extern template class fc::api<graphene::debug_witness::debug_api>;
namespace graphene { namespace app {
/**
* @brief The login_api class implements the bottom layer of the RPC API
*
* All other APIs must be requested from this API.
*/
* @brief The login_api class implements the bottom layer of the RPC API
*
* All other APIs must be requested from this API.
*/
class login_api {
public:
login_api(application &a);
~login_api();
/**
* @brief Authenticate to the RPC server
* @param user Username to login with
* @param password Password to login with
* @return True if logged in successfully; false otherwise
*
* @note This must be called prior to requesting other APIs. Other APIs may not be accessible until the client
* has sucessfully authenticated.
*/
* @brief Authenticate to the RPC server
* @param user Username to login with
* @param password Password to login with
* @return True if logged in successfully; false otherwise
*
* @note This must be called prior to requesting other APIs. Other APIs may not be accessible until the client
* has sucessfully authenticated.
*/
bool login(const string &user, const string &password);
/// @brief Retrieve the network block API
fc::api<block_api> block() const;

View file

@ -82,15 +82,6 @@ using namespace std;
class database_api_impl;
struct signed_block_with_info : public signed_block {
signed_block_with_info();
signed_block_with_info(const signed_block &block);
signed_block_with_info(const signed_block_with_info &block) = default;
block_id_type block_id;
public_key_type signing_key;
vector<transaction_id_type> transaction_ids;
};
struct order {
double price;
double quote;
@ -198,10 +189,10 @@ public:
optional<block_header> get_block_header(uint32_t block_num) const;
/**
* @brief Retrieve multiple block header by block numbers
* @param block_num vector containing heights of the block whose header should be returned
* @return array of headers of the referenced blocks, or null if no matching block was found
*/
* @brief Retrieve multiple block header by block numbers
* @param block_num vector containing heights of the block whose header should be returned
* @return array of headers of the referenced blocks, or null if no matching block was found
*/
map<uint32_t, optional<block_header>> get_block_header_batch(const vector<uint32_t> block_nums) const;
/**
@ -211,13 +202,6 @@ public:
*/
optional<signed_block> get_block(uint32_t block_num) const;
/**
* @brief Retrieve a full, signed block, with some extra info
* @param block_num Height of the block to be returned
* @return the referenced block, or null if no matching block was found
*/
optional<signed_block_with_info> get_block2(uint32_t block_num) const;
/**
* @brief Retrieve a list of signed blocks
* @param block_num_from start
@ -279,12 +263,12 @@ public:
vector<vector<account_id_type>> get_key_references(vector<public_key_type> key) const;
/**
* Determine whether a textual representation of a public key
* (in Base-58 format) is *currently* linked
* to any *registered* (i.e. non-stealth) account on the blockchain
* @param public_key Public key
* @return Whether a public key is known
*/
* Determine whether a textual representation of a public key
* (in Base-58 format) is *currently* linked
* to any *registered* (i.e. non-stealth) account on the blockchain
* @param public_key Public key
* @return Whether a public key is known
*/
bool is_public_key_registered(string public_key) const;
//////////////
@ -691,32 +675,6 @@ public:
*/
uint64_t get_son_count() const;
/**
* @brief Get list of active sons
* @return List of active SONs
*/
flat_map<sidechain_type, vector<son_sidechain_info>> get_active_sons();
/**
* @brief Get list of active sons
* @param sidechain Sidechain type [bitcoin|ethereum|hive]
* @return List of active SONs
*/
vector<son_sidechain_info> get_active_sons_by_sidechain(sidechain_type sidechain);
/**
* @brief Get SON network status
* @return SON network status description for a given sidechain type
*/
map<sidechain_type, map<son_id_type, string>> get_son_network_status();
/**
* @brief Get SON network status
* @param sidechain Sidechain type [bitcoin|ethereum|hive]
* @return SON network status description for a given sidechain type
*/
map<son_id_type, string> get_son_network_status_by_sidechain(sidechain_type sidechain);
/////////////////////////
// SON Wallets //
/////////////////////////
@ -1043,25 +1001,14 @@ public:
* @brief Returns list of all available NTF's
* @return List of all available NFT's
*/
vector<nft_object> nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const;
vector<nft_object> nft_get_all_tokens() const;
/**
* @brief Returns NFT's owned by owner
* @param owner NFT owner
* @param lower_id ID of the first NFT to return
* @param limit Maximum number of results to return
* @return List of NFT owned by owner
*/
vector<nft_object> nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const;
/**
* @brief Returns NFT metadata owned by owner
* @param owner NFT owner
* @param lower_id ID of the first NFT metadata to return
* @param limit Maximum number of results to return
* @return List of NFT owned by owner
*/
vector<nft_metadata_object> nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const;
vector<nft_object> nft_get_tokens_by_owner(const account_id_type owner) const;
//////////////////
// MARKET PLACE //
@ -1091,8 +1038,6 @@ extern template class fc::api<graphene::app::database_api>;
// clang-format off
FC_REFLECT_DERIVED(graphene::app::signed_block_with_info, (graphene::chain::signed_block), (block_id)(signing_key)(transaction_ids));
FC_REFLECT(graphene::app::order, (price)(quote)(base));
FC_REFLECT(graphene::app::order_book, (base)(quote)(bids)(asks));
FC_REFLECT(graphene::app::market_ticker, (base)(quote)(latest)(lowest_ask)(highest_bid)(percent_change)(base_volume)(quote_volume));
@ -1115,7 +1060,6 @@ FC_API(graphene::app::database_api,
(get_block_header)
(get_block_header_batch)
(get_block)
(get_block2)
(get_blocks)
(get_transaction)
(get_recent_transaction_by_id)
@ -1205,10 +1149,6 @@ FC_API(graphene::app::database_api,
(get_son_by_account)
(lookup_son_accounts)
(get_son_count)
(get_active_sons)
(get_active_sons_by_sidechain)
(get_son_network_status)
(get_son_network_status_by_sidechain)
// SON wallets
(get_active_son_wallet)
@ -1279,7 +1219,6 @@ FC_API(graphene::app::database_api,
(nft_token_of_owner_by_index)
(nft_get_all_tokens)
(nft_get_tokens_by_owner)
(nft_get_metadata_by_owner)
// Marketplace
(list_offers)

View file

@ -53,54 +53,7 @@ void verify_authority_accounts( const database& db, const authority& a )
}
}
// Overwrites the num_son values from the origin to the destination for those sidechains which are found in the origin.
// Keeps the values of num_son for the sidechains which are found in the destination, but not in the origin.
// Returns false if an error is detected.
bool merge_num_sons( flat_map<sidechain_type, uint16_t>& destination,
const flat_map<sidechain_type, uint16_t>& origin,
fc::optional<time_point_sec> head_block_time = {})
{
const auto active_sidechains = head_block_time.valid() ? active_sidechain_types(*head_block_time) : all_sidechain_types;
bool success = true;
for (const auto &ns : origin)
{
destination[ns.first] = ns.second;
if (active_sidechains.find(ns.first) == active_sidechains.end())
{
success = false;
}
}
return success;
}
flat_map<sidechain_type, uint16_t> count_SON_votes_per_sidechain( const flat_set<vote_id_type>& votes )
{
flat_map<sidechain_type, uint16_t> SON_votes_per_sidechain = account_options::ext::empty_num_son();
for (const auto &vote : votes)
{
switch (vote.type())
{
case vote_id_type::son_bitcoin:
SON_votes_per_sidechain[sidechain_type::bitcoin]++;
break;
case vote_id_type::son_hive:
SON_votes_per_sidechain[sidechain_type::hive]++;
break;
case vote_id_type::son_ethereum:
SON_votes_per_sidechain[sidechain_type::ethereum]++;
break;
default:
break;
}
}
return SON_votes_per_sidechain;
}
void verify_account_votes( const database& db, const account_options& options, fc::optional<account_object> account = {} )
void verify_account_votes( const database& db, const account_options& options )
{
// ensure account's votes satisfy requirements
// NB only the part of vote checking that requires chain state is here,
@ -116,40 +69,12 @@ void verify_account_votes( const database& db, const account_options& options, f
FC_ASSERT( options.num_committee <= chain_params.maximum_committee_count,
"Voted for more committee members than currently allowed (${c})", ("c", chain_params.maximum_committee_count) );
FC_ASSERT( chain_params.extensions.value.maximum_son_count.valid() , "Invalid maximum son count" );
flat_map<sidechain_type, uint16_t> merged_num_sons = account_options::ext::empty_num_son();
// Merge with existing account if exists
if ( account.valid() && account->options.extensions.value.num_son.valid())
{
merge_num_sons( merged_num_sons, *account->options.extensions.value.num_son, db.head_block_time() );
}
// Apply update operation on top
if ( options.extensions.value.num_son.valid() )
{
merge_num_sons( merged_num_sons, *options.extensions.value.num_son, db.head_block_time() );
}
for(const auto& num_sons : merged_num_sons)
FC_ASSERT( options.extensions.value.num_son.valid() , "Invalid son number" );
for(const auto& num_sons : *options.extensions.value.num_son)
{
FC_ASSERT( num_sons.second <= *chain_params.extensions.value.maximum_son_count,
"Voted for more sons than currently allowed (${c})", ("c", *chain_params.extensions.value.maximum_son_count) );
}
// Count the votes for SONs and confirm that the account did not vote for less SONs than num_son
flat_map<sidechain_type, uint16_t> SON_votes_per_sidechain = count_SON_votes_per_sidechain(options.votes);
for (const auto& number_of_votes : SON_votes_per_sidechain)
{
// Number of votes of account_options are also checked in account_options::do_evaluate,
// but there we are checking the value before merging num_sons, so the values should be checked again
const auto sidechain = number_of_votes.first;
FC_ASSERT( number_of_votes.second >= merged_num_sons[sidechain],
"Voted for less sons than specified in num_son (votes ${v} < num_son ${ns}) for sidechain ${s}",
("v", number_of_votes.second) ("ns", merged_num_sons[sidechain]) ("s", sidechain) );
}
FC_ASSERT( db.find_object(options.voting_account), "Invalid proxy account specified." );
uint32_t max_vote_id = gpo.next_available_vote_id;
@ -263,13 +188,6 @@ object_id_type account_create_evaluator::do_apply( const account_create_operatio
obj.owner = o.owner;
obj.active = o.active;
obj.options = o.options;
obj.options.extensions.value.num_son = account_options::ext::empty_num_son();
if ( o.options.extensions.value.num_son.valid() )
{
merge_num_sons( *obj.options.extensions.value.num_son, *o.options.extensions.value.num_son );
}
obj.statistics = d.create<account_statistics_object>([&obj](account_statistics_object& s){
s.owner = obj.id;
s.name = obj.name;
@ -369,7 +287,7 @@ void_result account_update_evaluator::do_evaluate( const account_update_operatio
acnt = &o.account(d);
if( o.new_options.valid() )
verify_account_votes( d, *o.new_options, *acnt );
verify_account_votes( d, *o.new_options );
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
@ -408,31 +326,7 @@ void_result account_update_evaluator::do_apply( const account_update_operation&
a.active = *o.active;
a.top_n_control_flags = 0;
}
// New num_son structure initialized to 0
flat_map<sidechain_type, uint16_t> new_num_son = account_options::ext::empty_num_son();
// If num_son of existing object is valid, we should merge the existing data
if ( a.options.extensions.value.num_son.valid() )
{
merge_num_sons( new_num_son, *a.options.extensions.value.num_son );
}
// If num_son of the operation are valid, they should merge the existing data
if ( o.new_options )
{
const auto new_options = *o.new_options;
if ( new_options.extensions.value.num_son.valid() )
{
merge_num_sons( new_num_son, *new_options.extensions.value.num_son );
}
a.options = *o.new_options;
}
a.options.extensions.value.num_son = new_num_son;
if( o.new_options ) a.options = *o.new_options;
if( o.extensions.value.owner_special_authority.valid() )
{
a.owner_special_authority = *(o.extensions.value.owner_special_authority);

View file

@ -33,163 +33,45 @@ namespace graphene { namespace chain {
void_result transfer_to_blind_evaluator::do_evaluate( const transfer_to_blind_operation& o )
{ try {
const auto& d = db();
if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME )
{
const auto& atype = o.amount.asset_id(d);
FC_ASSERT( atype.allow_confidential() );
FC_ASSERT( !atype.is_transfer_restricted() );
FC_ASSERT( !(atype.options.flags & white_list) );
for( const auto& out : o.outputs )
{
for( const auto& a : out.owner.account_auths )
a.first(d); // verify all accounts exist and are valid
}
}
return void_result();
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void_result transfer_to_blind_evaluator::do_apply( const transfer_to_blind_operation& o )
void_result transfer_to_blind_evaluator::do_apply( const transfer_to_blind_operation& o )
{ try {
if( db().head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
db().adjust_balance(o.from, -o.amount);
const auto &add = o.amount.asset_id(db()).dynamic_asset_data_id(db()); // verify fee is a legit asset
db().modify(add, [&](asset_dynamic_data_object &obj) {
obj.confidential_supply += o.amount.amount;
FC_ASSERT(obj.confidential_supply >= 0);
});
for (const auto &out : o.outputs) {
db().create<blinded_balance_object>([&](blinded_balance_object &obj) {
obj.asset_id = o.amount.asset_id;
obj.owner = out.owner;
obj.commitment = out.commitment;
});
}
}
return void_result();
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void transfer_to_blind_evaluator::pay_fee()
{
const auto& d = db();
if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
if (d.head_block_time() >= HARDFORK_563_TIME)
pay_fba_fee(fba_accumulator_id_transfer_to_blind);
else
generic_evaluator::pay_fee();
}
}
void_result transfer_from_blind_evaluator::do_evaluate( const transfer_from_blind_operation& o )
{ try {
const auto& d = db();
if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
o.fee.asset_id(d); // verify fee is a legit asset
const auto &bbi = d.get_index_type<blinded_balance_index>();
const auto &cidx = bbi.indices().get<by_commitment>();
for (const auto &in : o.inputs) {
auto itr = cidx.find(in.commitment);
FC_ASSERT(itr != cidx.end());
FC_ASSERT(itr->asset_id == o.fee.asset_id);
FC_ASSERT(itr->owner == in.owner);
}
}
return void_result();
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void_result transfer_from_blind_evaluator::do_apply( const transfer_from_blind_operation& o )
void_result transfer_from_blind_evaluator::do_apply( const transfer_from_blind_operation& o )
{ try {
if( db().head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
db().adjust_balance(o.fee_payer(), o.fee);
db().adjust_balance(o.to, o.amount);
const auto &bbi = db().get_index_type<blinded_balance_index>();
const auto &cidx = bbi.indices().get<by_commitment>();
for (const auto &in : o.inputs) {
auto itr = cidx.find(in.commitment);
FC_ASSERT(itr != cidx.end());
db().remove(*itr);
}
const auto &add = o.amount.asset_id(db()).dynamic_asset_data_id(db()); // verify fee is a legit asset
db().modify(add, [&](asset_dynamic_data_object &obj) {
obj.confidential_supply -= o.amount.amount + o.fee.amount;
FC_ASSERT(obj.confidential_supply >= 0);
});
}
return void_result();
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void transfer_from_blind_evaluator::pay_fee()
{
const auto& d = db();
if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
if (d.head_block_time() >= HARDFORK_563_TIME)
pay_fba_fee(fba_accumulator_id_transfer_from_blind);
else
generic_evaluator::pay_fee();
}
}
void_result blind_transfer_evaluator::do_evaluate( const blind_transfer_operation& o )
{ try {
const auto& d = db();
if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
o.fee.asset_id(d); // verify fee is a legit asset
const auto &bbi = d.get_index_type<blinded_balance_index>();
const auto &cidx = bbi.indices().get<by_commitment>();
for (const auto &out : o.outputs) {
for (const auto &a : out.owner.account_auths)
a.first(d); // verify all accounts exist and are valid
}
for (const auto &in : o.inputs) {
auto itr = cidx.find(in.commitment);
GRAPHENE_ASSERT(itr != cidx.end(), blind_transfer_unknown_commitment, "", ("commitment", in.commitment));
FC_ASSERT(itr->asset_id == o.fee.asset_id);
FC_ASSERT(itr->owner == in.owner);
}
}
return void_result();
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void_result blind_transfer_evaluator::do_apply( const blind_transfer_operation& o )
void_result blind_transfer_evaluator::do_apply( const blind_transfer_operation& o )
{ try {
if( db().head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
db().adjust_balance(o.fee_payer(), o.fee); // deposit the fee to the temp account
const auto &bbi = db().get_index_type<blinded_balance_index>();
const auto &cidx = bbi.indices().get<by_commitment>();
for (const auto &in : o.inputs) {
auto itr = cidx.find(in.commitment);
GRAPHENE_ASSERT(itr != cidx.end(), blind_transfer_unknown_commitment, "", ("commitment", in.commitment));
db().remove(*itr);
}
for (const auto &out : o.outputs) {
db().create<blinded_balance_object>([&](blinded_balance_object &obj) {
obj.asset_id = o.fee.asset_id;
obj.owner = out.owner;
obj.commitment = out.commitment;
});
}
const auto &add = o.fee.asset_id(db()).dynamic_asset_data_id(db());
db().modify(add, [&](asset_dynamic_data_object &obj) {
obj.confidential_supply -= o.fee.amount;
FC_ASSERT(obj.confidential_supply >= 0);
});
}
return void_result();
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void blind_transfer_evaluator::pay_fee()
{
const auto& d = db();
if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
if (d.head_block_time() >= HARDFORK_563_TIME)
pay_fba_fee(fba_accumulator_id_blind_transfer);
else
generic_evaluator::pay_fee();
}
}
} } // graphene::chain

View file

@ -40,10 +40,8 @@
#include <graphene/chain/exceptions.hpp>
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/witness_schedule_object.hpp>
#include <graphene/db/object_database.hpp>
#include <fc/crypto/digest.hpp>
#include <boost/filesystem.hpp>
namespace {
@ -162,13 +160,10 @@ void database::check_transaction_for_duplicated_operations(const signed_transact
existed_operations_digests.insert( proposed_operations_digests.begin(), proposed_operations_digests.end() );
});
for (auto& pending_transaction: _pending_tx)
{
const std::lock_guard<std::mutex> pending_tx_lock{_pending_tx_mutex};
for (auto &pending_transaction : _pending_tx)
{
auto proposed_operations_digests = gather_proposed_operations_digests(pending_transaction);
existed_operations_digests.insert(proposed_operations_digests.begin(), proposed_operations_digests.end());
}
auto proposed_operations_digests = gather_proposed_operations_digests(pending_transaction);
existed_operations_digests.insert(proposed_operations_digests.begin(), proposed_operations_digests.end());
}
auto proposed_operations_digests = gather_proposed_operations_digests(trx);
@ -190,12 +185,7 @@ bool database::push_block(const signed_block& new_block, uint32_t skip)
bool result;
detail::with_skip_flags( *this, skip, [&]()
{
std::vector<processed_transaction> pending_tx = [this] {
const std::lock_guard<std::mutex> pending_tx_lock{_pending_tx_mutex};
return std::move(_pending_tx);
}();
detail::without_pending_transactions( *this, std::move(pending_tx),
detail::without_pending_transactions( *this, std::move(_pending_tx),
[&]()
{
result = _push_block(new_block);
@ -206,9 +196,6 @@ bool database::push_block(const signed_block& new_block, uint32_t skip)
bool database::_push_block(const signed_block& new_block)
{ try {
boost::filesystem::space_info si = boost::filesystem::space(get_data_dir());
FC_ASSERT((si.available) > 104857600, "Rejecting block due to low disk space"); // 104857600 bytes = 100 MB
uint32_t skip = get_node_properties().skip_flags;
const auto now = fc::time_point::now().sec_since_epoch();
@ -395,26 +382,17 @@ processed_transaction database::_push_transaction( const signed_transaction& trx
{
// If this is the first transaction pushed after applying a block, start a new undo session.
// This allows us to quickly rewind to the clean state of the head block, in case a new block arrives.
{
const std::lock_guard<std::mutex> pending_tx_session_lock{_pending_tx_session_mutex};
if (!_pending_tx_session.valid()) {
const std::lock_guard<std::mutex> undo_db_lock{_undo_db_mutex};
_pending_tx_session = _undo_db.start_undo_session();
}
}
if( !_pending_tx_session.valid() )
_pending_tx_session = _undo_db.start_undo_session();
// Create a temporary undo session as a child of _pending_tx_session.
// The temporary session will be discarded by the destructor if
// _apply_transaction fails. If we make it to merge(), we
// apply the changes.
const std::lock_guard<std::mutex> undo_db_lock{_undo_db_mutex};
auto temp_session = _undo_db.start_undo_session();
auto processed_trx = _apply_transaction(trx);
{
const std::lock_guard<std::mutex> pending_tx_lock{_pending_tx_mutex};
_pending_tx.push_back(processed_trx);
}
auto processed_trx = _apply_transaction( trx );
_pending_tx.push_back(processed_trx);
// notify_changed_objects();
// The transaction applied successfully. Merge its changes into the pending block session.
@ -427,7 +405,6 @@ processed_transaction database::_push_transaction( const signed_transaction& trx
processed_transaction database::validate_transaction( const signed_transaction& trx )
{
const std::lock_guard<std::mutex> undo_db_lock{_undo_db_mutex};
auto session = _undo_db.start_undo_session();
return _apply_transaction( trx );
}
@ -527,52 +504,47 @@ signed_block database::_generate_block(
// the value of the "when" variable is known, which means we need to
// re-apply pending transactions in this method.
//
{
const std::lock_guard<std::mutex> pending_tx_session_lock{_pending_tx_session_mutex};
_pending_tx_session.reset();
_pending_tx_session = _undo_db.start_undo_session();
}
_pending_tx_session.reset();
_pending_tx_session = _undo_db.start_undo_session();
uint64_t postponed_tx_count = 0;
// pop pending state (reset to head block state)
for( const processed_transaction& tx : _pending_tx )
{
const std::lock_guard<std::mutex> pending_tx_lock{_pending_tx_mutex};
for (const processed_transaction &tx : _pending_tx) {
size_t new_total_size = total_block_size + fc::raw::pack_size(tx);
size_t new_total_size = total_block_size + fc::raw::pack_size( tx );
// postpone transaction if it would make block too big
if (new_total_size >= maximum_block_size) {
postponed_tx_count++;
continue;
}
// postpone transaction if it would make block too big
if( new_total_size >= maximum_block_size )
{
postponed_tx_count++;
continue;
}
try {
auto temp_session = _undo_db.start_undo_session();
processed_transaction ptx = _apply_transaction(tx);
temp_session.merge();
try
{
auto temp_session = _undo_db.start_undo_session();
processed_transaction ptx = _apply_transaction( tx );
temp_session.merge();
// We have to recompute pack_size(ptx) because it may be different
// than pack_size(tx) (i.e. if one or more results increased
// their size)
total_block_size += fc::raw::pack_size(ptx);
pending_block.transactions.push_back(ptx);
} catch (const fc::exception &e) {
// Do nothing, transaction will not be re-applied
wlog("Transaction was not processed while generating block due to ${e}", ("e", e));
wlog("The transaction was ${t}", ("t", tx));
}
// We have to recompute pack_size(ptx) because it may be different
// than pack_size(tx) (i.e. if one or more results increased
// their size)
total_block_size += fc::raw::pack_size( ptx );
pending_block.transactions.push_back( ptx );
}
catch ( const fc::exception& e )
{
// Do nothing, transaction will not be re-applied
wlog( "Transaction was not processed while generating block due to ${e}", ("e", e) );
wlog( "The transaction was ${t}", ("t", tx) );
}
}
if( postponed_tx_count > 0 )
{
wlog( "Postponed ${n} transactions due to block size limit", ("n", postponed_tx_count) );
}
{
const std::lock_guard<std::mutex> pending_tx_session_lock{_pending_tx_session_mutex};
_pending_tx_session.reset();
}
_pending_tx_session.reset();
// We have temporarily broken the invariant that
// _pending_tx_session is the result of applying _pending_tx, as
@ -620,11 +592,7 @@ signed_block database::_generate_block(
*/
void database::pop_block()
{ try {
{
const std::lock_guard<std::mutex> pending_tx_session_lock{_pending_tx_session_mutex};
_pending_tx_session.reset();
}
_pending_tx_session.reset();
auto head_id = head_block_id();
optional<signed_block> head_block = fetch_block_by_id( head_id );
GRAPHENE_ASSERT( head_block.valid(), pop_empty_chain, "there are no blocks to pop" );
@ -638,8 +606,6 @@ void database::pop_block()
void database::clear_pending()
{ try {
const std::lock_guard<std::mutex> pending_tx_lock{_pending_tx_mutex};
const std::lock_guard<std::mutex> pending_tx_session_lock{_pending_tx_session_mutex};
assert( (_pending_tx.size() == 0) || _pending_tx_session.valid() );
_pending_tx.clear();
_pending_tx_session.reset();
@ -739,11 +705,13 @@ void database::_apply_block( const signed_block& next_block )
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM) {
update_witness_schedule(next_block);
for(const auto& active_sons : global_props.active_sons) {
if(!active_sons.second.empty()) {
update_son_schedule(active_sons.first, next_block);
}
bool need_to_update_son_schedule = false;
for(const auto& active_sons : global_props.active_sons){
if(!active_sons.second.empty())
need_to_update_son_schedule = true;
}
if(need_to_update_son_schedule) {
update_son_schedule(next_block);
}
}
@ -758,7 +726,7 @@ void database::_apply_block( const signed_block& next_block )
check_ending_lotteries();
check_ending_nft_lotteries();
create_block_summary(next_block);
place_delayed_bets(); // must happen after update_global_dynamic_data() updates the time
clear_expired_transactions();
@ -781,11 +749,15 @@ void database::_apply_block( const signed_block& next_block )
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM) {
update_witness_schedule();
for(const auto& active_sidechain_type : active_sidechain_types(dynamic_global_props.time)) {
bool need_update_son_schedule = false;
for(const auto& active_sidechain_type : active_sidechain_types) {
if(global_props.active_sons.at(active_sidechain_type).size() > 0) {
update_son_schedule(active_sidechain_type);
need_update_son_schedule = true;
}
}
if(need_update_son_schedule) {
update_son_schedule();
}
}
if( !_node_property_object.debug_updates.empty() )

View file

@ -236,10 +236,8 @@ std::set<son_id_type> database::get_sons_to_be_deregistered()
// TODO : We need to add a function that returns if we can deregister SON
// i.e. with introduction of PW code, we have to make a decision if the SON
// is needed for release of funds from the PW
if(stats.last_active_timestamp.contains(sidechain)) {
if (head_block_time() - stats.last_active_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time())) {
need_to_be_deregistered = false;
}
if (head_block_time() - stats.last_down_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time())) {
need_to_be_deregistered = false;
}
}
}
@ -305,16 +303,17 @@ bool database::is_son_dereg_valid( son_id_type son_id )
}
bool status_son_dereg_valid = true;
for (const auto &active_sidechain_type : active_sidechain_types(head_block_time())) {
if(son->statuses.at(active_sidechain_type) != son_status::in_maintenance)
for(const auto& status : son->statuses)
{
const auto& sidechain = status.first;
if(status.second != son_status::in_maintenance)
status_son_dereg_valid = false;
if(status_son_dereg_valid)
{
if(son->statistics(*this).last_active_timestamp.contains(active_sidechain_type)) {
if (head_block_time() - son->statistics(*this).last_active_timestamp.at(active_sidechain_type) < fc::seconds(get_global_properties().parameters.son_deregister_time())) {
status_son_dereg_valid = false;
}
if(head_block_time() - son->statistics(*this).last_down_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time()))
{
status_son_dereg_valid = false;
}
}
}
@ -340,7 +339,7 @@ bool database::is_son_active( sidechain_type type, son_id_type son_id )
active_son_ids.reserve(gpo_as.size());
std::transform(gpo_as.cbegin(), gpo_as.cend(),
std::inserter(active_son_ids, active_son_ids.end()),
[](const son_sidechain_info& swi) {
[](const son_info& swi) {
return swi.son_id;
});
@ -386,14 +385,23 @@ vector<uint64_t> database::get_random_numbers(uint64_t minimum, uint64_t maximum
bool database::is_asset_creation_allowed(const string &symbol)
{
time_point_sec now = head_block_time();
std::unordered_set<std::string> post_son_hf_symbols = {"ETH", "USDT", "BNB", "ADA", "DOGE", "XRP", "USDC", "DOT", "UNI", "BUSD", "BCH", "LTC", "SOL", "LINK", "MATIC", "THETA",
"WBTC", "XLM", "ICP", "DAI", "VET", "ETC", "TRX", "FIL", "XMR", "EGR", "EOS", "SHIB", "AAVE", "CRO", "ALGO", "AMP", "BTCB",
"BSV", "KLAY", "CAKE", "FTT", "LEO", "XTZ", "TFUEL", "MIOTA", "LUNA", "NEO", "ATOM", "MKR", "FEI", "WBNB", "UST", "AVAX",
"STEEM", "HIVE", "HBD", "SBD", "BTS"};
if (symbol == "BTC")
{
if (head_block_time() < HARDFORK_SON_TIME)
if (now < HARDFORK_SON_TIME)
return false;
}
if (post_son_hf_symbols.find(symbol) != post_son_hf_symbols.end())
{
if (now >= HARDFORK_SON_TIME)
return false;
}
return true;
}
}
}
} }

View file

@ -365,7 +365,7 @@ void database::initialize_hardforks()
_hardfork_times.emplace_back(HARDFORK_SON_FOR_HIVE_TIME);
_hardfork_times.emplace_back(HARDFORK_SON_TIME);
_hardfork_times.emplace_back(HARDFORK_SON2_TIME);
_hardfork_times.emplace_back(HARDFORK_SON_FOR_ETHEREUM_TIME);
_hardfork_times.emplace_back(HARDFORK_SON3_TIME);
_hardfork_times.emplace_back(HARDFORK_SWEEPS_TIME);
std::sort(_hardfork_times.begin(), _hardfork_times.end());
@ -374,9 +374,7 @@ void database::initialize_hardforks()
void database::initialize_indexes()
{
reset_indexes();
const std::lock_guard<std::mutex> undo_db_lock{_undo_db_mutex};
_undo_db.set_max_size(GRAPHENE_MIN_UNDO_HISTORY);
_undo_db.set_max_size( GRAPHENE_MIN_UNDO_HISTORY );
//Protocol object indexes
add_index< primary_index<asset_index, 13> >(); // 8192 assets per chunk
@ -476,9 +474,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
FC_ASSERT(genesis_state.initial_active_witnesses <= genesis_state.initial_witness_candidates.size(),
"initial_active_witnesses is larger than the number of candidate witnesses.");
const std::lock_guard<std::mutex> undo_db_lock{_undo_db_mutex};
_undo_db.disable();
struct auth_inhibitor {
auth_inhibitor(database& db) : db(db), old_flags(db.node_properties().skip_flags)
{ db.node_properties().skip_flags |= skip_authority_check; }
@ -1105,6 +1101,28 @@ void database::init_genesis(const genesis_state_type& genesis_state)
// Initialize witness schedule
#ifndef NDEBUG
const son_schedule_object& ssohive =
#endif
create<son_schedule_object>([&](son_schedule_object& _sso)
{
// for scheduled
memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size());
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
auto init_witnesses = get_global_properties().active_witnesses;
_sso.scheduler = son_scheduler();
_sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1);
_sso.last_scheduling_block = 0;
_sso.recent_slots_filled = fc::uint128::max_value();
});
assert( ssohive.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::hive)) );
#ifndef NDEBUG
const son_schedule_object& ssobitcoin =
#endif
@ -1115,10 +1133,11 @@ void database::init_genesis(const genesis_state_type& genesis_state)
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
auto init_bitcoin_sons = get_global_properties().active_sons.at(sidechain_type::bitcoin);
auto init_witnesses = get_global_properties().active_witnesses;
_sso.scheduler = son_scheduler();
_sso.scheduler._min_token_count = std::max(int(init_bitcoin_sons.size()) / 2, 1);
_sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1);
_sso.last_scheduling_block = 0;
@ -1126,53 +1145,6 @@ void database::init_genesis(const genesis_state_type& genesis_state)
});
assert( ssobitcoin.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::bitcoin)) );
#ifndef NDEBUG
const son_schedule_object& ssoethereum =
#endif
create<son_schedule_object>([&](son_schedule_object& _sso)
{
// for scheduled
memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size());
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
auto init_ethereum_sons = get_global_properties().active_sons.at(sidechain_type::ethereum);
_sso.scheduler = son_scheduler();
_sso.scheduler._min_token_count = std::max(int(init_ethereum_sons.size()) / 2, 1);
_sso.last_scheduling_block = 0;
_sso.recent_slots_filled = fc::uint128::max_value();
});
assert( ssoethereum.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::ethereum)) );
#ifndef NDEBUG
const son_schedule_object& ssohive =
#endif
create<son_schedule_object>([&](son_schedule_object& _sso)
{
// for scheduled
memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size());
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
auto init_hive_sons = get_global_properties().active_sons.at(sidechain_type::hive);
_sso.scheduler = son_scheduler();
_sso.scheduler._min_token_count = std::max(int(init_hive_sons.size()) / 2, 1);
_sso.last_scheduling_block = 0;
_sso.recent_slots_filled = fc::uint128::max_value();
});
assert( ssohive.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::hive)) );
// Enable fees
modify(get_global_properties(), [&genesis_state](global_property_object& p) {
p.parameters.current_fees = genesis_state.initial_parameters.current_fees;
});
// Create FBA counters
create<fba_accumulator_object>([&]( fba_accumulator_object& acc )
{

View file

@ -84,29 +84,24 @@ vector<std::reference_wrapper<const son_object>> database::sort_votable_objects<
std::vector<std::reference_wrapper<const son_object>> refs;
for( auto& son : all_sons )
{
if(son.has_valid_config(head_block_time(), sidechain) && son.statuses.at(sidechain) != son_status::deregistered)
if(son.has_valid_config(head_block_time()) && son.statuses.at(sidechain) != son_status::deregistered)
{
refs.push_back(std::cref(son));
}
}
count = std::min(count, refs.size());
std::partial_sort(refs.begin(), refs.begin() + count, refs.end(),
[this, sidechain](const son_object& a, const son_object& b)->bool {
FC_ASSERT(sidechain == sidechain_type::bitcoin ||
sidechain == sidechain_type::ethereum ||
sidechain == sidechain_type::hive,
"Unexpected sidechain type");
[this, sidechain](const son_object& a, const son_object& b)->bool {
FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive, "Unexpected sidechain type");
FC_ASSERT(a.get_sidechain_vote_id(sidechain).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", sidechain)("son", a));
FC_ASSERT(b.get_sidechain_vote_id(sidechain).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", sidechain)("son", b));
const share_type oa_vote = _vote_tally_buffer.size() > *a.get_sidechain_vote_id(sidechain) ? _vote_tally_buffer[*a.get_sidechain_vote_id(sidechain)] : 0;
const share_type ob_vote = _vote_tally_buffer.size() > *b.get_sidechain_vote_id(sidechain) ? _vote_tally_buffer[*b.get_sidechain_vote_id(sidechain)] : 0;
const share_type oa_vote = _vote_tally_buffer[a.get_sidechain_vote_id(sidechain)];
const share_type ob_vote = _vote_tally_buffer[b.get_sidechain_vote_id(sidechain)];
if( oa_vote != ob_vote )
return oa_vote > ob_vote;
if( oa_vote != ob_vote )
return oa_vote > ob_vote;
return a.get_sidechain_vote_id(sidechain) < b.get_sidechain_vote_id(sidechain);
});
return a.get_sidechain_vote_id(sidechain) < b.get_sidechain_vote_id(sidechain);
});
refs.resize(count, refs.front());
return refs;
@ -170,7 +165,6 @@ struct worker_pay_visitor
worker.pay_worker(pay, db);
}
};
void database::update_worker_votes()
{
auto& idx = get_index_type<worker_index>();
@ -186,132 +180,14 @@ void database::update_worker_votes()
}
}
void database::hotfix_2024()
{
if (head_block_time() >= HARDFORK_HOTFIX_2024_TIME)
{
if (get_chain_id().str() == "6b6b5f0ce7a36d323768e534f3edb41c6d6332a541a95725b98e28d140850134")
{
const auto& vb_idx = get_index_type<vesting_balance_index>().indices().get<by_id>();
auto vbo = vb_idx.find(vesting_balance_id_type(388));
if (vbo != vb_idx.end())
{
if (vbo->owner == account_id_type(14786))
{
modify(*vbo, [&]( vesting_balance_object& _vbo)
{
_vbo.owner = account_id_type(0);
});
}
}
}
}
}
void database::pay_sons_before_hf_ethereum()
{
const auto now = head_block_time();
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
// Current requirement is that we have to pay every 24 hours, so the following check
if( dpo.son_budget.value > 0 && ((now - dpo.last_son_payout_time) >= fc::seconds(get_global_properties().parameters.son_pay_time())))
{
const sidechain_type st = sidechain_type::bitcoin;
const auto sons = sort_votable_objects<son_index>(st, get_global_properties().parameters.maximum_son_count());
// After SON2 HF
uint64_t total_votes = 0;
for( const son_object& son : sons )
{
FC_ASSERT(son.get_sidechain_vote_id(st).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", st)("son", son));
total_votes += _vote_tally_buffer[*son.get_sidechain_vote_id(st)];
}
const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0);
auto get_weight = [&bits_to_drop]( uint64_t son_votes ) {
const uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) );
return weight;
};
// Before SON2 HF
auto get_weight_before_son2_hf = []( uint64_t son_votes ) {
const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(son_votes)) - 15, 0);
const uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) );
return weight;
};
uint64_t weighted_total_txs_signed = 0;
const share_type son_budget = dpo.son_budget;
get_index_type<son_stats_index>().inspect_all_objects([this, &weighted_total_txs_signed, &get_weight, &now, &get_weight_before_son2_hf, &st](const object& o) {
const son_statistics_object& s = static_cast<const son_statistics_object&>(o);
const auto& idx = get_index_type<son_index>().indices().get<by_id>();
const auto son_obj = idx.find( s.owner );
uint16_t son_weight = 0;
FC_ASSERT(son_obj->get_sidechain_vote_id(st).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", st)("son", *son_obj));
if( now >= HARDFORK_SON2_TIME ) {
son_weight += get_weight(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]);
}
else {
son_weight += get_weight_before_son2_hf(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]);
}
const uint64_t txs_signed_bitcoin = s.txs_signed.contains(sidechain_type::bitcoin) ? s.txs_signed.at(sidechain_type::bitcoin) : 0;
const uint64_t txs_signed_hive = s.txs_signed.contains(sidechain_type::hive) ? s.txs_signed.at(sidechain_type::hive) : 0;
weighted_total_txs_signed += ((txs_signed_bitcoin + txs_signed_hive) * son_weight);
});
// Now pay off each SON proportional to the number of transactions signed.
get_index_type<son_stats_index>().inspect_all_objects([this, &weighted_total_txs_signed, &dpo, &son_budget, &get_weight, &get_weight_before_son2_hf, &now, &st](const object& o) {
const son_statistics_object& s = static_cast<const son_statistics_object&>(o);
const uint64_t txs_signed_bitcoin = s.txs_signed.contains(sidechain_type::bitcoin) ? s.txs_signed.at(sidechain_type::bitcoin) : 0;
const uint64_t txs_signed_hive = s.txs_signed.contains(sidechain_type::hive) ? s.txs_signed.at(sidechain_type::hive) : 0;
if(txs_signed_bitcoin > 0 || txs_signed_hive > 0) {
const auto& idx = get_index_type<son_index>().indices().get<by_id>();
auto son_obj = idx.find( s.owner );
uint16_t son_weight = 0;
FC_ASSERT(son_obj->get_sidechain_vote_id(st).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", st)("son", *son_obj));
if( now >= HARDFORK_SON2_TIME ) {
son_weight += get_weight(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]);
}
else {
son_weight += get_weight_before_son2_hf(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]);
}
const share_type pay = ((txs_signed_bitcoin + txs_signed_hive) * son_weight * son_budget.value)/weighted_total_txs_signed;
modify( *son_obj, [&]( son_object& _son_obj)
{
_son_obj.pay_son_fee(pay, *this);
});
//Remove the amount paid out to SON from global SON Budget
modify( dpo, [&]( dynamic_global_property_object& _dpo )
{
_dpo.son_budget -= pay;
} );
//Reset the tx counter in each son statistics object
modify( s, [&]( son_statistics_object& _s)
{
if(_s.txs_signed.contains(sidechain_type::bitcoin))
_s.txs_signed.at(sidechain_type::bitcoin) = 0;
if(_s.txs_signed.contains(sidechain_type::hive))
_s.txs_signed.at(sidechain_type::hive) = 0;
});
}
});
//Note the last son pay out time
modify( dpo, [&]( dynamic_global_property_object& _dpo )
{
_dpo.last_son_payout_time = now;
});
}
}
void database::pay_sons_after_hf_ethereum()
void database::pay_sons()
{
const time_point_sec now = head_block_time();
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
// Current requirement is that we have to pay every 24 hours, so the following check
if( dpo.son_budget.value > 0 && ((now - dpo.last_son_payout_time) >= fc::seconds(get_global_properties().parameters.son_pay_time())))
{
flat_map<sidechain_type, int8_t> bits_to_drop;
for(const auto& active_sidechain_type : active_sidechain_types(now))
for(const auto& active_sidechain_type : active_sidechain_types)
{
assert( _son_count_histogram_buffer.at(active_sidechain_type).size() > 0 );
const share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer.at(active_sidechain_type)[0]) / 2;
@ -328,76 +204,87 @@ void database::pay_sons_after_hf_ethereum()
}
}
const auto sons = sort_votable_objects<son_index>(active_sidechain_type, (std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count)));
const auto sons = sort_votable_objects<son_index>(active_sidechain_type,
(std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count))
);
// After SON2 HF
uint64_t total_votes = 0;
for( const son_object& son : sons )
{
FC_ASSERT(son.get_sidechain_vote_id(active_sidechain_type).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", active_sidechain_type)("son", son));
total_votes += _vote_tally_buffer[*son.get_sidechain_vote_id(active_sidechain_type)];
total_votes += _vote_tally_buffer[son.sidechain_vote_ids.at(active_sidechain_type)];
}
bits_to_drop[active_sidechain_type] = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0);
}
auto get_weight = [&bits_to_drop]( sidechain_type sidechain, uint64_t son_votes ) {
const uint16_t weight = std::max((son_votes >> bits_to_drop.at(sidechain)), uint64_t(1) );
return weight;
};
// Calculate weighted_total_txs_signed
uint64_t weighted_total_txs_signed = 0;
get_index_type<son_stats_index>().inspect_all_objects([this, &weighted_total_txs_signed, &get_weight, &now](const object& o) {
for(const auto& active_sidechain_type : active_sidechain_types(now)) {
const son_statistics_object &s = static_cast<const son_statistics_object &>(o);
const auto &idx = get_index_type<son_index>().indices().get<by_id>();
const auto son_obj = idx.find(s.owner);
FC_ASSERT(son_obj->get_sidechain_vote_id(active_sidechain_type).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", active_sidechain_type)("son", *son_obj));
const uint16_t son_weight = get_weight(active_sidechain_type, _vote_tally_buffer[*son_obj->get_sidechain_vote_id(active_sidechain_type)]);
const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0);
auto get_weight = [&bits_to_drop]( uint64_t son_votes ) {
const uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) );
return weight;
};
// Before SON2 HF
auto get_weight_before_son2_hf = []( uint64_t son_votes ) {
const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(son_votes)) - 15, 0);
const uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) );
return weight;
};
uint64_t weighted_total_txs_signed = 0;
const share_type son_budget = dpo.son_budget;
get_index_type<son_stats_index>().inspect_all_objects([this, &weighted_total_txs_signed, &get_weight, &now, &get_weight_before_son2_hf, &active_sidechain_type](const object& o) {
const son_statistics_object& s = static_cast<const son_statistics_object&>(o);
const auto& idx = get_index_type<son_index>().indices().get<by_id>();
const auto son_obj = idx.find( s.owner );
uint16_t son_weight = 0;
if( now >= HARDFORK_SON2_TIME ) {
son_weight += get_weight(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]);
}
else {
son_weight += get_weight_before_son2_hf(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]);
}
const uint64_t txs_signed = s.txs_signed.contains(active_sidechain_type) ? s.txs_signed.at(active_sidechain_type) : 0;
weighted_total_txs_signed += (txs_signed * son_weight);
}
});
// Now pay off each SON proportional to the number of transactions signed
const share_type son_budget = dpo.son_budget;
get_index_type<son_stats_index>().inspect_all_objects([this, &now, &get_weight, &weighted_total_txs_signed, &dpo, &son_budget](const object& o) {
for(const auto& active_sidechain_type : active_sidechain_types(now)) {
const son_statistics_object &s = static_cast<const son_statistics_object &>(o);
});
// Now pay off each SON proportional to the number of transactions signed.
get_index_type<son_stats_index>().inspect_all_objects([this, &weighted_total_txs_signed, &dpo, &son_budget, &get_weight, &get_weight_before_son2_hf, &now, &active_sidechain_type](const object& o) {
const son_statistics_object& s = static_cast<const son_statistics_object&>(o);
const uint64_t txs_signed = s.txs_signed.contains(active_sidechain_type) ? s.txs_signed.at(active_sidechain_type) : 0;
if (txs_signed > 0) {
const auto &idx = get_index_type<son_index>().indices().get<by_id>();
auto son_obj = idx.find(s.owner);
if(txs_signed > 0){
const auto& idx = get_index_type<son_index>().indices().get<by_id>();
auto son_obj = idx.find( s.owner );
uint16_t son_weight = 0;
FC_ASSERT(son_obj->get_sidechain_vote_id(active_sidechain_type).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", active_sidechain_type)("son", *son_obj));
son_weight += get_weight(active_sidechain_type, _vote_tally_buffer[*son_obj->get_sidechain_vote_id(active_sidechain_type)]);
const share_type pay = (txs_signed * son_weight * son_budget.value) / weighted_total_txs_signed;
modify(*son_obj, [&](son_object &_son_obj) {
_son_obj.pay_son_fee(pay, *this);
if( now >= HARDFORK_SON2_TIME ) {
son_weight += get_weight(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]);
}
else {
son_weight += get_weight_before_son2_hf(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]);
}
const share_type pay = (txs_signed * son_weight * son_budget.value)/weighted_total_txs_signed;
modify( *son_obj, [&]( son_object& _son_obj)
{
_son_obj.pay_son_fee(pay, *this);
});
// Remove the amount paid out to SON from global SON Budget
modify(dpo, [&](dynamic_global_property_object &_dpo) {
_dpo.son_budget -= pay;
});
// Reset the tx counter in each son statistics object
modify(s, [&](son_statistics_object &_s) {
if (_s.txs_signed.contains(active_sidechain_type))
//Remove the amount paid out to SON from global SON Budget
modify( dpo, [&]( dynamic_global_property_object& _dpo )
{
_dpo.son_budget -= pay;
} );
//Reset the tx counter in each son statistics object
modify( s, [&]( son_statistics_object& _s)
{
if(_s.txs_signed.contains(active_sidechain_type))
_s.txs_signed.at(active_sidechain_type) = 0;
});
}
}
});
//Note the last son pay out time
modify( dpo, [&]( dynamic_global_property_object& _dpo )
{
_dpo.last_son_payout_time = now;
});
});
//Note the last son pay out time
modify( dpo, [&]( dynamic_global_property_object& _dpo )
{
_dpo.last_son_payout_time = now;
});
}
}
}
void database::update_son_metrics(const flat_map<sidechain_type, vector<son_sidechain_info> >& curr_active_sons)
void database::update_son_metrics(const flat_map<sidechain_type, vector<son_info> >& curr_active_sons)
{
for(const auto& curr_active_sidechain_sons : curr_active_sons) {
const auto& sidechain = curr_active_sidechain_sons.first;
@ -408,7 +295,7 @@ void database::update_son_metrics(const flat_map<sidechain_type, vector<son_side
current_sons.reserve(_curr_active_sidechain_sons.size());
std::transform(_curr_active_sidechain_sons.cbegin(), _curr_active_sidechain_sons.cend(),
std::inserter(current_sons, current_sons.end()),
[](const son_sidechain_info &swi) {
[](const son_info &swi) {
return swi.son_id;
});
@ -420,10 +307,7 @@ void database::update_son_metrics(const flat_map<sidechain_type, vector<son_side
if (is_active_son) {
_stats.total_voted_time[sidechain] = _stats.total_voted_time[sidechain] + get_global_properties().parameters.maintenance_interval;
}
if(!_stats.current_interval_downtime.contains(sidechain))
_stats.current_interval_downtime[sidechain] = 0;
_stats.total_downtime[sidechain] += _stats.current_interval_downtime.at(sidechain);
_stats.total_downtime[sidechain] += _stats.current_interval_downtime[sidechain];
_stats.current_interval_downtime[sidechain] = 0;
_stats.sidechain_txs_reported[sidechain] = 0;
});
@ -431,8 +315,8 @@ void database::update_son_metrics(const flat_map<sidechain_type, vector<son_side
}
}
void database::update_son_statuses( const flat_map<sidechain_type, vector<son_sidechain_info> >& curr_active_sons,
const flat_map<sidechain_type, vector<son_sidechain_info> >& new_active_sons )
void database::update_son_statuses( const flat_map<sidechain_type, vector<son_info> >& curr_active_sons,
const flat_map<sidechain_type, vector<son_info> >& new_active_sons )
{
for(const auto& new_active_sidechain_sons : new_active_sons) {
const auto& sidechain = new_active_sidechain_sons.first;
@ -445,7 +329,7 @@ void database::update_son_statuses( const flat_map<sidechain_type, vector<son_si
current_sons.reserve(curr_active_sons.at(sidechain).size());
std::transform(curr_active_sons.at(sidechain).cbegin(), curr_active_sons.at(sidechain).cend(),
std::inserter(current_sons, current_sons.end()),
[](const son_sidechain_info &swi) {
[](const son_info &swi) {
return swi.son_id;
});
}
@ -453,7 +337,7 @@ void database::update_son_statuses( const flat_map<sidechain_type, vector<son_si
new_sons.reserve(new_active_sons.at(sidechain).size());
std::transform(new_active_sons.at(sidechain).cbegin(), new_active_sons.at(sidechain).cend(),
std::inserter(new_sons, new_sons.end()),
[](const son_sidechain_info &swi) {
[](const son_info &swi) {
return swi.son_id;
});
@ -489,7 +373,7 @@ void database::update_son_statuses( const flat_map<sidechain_type, vector<son_si
for (const auto &sid : sons_to_add) {
auto son = idx.find(sid);
FC_ASSERT(son != idx.end(), "Invalid SON in active list, id = ${sonid}.", ("sonid", sid));
FC_ASSERT(son != idx.end(), "Invalid SON in active list, id={sonid}.", ("sonid", sid));
// keep maintenance status for new nodes
if (son->statuses.at(sidechain) == son_status::inactive) {
modify(*son, [&](son_object &obj) {
@ -524,7 +408,7 @@ void database::update_son_statuses( const flat_map<sidechain_type, vector<son_si
}
}
void database::update_son_wallet(const flat_map<sidechain_type, vector<son_sidechain_info> >& new_active_sons)
void database::update_son_wallet(const flat_map<sidechain_type, vector<son_info> >& new_active_sons)
{
bool should_recreate_pw = true;
@ -833,28 +717,43 @@ void database::update_active_sons()
}
assert( _son_count_histogram_buffer.size() > 0 );
#ifndef NDEBUG
for( const auto& son_count_histogram_buffer : _son_count_histogram_buffer ){
assert( son_count_histogram_buffer.second.size() > 0 );
}
#endif
const auto supported_active_sidechain_types = active_sidechain_types(head_block_time());
flat_map<sidechain_type, size_t> son_count;
for(const auto& active_sidechain_type : supported_active_sidechain_types)
{
const share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer.at(active_sidechain_type)[0]) / 2;
const flat_map<sidechain_type, share_type> stake_target = [this]{
flat_map<sidechain_type, share_type> stake_target;
for( const auto& son_count_histogram_buffer : _son_count_histogram_buffer ){
const auto sidechain = son_count_histogram_buffer.first;
stake_target[sidechain] = (_total_voting_stake-son_count_histogram_buffer.second[0]) / 2;
}
return stake_target;
}();
/// accounts that vote for 0 or 1 son do not get to express an opinion on
/// the number of sons to have (they abstain and are non-voting accounts)
share_type stake_tally = 0;
son_count[active_sidechain_type] = 0;
if( stake_target > 0 )
/// accounts that vote for 0 or 1 son do not get to express an opinion on
/// the number of sons to have (they abstain and are non-voting accounts)
flat_map<sidechain_type, share_type> stake_tally = []{
flat_map<sidechain_type, share_type> stake_tally;
for(const auto& active_sidechain_type : active_sidechain_types){
stake_tally[active_sidechain_type] = 0;
}
return stake_tally;
}();
flat_map<sidechain_type, size_t> son_count = []{
flat_map<sidechain_type, size_t> son_count;
for(const auto& active_sidechain_type : active_sidechain_types){
son_count[active_sidechain_type] = 0;
}
return son_count;
}();
for( const auto& stake_target_sidechain : stake_target ){
const auto sidechain = stake_target_sidechain.first;
if( stake_target_sidechain.second > 0 )
{
while( (son_count.at(active_sidechain_type) < _son_count_histogram_buffer.at(active_sidechain_type).size() - 1)
&& (stake_tally <= stake_target) )
while( (son_count[sidechain] < _son_count_histogram_buffer.at(sidechain).size() - 1)
&& (stake_tally[sidechain] <= stake_target_sidechain.second) )
{
stake_tally += _son_count_histogram_buffer.at(active_sidechain_type)[ ++son_count[active_sidechain_type] ];
stake_tally[sidechain] += _son_count_histogram_buffer.at(sidechain)[ ++son_count[sidechain] ];
}
}
}
@ -863,17 +762,18 @@ void database::update_active_sons()
const chain_property_object& cpo = get_chain_properties();
const auto& all_sons = get_index_type<son_index>().indices();
flat_map<sidechain_type, vector<std::reference_wrapper<const son_object> > > sons;
for(const auto& active_sidechain_type : supported_active_sidechain_types)
for(const auto& active_sidechain_type : active_sidechain_types)
{
if(head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME) {
if(head_block_time() >= HARDFORK_SON3_TIME) {
sons[active_sidechain_type] = sort_votable_objects<son_index>(active_sidechain_type,
(std::max(son_count.at(active_sidechain_type) * 2 + 1, (size_t)cpo.immutable_parameters.min_son_count)));
}
else {
sons[active_sidechain_type] = sort_votable_objects<son_index>(sidechain_type::bitcoin, get_global_properties().parameters.maximum_son_count());
sons[active_sidechain_type] = sort_votable_objects<son_index>(active_sidechain_type, get_global_properties().parameters.maximum_son_count());
}
}
auto& local_vote_buffer_ref = _vote_tally_buffer;
for( const son_object& son : all_sons )
{
for(const auto& status: son.statuses)
@ -888,9 +788,9 @@ void database::update_active_sons()
}
}
modify( son, [this]( son_object& obj ){
modify( son, [local_vote_buffer_ref]( son_object& obj ){
for(const auto& sidechain_vote_id : obj.sidechain_vote_ids ){
obj.total_votes[sidechain_vote_id.first] = _vote_tally_buffer.size() > sidechain_vote_id.second ? _vote_tally_buffer[sidechain_vote_id.second] : 0;
obj.total_votes[sidechain_vote_id.first] = local_vote_buffer_ref[sidechain_vote_id.second];
}
for(auto& status: obj.statuses)
{
@ -945,7 +845,7 @@ void database::update_active_sons()
// Compare current and to-be lists of active sons
const auto cur_active_sons = gpo.active_sons;
flat_map<sidechain_type, vector<son_sidechain_info> > new_active_sons;
flat_map<sidechain_type, vector<son_info> > new_active_sons;
const auto &acc = get(gpo.parameters.son_account());
for( const auto& sidechain_sons : sons ){
const auto& sidechain = sidechain_sons.first;
@ -953,12 +853,11 @@ void database::update_active_sons()
new_active_sons[sidechain].reserve(sons_array.size());
for( const son_object& son : sons_array ) {
son_sidechain_info swi;
son_info swi;
swi.son_id = son.id;
swi.weight = acc.active.account_auths.at(son.son_account);
swi.signing_key = son.signing_key;
if (son.sidechain_public_keys.find(sidechain) != son.sidechain_public_keys.end())
swi.public_key = son.sidechain_public_keys.at(sidechain);
swi.public_key = son.sidechain_public_keys.at(sidechain);
new_active_sons[sidechain].push_back(swi);
}
}
@ -998,7 +897,7 @@ void database::update_active_sons()
}
});
for(const auto& active_sidechain_type : supported_active_sidechain_types)
for(const auto& active_sidechain_type : active_sidechain_types)
{
const son_schedule_object& sidechain_sso = son_schedule_id_type(get_son_schedule_id(active_sidechain_type))(*this);
modify(sidechain_sso, [&](son_schedule_object& _sso)
@ -1007,13 +906,12 @@ void database::update_active_sons()
active_sons.reserve(gpo.active_sons.at(active_sidechain_type).size());
std::transform(gpo.active_sons.at(active_sidechain_type).cbegin(), gpo.active_sons.at(active_sidechain_type).cend(),
std::inserter(active_sons, active_sons.end()),
[](const son_sidechain_info& swi) {
[](const son_info& swi) {
return swi.son_id;
});
_sso.scheduler.update(active_sons);
// similar to witness, produce schedule for sons
if( ((cur_active_sons.contains(active_sidechain_type) && cur_active_sons.at(active_sidechain_type).size() == 0) ||
!cur_active_sons.contains(active_sidechain_type)) && new_active_sons.at(active_sidechain_type).size() > 0 )
if(cur_active_sons.at(active_sidechain_type).size() == 0 && new_active_sons.at(active_sidechain_type).size() > 0)
{
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
for( size_t i=0; i<new_active_sons.at(active_sidechain_type).size(); ++i )
@ -1560,19 +1458,17 @@ void rolling_period_start(database& db)
{
if(db.head_block_time() >= HARDFORK_GPOS_TIME)
{
const auto gpo = db.get_global_properties();
auto gpo = db.get_global_properties();
auto period_start = db.get_global_properties().parameters.gpos_period_start();
const auto vesting_period = db.get_global_properties().parameters.gpos_period();
auto vesting_period = db.get_global_properties().parameters.gpos_period();
const auto now = db.head_block_time();
while(now.sec_since_epoch() >= (period_start + vesting_period))
auto now = db.head_block_time();
if(now.sec_since_epoch() >= (period_start + vesting_period))
{
// roll
db.modify(db.get_global_properties(), [period_start, vesting_period](global_property_object& p) {
p.parameters.extensions.value.gpos_period_start = period_start + vesting_period;
});
period_start = db.get_global_properties().parameters.gpos_period_start();
}
}
}
@ -2148,7 +2044,7 @@ void database::perform_son_tasks()
});
}
// create BTC asset here because son_account is the issuer of the BTC
if (gpo.parameters.btc_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_TIME)
if (gpo.parameters.btc_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_TIME)
{
const asset_dynamic_data_object& dyn_asset =
create<asset_dynamic_data_object>([](asset_dynamic_data_object& a) {
@ -2167,7 +2063,7 @@ void database::perform_son_tasks()
asset_issuer_permission_flags::override_authority;
a.options.core_exchange_rate.base.amount = 100000;
a.options.core_exchange_rate.base.asset_id = asset_id_type(0);
a.options.core_exchange_rate.quote.amount = 2500;
a.options.core_exchange_rate.quote.amount = 2500; // CoinMarketCap approx value
a.options.core_exchange_rate.quote.asset_id = a.id;
a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty
a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set
@ -2181,42 +2077,8 @@ void database::perform_son_tasks()
gpo.pending_parameters->extensions.value.btc_asset = btc_asset.get_id();
});
}
// create ETH asset here because son_account is the issuer of the ETH
if (gpo.parameters.eth_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME)
{
const asset_dynamic_data_object& dyn_asset =
create<asset_dynamic_data_object>([](asset_dynamic_data_object& a) {
a.current_supply = 0;
});
const asset_object& eth_asset =
create<asset_object>( [&gpo, &dyn_asset]( asset_object& a ) {
a.symbol = "ETH";
a.precision = 8;
a.issuer = gpo.parameters.son_account();
a.options.max_supply = GRAPHENE_MAX_SHARE_SUPPLY;
a.options.market_fee_percent = 500; // 5%
a.options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK;
a.options.flags = asset_issuer_permission_flags::charge_market_fee |
asset_issuer_permission_flags::override_authority;
a.options.core_exchange_rate.base.amount = 100000;
a.options.core_exchange_rate.base.asset_id = asset_id_type(0);
a.options.core_exchange_rate.quote.amount = 2500;
a.options.core_exchange_rate.quote.asset_id = a.id;
a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty
a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set
a.options.whitelist_markets.clear(); // might be traded with
a.options.blacklist_markets.clear(); // might not be traded with
a.dynamic_asset_data_id = dyn_asset.id;
});
modify( gpo, [&eth_asset]( global_property_object& gpo ) {
gpo.parameters.extensions.value.eth_asset = eth_asset.get_id();
if( gpo.pending_parameters )
gpo.pending_parameters->extensions.value.eth_asset = eth_asset.get_id();
});
}
// create HBD asset here because son_account is the issuer of the HBD
if (gpo.parameters.hbd_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME)
if (gpo.parameters.hbd_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME)
{
const asset_dynamic_data_object& dyn_asset =
create<asset_dynamic_data_object>([](asset_dynamic_data_object& a) {
@ -2235,7 +2097,7 @@ void database::perform_son_tasks()
asset_issuer_permission_flags::override_authority;
a.options.core_exchange_rate.base.amount = 100000;
a.options.core_exchange_rate.base.asset_id = asset_id_type(0);
a.options.core_exchange_rate.quote.amount = 2500;
a.options.core_exchange_rate.quote.amount = 2500; // CoinMarketCap approx value
a.options.core_exchange_rate.quote.asset_id = a.id;
a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty
a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set
@ -2250,7 +2112,7 @@ void database::perform_son_tasks()
});
}
// create HIVE asset here because son_account is the issuer of the HIVE
if (gpo.parameters.hive_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME)
if (gpo.parameters.hive_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME)
{
const asset_dynamic_data_object& dyn_asset =
create<asset_dynamic_data_object>([](asset_dynamic_data_object& a) {
@ -2269,7 +2131,7 @@ void database::perform_son_tasks()
asset_issuer_permission_flags::override_authority;
a.options.core_exchange_rate.base.amount = 100000;
a.options.core_exchange_rate.base.asset_id = asset_id_type(0);
a.options.core_exchange_rate.quote.amount = 2500;
a.options.core_exchange_rate.quote.amount = 2500; // CoinMarketCap approx value
a.options.core_exchange_rate.quote.asset_id = a.id;
a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty
a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set
@ -2283,69 +2145,26 @@ void database::perform_son_tasks()
gpo.pending_parameters->extensions.value.hive_asset = hive_asset.get_id();
});
}
// Pay the SONs
if (head_block_time() >= HARDFORK_SON_TIME)
{
// Before making a budget we should pay out SONs
// This function should check if its time to pay sons
// and modify the global son funds accordingly, whatever is left is passed on to next budget
if(head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME)
pay_sons_before_hf_ethereum();
else
pay_sons_after_hf_ethereum();
}
// Split vote_ids
if (head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME) {
// Get SON 1.33.0 and check if it has HIVE vote_id
const son_id_type sid = son_id_type(0);
const auto p_son = find(sid);
if(p_son != nullptr) {
if (p_son->sidechain_vote_ids.find(sidechain_type::hive) == p_son->sidechain_vote_ids.end()) {
// Add vote_ids for HIVE and ETHEREUM to all existing SONs
const auto &all_sons = get_index_type<son_index>().indices().get<by_id>();
for (const son_object &son : all_sons) {
const auto existing_vote_id_bitcoin = son.get_bitcoin_vote_id();
vote_id_type new_vote_id_hive;
vote_id_type new_vote_id_eth;
modify(gpo, [&new_vote_id_hive, &new_vote_id_eth](global_property_object &p) {
new_vote_id_hive = get_next_vote_id(p, vote_id_type::son_hive);
new_vote_id_eth = get_next_vote_id(p, vote_id_type::son_ethereum);
});
modify(son, [new_vote_id_hive, new_vote_id_eth](son_object &obj) {
obj.sidechain_vote_ids[sidechain_type::hive] = new_vote_id_hive;
obj.sidechain_vote_ids[sidechain_type::ethereum] = new_vote_id_eth;
});
// Duplicate all votes from bitcoin to hive
const auto &all_accounts = get_index_type<account_index>().indices().get<by_id>();
for (const auto &account : all_accounts) {
if (existing_vote_id_bitcoin.valid() && account.options.votes.count(*existing_vote_id_bitcoin) != 0) {
modify(account, [new_vote_id_hive](account_object &a) {
a.options.votes.insert(new_vote_id_hive);
});
}
}
}
}
}
pay_sons();
}
}
void update_son_params(database& db)
{
if( (db.head_block_time() >= HARDFORK_SON2_TIME) && (db.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME) )
if( (db.head_block_time() >= HARDFORK_SON2_TIME) && (db.head_block_time() < HARDFORK_SON3_TIME) )
{
const auto& gpo = db.get_global_properties();
db.modify( gpo, []( global_property_object& gpo ) {
gpo.parameters.extensions.value.maximum_son_count = 7;
});
}
if( (db.head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME) )
else
{
const auto& gpo = db.get_global_properties();
db.modify( gpo, []( global_property_object& gpo ) {
@ -2480,23 +2299,20 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
// same rationale as for witnesses
d._committee_count_histogram_buffer[offset] += voting_stake;
}
if ( opinion_account.options.extensions.value.num_son.valid() )
{
for(const auto& num_sidechain_son : *opinion_account.options.extensions.value.num_son) {
const auto sidechain = num_sidechain_son.first;
const auto& num_son = num_sidechain_son.second;
if (num_son <= props.parameters.maximum_son_count()) {
uint16_t offset = std::min(size_t(num_son / 2),
d._son_count_histogram_buffer.at(sidechain).size() - 1);
// votes for a number greater than maximum_son_count
// are turned into votes for maximum_son_count.
//
// in particular, this takes care of the case where a
// member was voting for a high number, then the
// parameter was lowered.
d._son_count_histogram_buffer.at(sidechain)[offset] += voting_stake;
}
FC_ASSERT( opinion_account.options.extensions.value.num_son.valid() , "Invalid son number" );
for(const auto& num_sidechain_son : *opinion_account.options.extensions.value.num_son) {
const auto sidechain = num_sidechain_son.first;
const auto& num_son = num_sidechain_son.second;
if (num_son <= props.parameters.maximum_son_count()) {
uint16_t offset = std::min(size_t(num_son / 2),
d._son_count_histogram_buffer.at(sidechain).size() - 1);
// votes for a number greater than maximum_son_count
// are turned into votes for maximum_son_count.
//
// in particular, this takes care of the case where a
// member was voting for a high number, then the
// parameter was lowered.
d._son_count_histogram_buffer.at(sidechain)[offset] += voting_stake;
}
}
@ -2533,7 +2349,6 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
update_active_committee_members();
update_active_sons();
update_worker_votes();
hotfix_2024();
const dynamic_global_property_object& dgpo = get_dynamic_global_properties();
@ -2598,17 +2413,14 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset;
if( !p.pending_parameters->extensions.value.hive_asset.valid() )
p.pending_parameters->extensions.value.hive_asset = p.parameters.extensions.value.hive_asset;
if( !p.pending_parameters->extensions.value.eth_asset.valid() )
p.pending_parameters->extensions.value.eth_asset = p.parameters.extensions.value.eth_asset;
// the following parameters are not allowed to be changed. So take what is in global property
p.pending_parameters->extensions.value.gpos_period_start = p.parameters.extensions.value.gpos_period_start;
p.pending_parameters->extensions.value.son_account = p.parameters.extensions.value.son_account;
p.pending_parameters->extensions.value.btc_asset = p.parameters.extensions.value.btc_asset;
p.pending_parameters->extensions.value.maximum_son_count = p.parameters.extensions.value.maximum_son_count;
p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset;
p.pending_parameters->extensions.value.hive_asset = p.parameters.extensions.value.hive_asset;
p.pending_parameters->extensions.value.eth_asset = p.parameters.extensions.value.eth_asset;
p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset;
p.pending_parameters->extensions.value.maximum_son_count = p.parameters.extensions.value.maximum_son_count;
p.pending_parameters->extensions.value.btc_asset = p.parameters.extensions.value.btc_asset;
p.pending_parameters->extensions.value.son_account = p.parameters.extensions.value.son_account;
p.pending_parameters->extensions.value.gpos_period_start = p.parameters.extensions.value.gpos_period_start;
p.parameters = std::move(*p.pending_parameters);
p.pending_parameters.reset();

View file

@ -77,9 +77,8 @@ witness_id_type database::get_scheduled_witness( uint32_t slot_num )const
unsigned_int database::get_son_schedule_id( sidechain_type type )const
{
static const map<sidechain_type, unsigned_int> schedule_map = {
{ sidechain_type::bitcoin, 0 },
{ sidechain_type::ethereum, 1 },
{ sidechain_type::hive, 2 }
{ sidechain_type::hive, 0 },
{ sidechain_type::bitcoin, 1 }
};
return schedule_map.at(type);
@ -200,41 +199,43 @@ void database::update_witness_schedule()
}
}
void database::update_son_schedule(sidechain_type type)
void database::update_son_schedule()
{
const global_property_object& gpo = get_global_properties();
const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(type)));
if( gpo.active_sons.at(type).size() != 0 &&
head_block_num() % gpo.active_sons.at(type).size() == 0)
for(const auto& active_sidechain_type : active_sidechain_types)
{
modify( sidechain_sso, [&]( son_schedule_object& _sso )
const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(active_sidechain_type)));
if( head_block_num() % gpo.active_sons.at(active_sidechain_type).size() == 0)
{
_sso.current_shuffled_sons.clear();
_sso.current_shuffled_sons.reserve( gpo.active_sons.at(type).size() );
for ( const auto &w : gpo.active_sons.at(type) ) {
_sso.current_shuffled_sons.push_back(w.son_id);
}
auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32;
for (uint32_t i = 0; i < _sso.current_shuffled_sons.size(); ++i)
modify( sidechain_sso, [&]( son_schedule_object& _sso )
{
/// High performance random generator
/// http://xorshift.di.unimi.it/
uint64_t k = now_hi + uint64_t(i) * 2685821657736338717ULL;
k ^= (k >> 12);
k ^= (k << 25);
k ^= (k >> 27);
k *= 2685821657736338717ULL;
_sso.current_shuffled_sons.clear();
_sso.current_shuffled_sons.reserve( gpo.active_sons.at(active_sidechain_type).size() );
uint32_t jmax = _sso.current_shuffled_sons.size() - i;
uint32_t j = i + k % jmax;
std::swap(_sso.current_shuffled_sons[i],
_sso.current_shuffled_sons[j]);
}
});
for ( const son_info &w : gpo.active_sons.at(active_sidechain_type) ) {
_sso.current_shuffled_sons.push_back(w.son_id);
}
auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32;
for (uint32_t i = 0; i < _sso.current_shuffled_sons.size(); ++i)
{
/// High performance random generator
/// http://xorshift.di.unimi.it/
uint64_t k = now_hi + uint64_t(i) * 2685821657736338717ULL;
k ^= (k >> 12);
k ^= (k << 25);
k ^= (k >> 27);
k *= 2685821657736338717ULL;
uint32_t jmax = _sso.current_shuffled_sons.size() - i;
uint32_t j = i + k % jmax;
std::swap(_sso.current_shuffled_sons[i],
_sso.current_shuffled_sons[j]);
}
});
}
}
}
@ -318,15 +319,21 @@ void database::update_witness_schedule(const signed_block& next_block)
idump( ( double(total_time/1000000.0)/calls) );
}
void database::update_son_schedule(sidechain_type type, const signed_block& next_block)
void database::update_son_schedule(const signed_block& next_block)
{
auto start = fc::time_point::now();
#ifndef NDEBUG
const son_schedule_object& sso = get(son_schedule_id_type());
#endif
const global_property_object& gpo = get_global_properties();
const uint32_t schedule_needs_filled = gpo.active_sons.at(type).size();
const uint32_t schedule_slot = get_slot_at_time(next_block.timestamp);
const son_schedule_object& sso = get(son_schedule_id_type());
const flat_map<sidechain_type, uint32_t> schedule_needs_filled = [&gpo]()
{
flat_map<sidechain_type, uint32_t> schedule_needs_filled;
for(const auto& sidechain_active_sons : gpo.active_sons)
{
schedule_needs_filled[sidechain_active_sons.first] = sidechain_active_sons.second.size();
}
return schedule_needs_filled;
}();
uint32_t schedule_slot = get_slot_at_time(next_block.timestamp);
// We shouldn't be able to generate _pending_block with timestamp
// in the past, and incoming blocks from the network with timestamp
@ -340,43 +347,46 @@ void database::update_son_schedule(sidechain_type type, const signed_block& next
assert( dpo.random.data_size() == witness_scheduler_rng::seed_length );
assert( witness_scheduler_rng::seed_length == sso.rng_seed.size() );
const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(type)));
son_id_type first_son;
bool slot_is_near = sidechain_sso.scheduler.get_slot( schedule_slot-1, first_son );
son_id_type son_id;
modify(sidechain_sso, [&](son_schedule_object& _sso)
for(const auto& active_sidechain_type : active_sidechain_types)
{
_sso.slots_since_genesis += schedule_slot;
witness_scheduler_rng rng(_sso.rng_seed.data, _sso.slots_since_genesis);
const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(active_sidechain_type)));
son_id_type first_son;
bool slot_is_near = sidechain_sso.scheduler.get_slot( schedule_slot-1, first_son );
son_id_type son_id;
_sso.scheduler._min_token_count = std::max(int(gpo.active_sons.at(type).size()) / 2, 1);
modify(sidechain_sso, [&](son_schedule_object& _sso)
{
_sso.slots_since_genesis += schedule_slot;
witness_scheduler_rng rng(_sso.rng_seed.data, _sso.slots_since_genesis);
if( slot_is_near )
{
uint32_t drain = schedule_slot;
while( drain > 0 )
_sso.scheduler._min_token_count = std::max(int(gpo.active_sons.at(active_sidechain_type).size()) / 2, 1);
if( slot_is_near )
{
if( _sso.scheduler.size() == 0 )
break;
_sso.scheduler.consume_schedule();
--drain;
uint32_t drain = schedule_slot;
while( drain > 0 )
{
if( _sso.scheduler.size() == 0 )
break;
_sso.scheduler.consume_schedule();
--drain;
}
}
}
else
{
_sso.scheduler.reset_schedule( first_son );
}
while( !_sso.scheduler.get_slot(schedule_needs_filled, son_id) )
{
if( _sso.scheduler.produce_schedule(rng) & emit_turn )
memcpy(_sso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size());
}
_sso.last_scheduling_block = next_block.block_num();
_sso.recent_slots_filled = (
(_sso.recent_slots_filled << 1)
+ 1) << (schedule_slot - 1);
});
else
{
_sso.scheduler.reset_schedule( first_son );
}
while( !_sso.scheduler.get_slot(schedule_needs_filled.at(active_sidechain_type), son_id) )
{
if( _sso.scheduler.produce_schedule(rng) & emit_turn )
memcpy(_sso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size());
}
_sso.last_scheduling_block = next_block.block_num();
_sso.recent_slots_filled = (
(_sso.recent_slots_filled << 1)
+ 1) << (schedule_slot - 1);
});
}
auto end = fc::time_point::now();
static uint64_t total_time = 0;

View file

@ -1,7 +0,0 @@
#ifndef HARDFORK_HOTFIX_2024_TIME
#ifdef BUILD_PEERPLAYS_TESTNET
#define HARDFORK_HOTFIX_2024_TIME (fc::time_point_sec::from_iso_string("2023-12-20T00:00:00"))
#else
#define HARDFORK_HOTFIX_2024_TIME (fc::time_point_sec::from_iso_string("2023-12-20T00:00:00"))
#endif
#endif

View file

@ -1,7 +0,0 @@
#ifndef HARDFORK_SIDECHAIN_DELETE_TIME
#ifdef BUILD_PEERPLAYS_TESTNET
#define HARDFORK_SIDECHAIN_DELETE_TIME (fc::time_point_sec::from_iso_string("2022-11-16T02:00:00"))
#else
#define HARDFORK_SIDECHAIN_DELETE_TIME (fc::time_point_sec::from_iso_string("2022-11-16T02:00:00"))
#endif
#endif

View file

@ -0,0 +1,7 @@
#ifndef HARDFORK_SON3_TIME
#ifdef BUILD_PEERPLAYS_TESTNET
#define HARDFORK_SON3_TIME (fc::time_point_sec::from_iso_string("2022-07-16T00:00:00"))
#else
#define HARDFORK_SON3_TIME (fc::time_point_sec::from_iso_string("2022-07-16T00:00:00"))
#endif
#endif

View file

@ -1,7 +0,0 @@
#ifndef HARDFORK_SON_FOR_ETHEREUM_TIME
#ifdef BUILD_PEERPLAYS_TESTNET
#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2023-07-17T12:00:00"))
#else
#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2023-10-24T12:00:00"))
#endif
#endif

View file

@ -158,7 +158,7 @@
#define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4
#define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3
#define GRAPHENE_CURRENT_DB_VERSION "PPY2.5"
#define GRAPHENE_CURRENT_DB_VERSION "PPY2.4"
#define GRAPHENE_IRREVERSIBLE_THRESHOLD (70 * GRAPHENE_1_PERCENT)

View file

@ -292,8 +292,8 @@ namespace graphene { namespace chain {
vector<witness_id_type> get_near_witness_schedule()const;
void update_witness_schedule();
void update_witness_schedule(const signed_block& next_block);
void update_son_schedule(sidechain_type type);
void update_son_schedule(sidechain_type type, const signed_block& next_block);
void update_son_schedule();
void update_son_schedule(const signed_block& next_block);
void check_lottery_end_by_participants( asset_id_type asset_id );
void check_ending_lotteries();
@ -520,7 +520,6 @@ namespace graphene { namespace chain {
void notify_changed_objects();
private:
std::mutex _pending_tx_session_mutex;
optional<undo_database::session> _pending_tx_session;
vector< unique_ptr<op_evaluator> > _operation_evaluators;
@ -579,22 +578,20 @@ namespace graphene { namespace chain {
void initialize_budget_record( fc::time_point_sec now, budget_record& rec )const;
void process_budget();
void pay_workers( share_type& budget );
void pay_sons_before_hf_ethereum();
void pay_sons_after_hf_ethereum();
void pay_sons();
void perform_son_tasks();
void perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props);
void update_active_witnesses();
void update_active_committee_members();
void update_son_metrics( const flat_map<sidechain_type, vector<son_sidechain_info> >& curr_active_sons );
void update_son_metrics( const flat_map<sidechain_type, vector<son_info> >& curr_active_sons );
void update_active_sons();
void remove_son_proposal( const proposal_object& proposal );
void remove_inactive_son_down_proposals( const vector<son_id_type>& son_ids_to_remove );
void remove_inactive_son_proposals( const vector<son_id_type>& son_ids_to_remove );
void update_son_statuses( const flat_map<sidechain_type, vector<son_sidechain_info> >& curr_active_sons,
const flat_map<sidechain_type, vector<son_sidechain_info> >& new_active_sons );
void update_son_wallet( const flat_map<sidechain_type, vector<son_sidechain_info> >& new_active_sons );
void update_son_statuses( const flat_map<sidechain_type, vector<son_info> >& curr_active_sons,
const flat_map<sidechain_type, vector<son_info> >& new_active_sons );
void update_son_wallet( const flat_map<sidechain_type, vector<son_info> >& new_active_sons );
void update_worker_votes();
void hotfix_2024();
public:
double calculate_vesting_factor(const account_object& stake_account);
@ -605,7 +602,6 @@ namespace graphene { namespace chain {
///@}
///@}
std::mutex _pending_tx_mutex;
vector< processed_transaction > _pending_tx;
fork_database _fork_db;
@ -638,7 +634,7 @@ namespace graphene { namespace chain {
vector<uint64_t> _committee_count_histogram_buffer;
flat_map<sidechain_type, vector<uint64_t> > _son_count_histogram_buffer = []{
flat_map<sidechain_type, vector<uint64_t> > son_count_histogram_buffer;
for(const auto& active_sidechain_type : all_sidechain_types){
for(const auto& active_sidechain_type : active_sidechain_types){
son_count_histogram_buffer[active_sidechain_type] = vector<uint64_t>{};
}
return son_count_histogram_buffer;

View file

@ -182,9 +182,6 @@ namespace graphene { namespace chain {
GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( override_transfer );
GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( not_permitted, override_transfer, 1, "not permitted" )
GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( blind_transfer );
GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( unknown_commitment, blind_transfer, 1, "Attempting to claim an unknown prior commitment" );
/*
FC_DECLARE_DERIVED_EXCEPTION( addition_overflow, graphene::chain::chain_exception, 30002, "addition overflow" )
FC_DECLARE_DERIVED_EXCEPTION( subtraction_overflow, graphene::chain::chain_exception, 30003, "subtraction overflow" )

View file

@ -27,7 +27,7 @@
#include <graphene/chain/protocol/chain_parameters.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/son_sidechain_info.hpp>
#include <graphene/chain/son_info.hpp>
#include <graphene/db/object.hpp>
namespace graphene { namespace chain {
@ -49,15 +49,15 @@ namespace graphene { namespace chain {
chain_parameters parameters;
optional<chain_parameters> pending_parameters;
uint32_t next_available_vote_id = 0;
vector<committee_member_id_type> active_committee_members; // updated once per maintenance interval
flat_set<witness_id_type> active_witnesses; // updated once per maintenance interval
flat_map<sidechain_type, vector<son_sidechain_info> > active_sons = []() // updated once per maintenance interval
uint32_t next_available_vote_id = 0;
vector<committee_member_id_type> active_committee_members; // updated once per maintenance interval
flat_set<witness_id_type> active_witnesses; // updated once per maintenance interval
flat_map<sidechain_type, vector<son_info> > active_sons = []() // updated once per maintenance interval
{
flat_map<sidechain_type, vector<son_sidechain_info> > active_sons;
for(const auto& active_sidechain_type : all_sidechain_types)
flat_map<sidechain_type, vector<son_info> > active_sons;
for(const auto& active_sidechain_type : active_sidechain_types)
{
active_sons[active_sidechain_type] = vector<son_sidechain_info>();
active_sons[active_sidechain_type] = vector<son_info>();
}
return active_sons;
}();

View file

@ -130,9 +130,6 @@ namespace graphene { namespace chain {
std::greater< uint32_t >,
std::greater< object_id_type >
>
>,
ordered_non_unique< tag<by_owner>,
member<nft_metadata_object, account_id_type, &nft_metadata_object::owner>
>
>
>;

View file

@ -36,28 +36,21 @@ namespace graphene { namespace chain {
bool is_cheap_name( const string& n );
/// These are the fields which can be updated by the active authority.
struct account_options
struct account_options
{
struct ext
{
/// The number of active son members this account votes the blockchain should appoint
/// Must not exceed the actual number of son members voted for in @ref votes
optional< flat_map<sidechain_type, uint16_t> > num_son;
/// Returns and empty num_son map with all sidechains
static flat_map<sidechain_type, uint16_t> empty_num_son()
{
optional< flat_map<sidechain_type, uint16_t> > num_son = []{
flat_map<sidechain_type, uint16_t> num_son;
for(const auto& active_sidechain_type : all_sidechain_types)
{
for(const auto& active_sidechain_type : active_sidechain_types){
num_son[active_sidechain_type] = 0;
}
return num_son;
}
}();
};
/// The memo key is the key this account will typically use to encrypt/sign transaction memos and other non-
/// validated account activities. This field is here to prevent confusion if the active authority has zero or
/// multiple keys in it.

View file

@ -70,7 +70,6 @@ namespace graphene { namespace chain {
optional < uint16_t > maximum_son_count = GRAPHENE_DEFAULT_MAX_SONS; ///< maximum number of active SONS
optional < asset_id_type > hbd_asset = asset_id_type();
optional < asset_id_type > hive_asset = asset_id_type();
optional < asset_id_type > eth_asset = asset_id_type();
};
struct chain_parameters
@ -221,9 +220,6 @@ namespace graphene { namespace chain {
inline asset_id_type hive_asset() const {
return extensions.value.hive_asset.valid() ? *extensions.value.hive_asset : asset_id_type();
}
inline asset_id_type eth_asset() const {
return extensions.value.eth_asset.valid() ? *extensions.value.eth_asset : asset_id_type();
}
private:
static void safe_copy(chain_parameters& to, const chain_parameters& from);
};
@ -261,7 +257,6 @@ FC_REFLECT( graphene::chain::parameter_extension,
(maximum_son_count)
(hbd_asset)
(hive_asset)
(eth_asset)
)
FC_REFLECT( graphene::chain::chain_parameters,

View file

@ -158,7 +158,9 @@ struct transfer_to_blind_operation : public base_operation
blind_factor_type blinding_factor;
vector<blind_output> outputs;
account_id_type fee_payer()const { return from; }
account_id_type fee_payer()const { return account_id_type{}; }
//account_id_type fee_payer()const { return from; }
//void validate()const;
//share_type calculate_fee(const fee_parameters_type& )const;
};
@ -179,7 +181,9 @@ struct transfer_from_blind_operation : public base_operation
blind_factor_type blinding_factor;
vector<blind_input> inputs;
account_id_type fee_payer()const { return GRAPHENE_TEMP_ACCOUNT; }
account_id_type fee_payer()const { return account_id_type{}; }
//account_id_type fee_payer()const { return GRAPHENE_TEMP_ACCOUNT; }
//void validate()const;
//void get_required_authorities( vector<authority>& a )const
//{
@ -242,8 +246,10 @@ struct blind_transfer_operation : public base_operation
vector<blind_input> inputs;
vector<blind_output> outputs;
account_id_type fee_payer()const { return account_id_type{}; }
/** graphene TEMP account */
account_id_type fee_payer()const { return GRAPHENE_TEMP_ACCOUNT; }
//account_id_type fee_payer()const;
//void validate()const;
//share_type calculate_fee( const fee_parameters_type& k )const;
//void get_required_authorities( vector<authority>& a )const

View file

@ -18,7 +18,7 @@ namespace graphene
// Buyer purchasing lottery tickets
account_id_type buyer;
// count of tickets to buy
share_type tickets_to_buy;
uint64_t tickets_to_buy;
// amount that can spent
asset amount;
@ -83,4 +83,4 @@ FC_REFLECT(graphene::chain::nft_lottery_reward_operation::fee_parameters_type, (
FC_REFLECT(graphene::chain::nft_lottery_end_operation::fee_parameters_type, (fee))
FC_REFLECT(graphene::chain::nft_lottery_token_purchase_operation, (fee)(lottery_id)(buyer)(tickets_to_buy)(amount)(extensions))
FC_REFLECT(graphene::chain::nft_lottery_reward_operation, (fee)(lottery_id)(winner)(amount)(win_percentage)(is_benefactor_reward)(winner_ticket_id)(extensions))
FC_REFLECT(graphene::chain::nft_lottery_end_operation, (fee)(lottery_id)(extensions))
FC_REFLECT(graphene::chain::nft_lottery_end_operation, (fee)(lottery_id)(extensions))

View file

@ -71,7 +71,7 @@ FC_REFLECT( graphene::chain::sidechain_transaction_create_operation, (fee)(payer
(sidechain)
(object_id)
(transaction)
(signers))
(signers) )
FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation, (fee)(signer)(payer)

View file

@ -1,47 +1,40 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/son_info.hpp>
#include <graphene/chain/son_sidechain_info.hpp>
namespace graphene { namespace chain {
struct son_wallet_recreate_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 0; };
struct ext
{
optional<flat_map<sidechain_type, vector<son_sidechain_info> > > sidechain_sons;
};
struct son_wallet_recreate_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 0; };
asset fee;
account_id_type payer;
asset fee;
account_id_type payer;
vector<son_info> sons;
extension< ext > extensions;
flat_map<sidechain_type, vector<son_info> > sons;
account_id_type fee_payer()const { return payer; }
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
};
account_id_type fee_payer()const { return payer; }
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
};
struct son_wallet_update_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 0; };
struct son_wallet_update_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 0; };
asset fee;
account_id_type payer;
asset fee;
account_id_type payer;
son_wallet_id_type son_wallet_id;
sidechain_type sidechain;
string address;
son_wallet_id_type son_wallet_id;
sidechain_type sidechain;
string address;
account_id_type fee_payer()const { return payer; }
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
};
account_id_type fee_payer()const { return payer; }
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
};
} } // namespace graphene::chain
FC_REFLECT(graphene::chain::son_wallet_recreate_operation::fee_parameters_type, (fee) )
FC_REFLECT(graphene::chain::son_wallet_recreate_operation::ext, (sidechain_sons))
FC_REFLECT(graphene::chain::son_wallet_recreate_operation, (fee)(payer)(sons)(extensions) )
FC_REFLECT(graphene::chain::son_wallet_recreate_operation, (fee)(payer)(sons) )
FC_REFLECT(graphene::chain::son_wallet_update_operation::fee_parameters_type, (fee) )
FC_REFLECT(graphene::chain::son_wallet_update_operation, (fee)(payer)(son_wallet_id)(sidechain)(address) )

View file

@ -395,13 +395,6 @@ namespace graphene { namespace chain {
bool is_valid_muse( const std::string& base58str );
};
class pubkey_comparator {
public:
inline bool operator()(const public_key_type& a, const public_key_type& b) const {
return a.key_data < b.key_data;
}
};
struct extended_public_key_type
{
struct binary_key

View file

@ -61,7 +61,6 @@ struct vote_id_type
worker,
son_bitcoin,
son_hive,
son_ethereum,
VOTE_TYPE_COUNT
};
@ -146,7 +145,7 @@ void from_variant( const fc::variant& var, graphene::chain::vote_id_type& vo, ui
FC_REFLECT_TYPENAME( fc::flat_set<graphene::chain::vote_id_type> )
FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(son_bitcoin)(son_hive)(son_ethereum)(VOTE_TYPE_COUNT) )
FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(son_bitcoin)(son_hive)(VOTE_TYPE_COUNT) )
FC_REFLECT( graphene::chain::vote_id_type, (content) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vote_id_type )

View file

@ -36,15 +36,6 @@ namespace graphene { namespace chain {
deposit_address(""),
withdraw_public_key(""),
withdraw_address("") {}
inline string get_deposit_address() const {
if(sidechain_type::ethereum != sidechain)
return deposit_address;
auto deposit_address_lower = deposit_address;
std::transform(deposit_address_lower.begin(), deposit_address_lower.end(), deposit_address_lower.begin(), ::tolower);
return deposit_address_lower;
}
};
struct by_account;
@ -85,7 +76,7 @@ namespace graphene { namespace chain {
ordered_non_unique< tag<by_sidechain_and_deposit_address_and_expires>,
composite_key<sidechain_address_object,
member<sidechain_address_object, sidechain_type, &sidechain_address_object::sidechain>,
const_mem_fun<sidechain_address_object, string, &sidechain_address_object::get_deposit_address>,
member<sidechain_address_object, string, &sidechain_address_object::deposit_address>,
member<sidechain_address_object, time_point_sec, &sidechain_address_object::expires>
>
>

View file

@ -1,11 +1,7 @@
#pragma once
#include <set>
#include <graphene/chain/hardfork.hpp>
#include <fc/reflect/reflect.hpp>
#include <fc/time.hpp>
namespace graphene { namespace chain {
@ -18,23 +14,9 @@ enum class sidechain_type {
hive
};
static const std::set<sidechain_type> all_sidechain_types = {sidechain_type::bitcoin, sidechain_type::ethereum, sidechain_type::hive};
static const std::set<sidechain_type> active_sidechain_types = {sidechain_type::bitcoin, sidechain_type::hive};
inline std::set<sidechain_type> active_sidechain_types(const fc::time_point_sec block_time) {
std::set<sidechain_type> active_sidechain_types{};
if (block_time >= HARDFORK_SON_TIME)
active_sidechain_types.insert(sidechain_type::bitcoin);
if (block_time >= HARDFORK_SON_FOR_HIVE_TIME)
active_sidechain_types.insert(sidechain_type::hive);
if (block_time >= HARDFORK_SON_FOR_ETHEREUM_TIME)
active_sidechain_types.insert(sidechain_type::ethereum);
return active_sidechain_types;
}
} // namespace chain
} // namespace graphene
} }
FC_REFLECT_ENUM(graphene::chain::sidechain_type,
(unknown)
@ -42,4 +24,4 @@ FC_REFLECT_ENUM(graphene::chain::sidechain_type,
(ethereum)
(eos)
(hive)
(peerplays) )
(peerplays) )

View file

@ -2,7 +2,7 @@
#include <boost/multi_index/composite_key.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/sidechain_defs.hpp>
#include <graphene/chain/son_sidechain_info.hpp>
#include <graphene/chain/son_info.hpp>
namespace graphene { namespace chain {
using namespace graphene::db;
@ -30,7 +30,7 @@ namespace graphene { namespace chain {
sidechain_type sidechain = sidechain_type::unknown;
object_id_type object_id;
std::string transaction;
std::vector<son_sidechain_info> signers;
std::vector<son_info> signers;
std::vector<std::pair<son_id_type, std::string>> signatures;
std::string sidechain_transaction;

View file

@ -3,40 +3,34 @@
#include <graphene/chain/sidechain_defs.hpp>
namespace graphene { namespace chain {
using namespace graphene::db;
/**
* @class son_info
* @brief tracks information about a SON info required to re/create primary wallet
* @ingroup object
* @class son_info
* @brief tracks information about a SON info required to re/create primary wallet
* @ingroup object
*/
struct son_info {
son_id_type son_id;
weight_type weight = 0;
public_key_type signing_key;
flat_map<sidechain_type, string> sidechain_public_keys;
string public_key;
bool operator==(const son_info& rhs) {
bool operator==(const son_info& rhs) const {
bool son_sets_equal =
(son_id == rhs.son_id) &&
(weight == rhs.weight) &&
(signing_key == rhs.signing_key) &&
(sidechain_public_keys.size() == rhs.sidechain_public_keys.size());
(public_key == rhs.public_key);
if (son_sets_equal) {
bool sidechain_public_keys_equal = true;
for (size_t i = 0; i < sidechain_public_keys.size(); i++) {
const auto lhs_scpk = sidechain_public_keys.nth(i);
const auto rhs_scpk = rhs.sidechain_public_keys.nth(i);
sidechain_public_keys_equal = sidechain_public_keys_equal &&
(lhs_scpk->first == rhs_scpk->first) &&
(lhs_scpk->second == rhs_scpk->second);
}
son_sets_equal = son_sets_equal && sidechain_public_keys_equal;
}
return son_sets_equal;
}
};
} }
FC_REFLECT( graphene::chain::son_info, (son_id) (weight) (signing_key) (sidechain_public_keys) )
FC_REFLECT( graphene::chain::son_info,
(son_id)
(weight)
(signing_key)
(public_key) )

View file

@ -65,15 +65,7 @@ namespace graphene { namespace chain {
account_id_type son_account;
flat_map<sidechain_type, vote_id_type> sidechain_vote_ids;
flat_map<sidechain_type, uint64_t> total_votes = []()
{
flat_map<sidechain_type, uint64_t> total_votes;
for(const auto& active_sidechain_type : all_sidechain_types)
{
total_votes[active_sidechain_type] = 0;
}
return total_votes;
}();
flat_map<sidechain_type, uint64_t> total_votes;
string url;
vesting_balance_id_type deposit;
public_key_type signing_key;
@ -82,7 +74,7 @@ namespace graphene { namespace chain {
flat_map<sidechain_type, son_status> statuses = []()
{
flat_map<sidechain_type, son_status> statuses;
for(const auto& active_sidechain_type : all_sidechain_types)
for(const auto& active_sidechain_type : active_sidechain_types)
{
statuses[active_sidechain_type] = son_status::inactive;
}
@ -91,21 +83,17 @@ namespace graphene { namespace chain {
flat_map<sidechain_type, string> sidechain_public_keys;
void pay_son_fee(share_type pay, database& db);
bool has_valid_config(time_point_sec head_block_time, sidechain_type sidechain) const;
bool has_valid_config()const;
bool has_valid_config(time_point_sec head_block_time)const;
inline optional<vote_id_type> get_sidechain_vote_id(sidechain_type sidechain) const { return sidechain_vote_ids.contains(sidechain) ? sidechain_vote_ids.at(sidechain) : optional<vote_id_type>{}; }
inline optional<vote_id_type> get_bitcoin_vote_id() const { return get_sidechain_vote_id(sidechain_type::bitcoin); }
inline optional<vote_id_type> get_hive_vote_id() const { return get_sidechain_vote_id(sidechain_type::hive); }
inline optional<vote_id_type> get_ethereum_vote_id() const { return get_sidechain_vote_id(sidechain_type::ethereum); }
private:
bool has_valid_config(sidechain_type sidechain) const;
inline vote_id_type get_sidechain_vote_id(sidechain_type sidechain) const { return sidechain_vote_ids.at(sidechain); }
inline vote_id_type get_bitcoin_vote_id() const { return get_sidechain_vote_id(sidechain_type::bitcoin); }
inline vote_id_type get_hive_vote_id() const { return get_sidechain_vote_id(sidechain_type::hive); }
};
struct by_account;
struct by_vote_id_bitcoin;
struct by_vote_id_hive;
struct by_vote_id_ethereum;
using son_multi_index_type = multi_index_container<
son_object,
indexed_by<
@ -115,14 +103,11 @@ namespace graphene { namespace chain {
ordered_unique< tag<by_account>,
member<son_object, account_id_type, &son_object::son_account>
>,
ordered_non_unique< tag<by_vote_id_bitcoin>,
const_mem_fun<son_object, optional<vote_id_type>, &son_object::get_bitcoin_vote_id>
ordered_unique< tag<by_vote_id_bitcoin>,
const_mem_fun<son_object, vote_id_type, &son_object::get_bitcoin_vote_id>
>,
ordered_non_unique< tag<by_vote_id_hive>,
const_mem_fun<son_object, optional<vote_id_type>, &son_object::get_hive_vote_id>
>,
ordered_non_unique< tag<by_vote_id_ethereum>,
const_mem_fun<son_object, optional<vote_id_type>, &son_object::get_ethereum_vote_id>
ordered_unique< tag<by_vote_id_hive>,
const_mem_fun<son_object, vote_id_type, &son_object::get_hive_vote_id>
>
>
>;

View file

@ -1,31 +0,0 @@
#pragma once
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/sidechain_defs.hpp>
namespace graphene { namespace chain {
/**
* @class son_sidechain_info
* @brief tracks information about a SON info required to re/create primary wallet
* @ingroup object
*/
struct son_sidechain_info {
son_id_type son_id;
weight_type weight = 0;
public_key_type signing_key;
string public_key;
bool operator==(const son_sidechain_info& rhs) const {
bool son_sets_equal =
(son_id == rhs.son_id) &&
(weight == rhs.weight) &&
(signing_key == rhs.signing_key) &&
(public_key == rhs.public_key);
return son_sets_equal;
}
};
} }
FC_REFLECT( graphene::chain::son_sidechain_info, (son_id) (weight) (signing_key) (public_key) )

View file

@ -1,6 +1,6 @@
#pragma once
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/son_sidechain_info.hpp>
#include <graphene/chain/son_info.hpp>
#include <graphene/chain/sidechain_defs.hpp>
namespace graphene { namespace chain {
@ -21,7 +21,7 @@ namespace graphene { namespace chain {
time_point_sec expires;
flat_map<sidechain_type, string> addresses;
flat_map<sidechain_type, vector<son_sidechain_info> > sons;
flat_map<sidechain_type, vector<son_info> > sons;
};
struct by_valid_from;

View file

@ -30,7 +30,7 @@ namespace graphene
auto lottery_options = lottery_md_obj.lottery_data->lottery_options;
FC_ASSERT(lottery_options.ticket_price.asset_id == op.amount.asset_id);
FC_ASSERT(op.tickets_to_buy * lottery_options.ticket_price.amount.value == op.amount.amount.value);
FC_ASSERT((double)op.amount.amount.value / lottery_options.ticket_price.amount.value == (double)op.tickets_to_buy);
return void_result();
}
FC_CAPTURE_AND_RETHROW((op))
@ -142,4 +142,4 @@ namespace graphene
FC_CAPTURE_AND_RETHROW((op))
}
} // namespace chain
} // namespace graphene
} // namespace graphene

View file

@ -174,37 +174,27 @@ void account_options::validate() const
{
auto needed_witnesses = num_witness;
auto needed_committee = num_committee;
FC_ASSERT( extensions.value.num_son.valid() , "Invalid son number" );
flat_map<sidechain_type, uint16_t> needed_sons = *extensions.value.num_son;
for( vote_id_type id : votes )
if( id.type() == vote_id_type::witness && needed_witnesses )
--needed_witnesses;
else if ( id.type() == vote_id_type::committee && needed_committee )
--needed_committee;
else if ( id.type() == vote_id_type::son_bitcoin && needed_sons[sidechain_type::bitcoin] )
--needed_sons[sidechain_type::bitcoin];
else if ( id.type() == vote_id_type::son_hive && needed_sons[sidechain_type::hive] )
--needed_sons[sidechain_type::hive];
FC_ASSERT( needed_witnesses == 0,
"May not specify fewer witnesses than the number voted for.");
FC_ASSERT( needed_committee == 0,
"May not specify fewer committee members than the number voted for.");
if ( extensions.value.num_son.valid() )
{
flat_map<sidechain_type, uint16_t> needed_sons = *extensions.value.num_son;
for( vote_id_type id : votes )
if ( id.type() == vote_id_type::son_bitcoin && needed_sons[sidechain_type::bitcoin] )
--needed_sons[sidechain_type::bitcoin];
else if ( id.type() == vote_id_type::son_hive && needed_sons[sidechain_type::hive] )
--needed_sons[sidechain_type::hive];
else if ( id.type() == vote_id_type::son_ethereum && needed_sons[sidechain_type::ethereum] )
--needed_sons[sidechain_type::ethereum];
FC_ASSERT( needed_sons[sidechain_type::bitcoin] == 0,
"May not specify fewer Bitcoin SONs than the number voted for.");
FC_ASSERT( needed_sons[sidechain_type::hive] == 0,
"May not specify fewer Hive SONs than the number voted for.");
FC_ASSERT( needed_sons[sidechain_type::ethereum] == 0,
"May not specify fewer Ethereum SONs than the number voted for.");
}
FC_ASSERT( needed_sons[sidechain_type::bitcoin] == 0,
"May not specify fewer Bitcoin SONs than the number voted for.");
FC_ASSERT( needed_sons[sidechain_type::hive] == 0,
"May not specify fewer Hive SONs than the number voted for.");
}
void affiliate_reward_distribution::validate() const

View file

@ -22,14 +22,11 @@ object_id_type add_sidechain_address_evaluator::do_apply(const sidechain_address
const auto &sidechain_addresses_idx = db().get_index_type<sidechain_address_index>().indices().get<by_account_and_sidechain_and_expires>();
const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(op.sidechain_address_account, op.sidechain, time_point_sec::maximum()));
if (addr_itr != sidechain_addresses_idx.end()) {
if (db().head_block_time() >= HARDFORK_SIDECHAIN_DELETE_TIME) {
db().remove(*addr_itr);
} else {
db().modify(*addr_itr, [&](sidechain_address_object &sao) {
sao.expires = db().head_block_time();
});
}
if (addr_itr != sidechain_addresses_idx.end())
{
db().modify(*addr_itr, [&](sidechain_address_object &sao) {
sao.expires = db().head_block_time();
});
}
const auto& new_sidechain_address_object = db().create<sidechain_address_object>( [&]( sidechain_address_object& obj ){
@ -108,14 +105,10 @@ void_result delete_sidechain_address_evaluator::do_apply(const sidechain_address
{ try {
const auto& idx = db().get_index_type<sidechain_address_index>().indices().get<by_id>();
auto sidechain_address = idx.find(op.sidechain_address_id);
if (sidechain_address != idx.end()) {
if (db().head_block_time() >= HARDFORK_SIDECHAIN_DELETE_TIME) {
db().remove(*sidechain_address);
} else {
db().modify(*sidechain_address, [&](sidechain_address_object &sao) {
sao.expires = db().head_block_time();
});
}
if(sidechain_address != idx.end()) {
db().modify(*sidechain_address, [&](sidechain_address_object &sao) {
sao.expires = db().head_block_time();
});
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }

View file

@ -11,7 +11,7 @@ namespace graphene { namespace chain {
void_result sidechain_transaction_create_evaluator::do_evaluate(const sidechain_transaction_create_operation &op)
{ try {
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
FC_ASSERT(op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer.");
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
FC_ASSERT((op.object_id.is<son_wallet_id_type>() || op.object_id.is<son_wallet_deposit_id_type>() || op.object_id.is<son_wallet_withdraw_id_type>()), "Invalid object id");
@ -28,26 +28,15 @@ void_result sidechain_transaction_create_evaluator::do_evaluate(const sidechain_
object_id_type sidechain_transaction_create_evaluator::do_apply(const sidechain_transaction_create_operation &op)
{ try {
const auto &new_sidechain_transaction_object = db().create<sidechain_transaction_object>([&](sidechain_transaction_object &sto) {
sto.timestamp = db().head_block_time();
sto.sidechain = op.sidechain;
sto.object_id = op.object_id;
sto.transaction = op.transaction;
std::vector<son_sidechain_info> signers;
for(const auto& signer : op.signers){
son_sidechain_info ssi;
ssi.son_id = signer.son_id;
ssi.weight = signer.weight;
ssi.signing_key = signer.signing_key;
ssi.public_key = signer.sidechain_public_keys.at(op.sidechain);
signers.emplace_back(std::move(ssi));
}
sto.signers = std::move(signers);
std::transform(sto.signers.begin(), sto.signers.end(), std::inserter(sto.signatures, sto.signatures.end()), [](const son_sidechain_info &si) {
sto.signers = op.signers;
std::transform(op.signers.begin(), op.signers.end(), std::inserter(sto.signatures, sto.signatures.end()), [](const son_info &si) {
return std::make_pair(si.son_id, std::string());
});
for (const auto &si : sto.signers) {
for (const auto &si : op.signers) {
sto.total_weight = sto.total_weight + si.weight;
}
sto.sidechain_transaction = "";

View file

@ -38,29 +38,17 @@ void_result create_son_evaluator::do_evaluate(const son_create_operation& op)
object_id_type create_son_evaluator::do_apply(const son_create_operation& op)
{ try {
vote_id_type vote_id;
flat_map<sidechain_type, vote_id_type> vote_ids;
vote_id_type vote_id_bitcoin;
vote_id_type vote_id_hive;
db().modify(db().get_global_properties(), [&vote_id_bitcoin, &vote_id_hive](global_property_object& p) {
vote_id_bitcoin = get_next_vote_id(p, vote_id_type::son_bitcoin);
vote_id_hive = get_next_vote_id(p, vote_id_type::son_hive);
});
const auto now = db().head_block_time();
if( now < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
db().modify(db().get_global_properties(), [&vote_id](global_property_object &p) {
vote_id = get_next_vote_id(p, vote_id_type::son_bitcoin);
});
}
else {
db().modify(db().get_global_properties(), [&vote_ids](global_property_object &p) {
vote_ids[sidechain_type::bitcoin] = get_next_vote_id(p, vote_id_type::son_bitcoin);
vote_ids[sidechain_type::hive] = get_next_vote_id(p, vote_id_type::son_hive);
vote_ids[sidechain_type::ethereum] = get_next_vote_id(p, vote_id_type::son_ethereum);
});
}
const auto& new_son_object = db().create<son_object>( [&]( son_object& obj ) {
const auto& new_son_object = db().create<son_object>( [&]( son_object& obj ){
obj.son_account = op.owner_account;
if( now < HARDFORK_SON_FOR_ETHEREUM_TIME )
obj.sidechain_vote_ids[sidechain_type::bitcoin] = vote_id;
else
obj.sidechain_vote_ids = vote_ids;
obj.sidechain_vote_ids[sidechain_type::bitcoin] = vote_id_bitcoin;
obj.sidechain_vote_ids[sidechain_type::hive] = vote_id_hive;
obj.url = op.url;
obj.deposit = op.deposit;
obj.signing_key = op.signing_key;
@ -177,7 +165,7 @@ void_result son_heartbeat_evaluator::do_evaluate(const son_heartbeat_operation&
fc::time_point_sec min_ts = db().head_block_time() - fc::seconds(5 * db().block_interval());
// Account for server ntp sync difference
fc::time_point_sec max_ts = db().head_block_time() + fc::seconds(5 * db().block_interval());
for(const auto& active_sidechain_type : active_sidechain_types(db().head_block_time())) {
for(const auto& active_sidechain_type : active_sidechain_types) {
if(stats.last_active_timestamp.contains(active_sidechain_type))
FC_ASSERT(op.ts > stats.last_active_timestamp.at(active_sidechain_type), "Heartbeat sent for sidechain = ${sidechain} without waiting minimum time", ("sidechain", active_sidechain_type));
if(stats.last_down_timestamp.contains(active_sidechain_type))
@ -204,7 +192,7 @@ object_id_type son_heartbeat_evaluator::do_apply(const son_heartbeat_operation&
active_son_ids.reserve(active_sons.size());
std::transform(active_sons.cbegin(), active_sons.cend(),
std::inserter(active_son_ids, active_son_ids.end()),
[](const son_sidechain_info &swi) {
[](const son_info &swi) {
return swi.son_id;
});
@ -217,7 +205,7 @@ object_id_type son_heartbeat_evaluator::do_apply(const son_heartbeat_operation&
if (itr->statuses.at(sidechain) == son_status::in_maintenance) {
db().modify(itr->statistics(db()), [&](son_statistics_object &sso) {
sso.current_interval_downtime[sidechain] += op.ts.sec_since_epoch() - (sso.last_down_timestamp.contains(sidechain) ? sso.last_down_timestamp.at(sidechain).sec_since_epoch() : op.ts.sec_since_epoch());
sso.current_interval_downtime[sidechain] += op.ts.sec_since_epoch() - sso.last_down_timestamp.at(sidechain).sec_since_epoch();
sso.last_active_timestamp[sidechain] = op.ts;
});
@ -253,9 +241,8 @@ void_result son_report_down_evaluator::do_evaluate(const son_report_down_operati
status_need_to_report_down = true;
}
FC_ASSERT(status_need_to_report_down, "Inactive/Deregistered/in_maintenance SONs cannot be reported on as down");
for(const auto& active_sidechain_type : active_sidechain_types(db().head_block_time())) {
if(stats.last_active_timestamp.contains(active_sidechain_type))
FC_ASSERT(op.down_ts >= stats.last_active_timestamp.at(active_sidechain_type), "sidechain = ${sidechain} down_ts should be greater than last_active_timestamp", ("sidechain", active_sidechain_type));
for(const auto& active_sidechain_type : active_sidechain_types) {
FC_ASSERT(op.down_ts >= stats.last_active_timestamp.at(active_sidechain_type), "sidechain = ${sidechain} down_ts should be greater than last_active_timestamp", ("sidechain", active_sidechain_type));
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }

View file

@ -6,22 +6,20 @@ namespace graphene { namespace chain {
db.adjust_balance(son_account, pay);
}
bool son_object::has_valid_config(sidechain_type sidechain) const {
return (sidechain_public_keys.find( sidechain ) != sidechain_public_keys.end()) &&
(sidechain_public_keys.at(sidechain).length() > 0);
bool son_object::has_valid_config()const {
return ((std::string(signing_key).length() > 0) &&
(sidechain_public_keys.size() > 0) &&
(sidechain_public_keys.find( sidechain_type::bitcoin ) != sidechain_public_keys.end()) &&
(sidechain_public_keys.at(sidechain_type::bitcoin).length() > 0));
}
bool son_object::has_valid_config(time_point_sec head_block_time, sidechain_type sidechain) const {
bool retval = (std::string(signing_key).length() > 0) && (sidechain_public_keys.size() > 0);
bool son_object::has_valid_config(time_point_sec head_block_time)const {
bool retval = has_valid_config();
if (head_block_time < HARDFORK_SON_FOR_HIVE_TIME) {
retval = retval && has_valid_config(sidechain_type::bitcoin);
}
if (head_block_time >= HARDFORK_SON_FOR_HIVE_TIME && head_block_time < HARDFORK_SON_FOR_ETHEREUM_TIME) {
retval = retval && has_valid_config(sidechain_type::bitcoin) && has_valid_config(sidechain_type::hive);
}
else if (head_block_time >= HARDFORK_SON_FOR_ETHEREUM_TIME) {
retval = retval && has_valid_config(sidechain);
if (head_block_time >= HARDFORK_SON_FOR_HIVE_TIME) {
retval = retval &&
(sidechain_public_keys.find( sidechain_type::hive ) != sidechain_public_keys.end()) &&
(sidechain_public_keys.at(sidechain_type::hive).length() > 0);
}
return retval;

View file

@ -7,9 +7,8 @@ namespace graphene { namespace chain {
void_result recreate_son_wallet_evaluator::do_evaluate(const son_wallet_recreate_operation& op)
{ try{
const auto now = db().head_block_time();
FC_ASSERT(now >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
FC_ASSERT(op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer.");
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
auto itr = idx.rbegin();
@ -17,23 +16,7 @@ void_result recreate_son_wallet_evaluator::do_evaluate(const son_wallet_recreate
{
// Compare current wallet SONs and to-be lists of active sons
auto cur_wallet_sons = (*itr).sons;
flat_map<sidechain_type, vector<son_sidechain_info> > new_wallet_sons;
if( now < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
for(const auto& son : op.sons){
for(const auto& active_sidechain_type : active_sidechain_types(db().head_block_time())){
son_sidechain_info ssi;
ssi.son_id = son.son_id;
ssi.weight = son.weight;
ssi.signing_key = son.signing_key;
ssi.public_key = son.sidechain_public_keys.at(active_sidechain_type);
new_wallet_sons[active_sidechain_type].emplace_back(std::move(ssi));
}
}
}
else{
FC_ASSERT(op.extensions.value.sidechain_sons.valid(), "Sons is not valid");
new_wallet_sons = *op.extensions.value.sidechain_sons;
}
auto new_wallet_sons = op.sons;
bool son_sets_equal = (cur_wallet_sons.size() == new_wallet_sons.size());
if (son_sets_equal) {
@ -68,26 +51,9 @@ object_id_type recreate_son_wallet_evaluator::do_apply(const son_wallet_recreate
}
const auto& new_son_wallet_object = db().create<son_wallet_object>( [&]( son_wallet_object& obj ){
const auto now = db().head_block_time();
obj.valid_from = now;
obj.valid_from = db().head_block_time();
obj.expires = time_point_sec::maximum();
if( now < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
flat_map<sidechain_type, vector<son_sidechain_info> > sons;
for(const auto& son : op.sons){
for(const auto& active_sidechain_type : active_sidechain_types(db().head_block_time())){
son_sidechain_info ssi;
ssi.son_id = son.son_id;
ssi.weight = son.weight;
ssi.signing_key = son.signing_key;
ssi.public_key = son.sidechain_public_keys.at(active_sidechain_type);
sons[active_sidechain_type].emplace_back(std::move(ssi));
}
}
obj.sons = std::move(sons);
}
else{
obj.sons = *op.extensions.value.sidechain_sons;
}
obj.sons = op.sons;
});
return new_son_wallet_object.id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
@ -97,19 +63,8 @@ void_result update_son_wallet_evaluator::do_evaluate(const son_wallet_update_ope
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
const son_wallet_id_type son_wallet_id = [&]{
if(db().head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME)
{
const auto ast = active_sidechain_types(db().head_block_time());
const auto id = (op.son_wallet_id.instance.value - std::distance(ast.begin(), ast.find(op.sidechain))) / ast.size();
return son_wallet_id_type{ id };
}
return op.son_wallet_id;
}();
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
FC_ASSERT( idx.find(son_wallet_id) != idx.end() );
FC_ASSERT( idx.find(op.son_wallet_id) != idx.end() );
//auto itr = idx.find(op.son_wallet_id);
//FC_ASSERT( itr->addresses.find(op.sidechain) == itr->addresses.end() ||
// itr->addresses.at(op.sidechain).empty(), "Sidechain wallet address already set");
@ -118,19 +73,8 @@ void_result update_son_wallet_evaluator::do_evaluate(const son_wallet_update_ope
object_id_type update_son_wallet_evaluator::do_apply(const son_wallet_update_operation& op)
{ try {
const son_wallet_id_type son_wallet_id = [&]{
if(db().head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME)
{
const auto ast = active_sidechain_types(db().head_block_time());
const auto id = (op.son_wallet_id.instance.value - std::distance(ast.begin(), ast.find(op.sidechain))) / ast.size();
return son_wallet_id_type{ id };
}
return op.son_wallet_id;
}();
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
auto itr = idx.find(son_wallet_id);
auto itr = idx.find(op.son_wallet_id);
if (itr != idx.end())
{
if (itr->addresses.find(op.sidechain) == itr->addresses.end()) {

View file

@ -10,13 +10,12 @@ namespace graphene { namespace chain {
void_result create_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_withdraw_create_operation& op)
{ try {
const auto now = db().head_block_time();
FC_ASSERT(now >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
const auto &son_idx = db().get_index_type<son_index>().indices().get<by_id>();
const auto so = son_idx.find(op.son_id);
FC_ASSERT(so != son_idx.end(), "SON not found");
FC_ASSERT(so->son_account == op.payer, "Payer is not SON account owner");
FC_ASSERT(!(op.sidechain == sidechain_type::peerplays && now >= HARDFORK_SON_FOR_ETHEREUM_TIME), "Peerplays sidechain type is not allowed");
const auto &ss_idx = db().get_index_type<son_stats_index>().indices().get<by_owner>();
FC_ASSERT(ss_idx.find(op.son_id) != ss_idx.end(), "Statistic object for a given SON ID does not exists");
@ -24,17 +23,9 @@ void_result create_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_w
const auto &swwo_idx = db().get_index_type<son_wallet_withdraw_index>().indices().get<by_peerplays_uid>();
const auto swwo = swwo_idx.find(op.peerplays_uid);
if (swwo == swwo_idx.end()) {
const sidechain_type sidechain = [&op]{
if(op.sidechain == sidechain_type::peerplays){
return op.withdraw_sidechain;
}
else
return op.sidechain;
}();
const auto &gpo = db().get_global_properties();
bool expected = false;
for (auto &si : gpo.active_sons.at(sidechain)) {
for (auto &si : gpo.active_sons.at(op.sidechain)) {
if (op.son_id == si.son_id) {
expected = true;
break;
@ -85,16 +76,8 @@ object_id_type create_son_wallet_withdraw_evaluator::do_apply(const son_wallet_w
swwo.withdraw_currency = op.withdraw_currency;
swwo.withdraw_amount = op.withdraw_amount;
const sidechain_type sidechain = [&op]{
if(op.sidechain == sidechain_type::peerplays){
return op.withdraw_sidechain;
}
else
return op.sidechain;
}();
const auto &gpo = db().get_global_properties();
for (auto &si : gpo.active_sons.at(sidechain)) {
for (auto &si : gpo.active_sons.at(op.sidechain)) {
swwo.expected_reports.insert(std::make_pair(si.son_id, si.weight));
auto stats_itr = db().get_index_type<son_stats_index>().indices().get<by_owner>().find(si.son_id);
@ -155,17 +138,13 @@ object_id_type create_son_wallet_withdraw_evaluator::do_apply(const son_wallet_w
void_result process_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_withdraw_process_operation& op)
{ try{
const auto now = db().head_block_time();
FC_ASSERT(now >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
const auto& idx = db().get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
const auto& itr = idx.find(op.son_wallet_withdraw_id);
FC_ASSERT(itr != idx.end(), "Son wallet withdraw not found");
FC_ASSERT(!(itr->sidechain == sidechain_type::peerplays && now >= HARDFORK_SON_FOR_ETHEREUM_TIME), "Peerplays sidechain type is not allowed");
if(itr->sidechain != sidechain_type::peerplays) {
FC_ASSERT(db().get_global_properties().active_sons.at(itr->sidechain).size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present");
}
FC_ASSERT(db().get_global_properties().active_sons.at(itr->sidechain).size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present");
FC_ASSERT(!itr->processed, "Son wallet withdraw is already processed");
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }

View file

@ -29,7 +29,6 @@
#include <fc/log/logger.hpp>
#include <map>
#include <mutex>
namespace graphene { namespace db {
@ -145,7 +144,6 @@ namespace graphene { namespace db {
fc::path get_data_dir()const { return _data_dir; }
/** public for testing purposes only... should be private in practice. */
mutable std::mutex _undo_db_mutex;
undo_database _undo_db;
protected:
template<typename IndexType>

View file

@ -47,3 +47,4 @@ namespace graphene { namespace net {
const core_message_type_enum get_current_connections_reply_message::type = core_message_type_enum::get_current_connections_reply_message_type;
} } // graphene::net

View file

@ -23,8 +23,6 @@
*/
#pragma once
#include <stddef.h>
#define GRAPHENE_NET_PROTOCOL_VERSION 106
/**
@ -112,6 +110,3 @@
#define GRAPHENE_NET_MAX_NESTED_OBJECTS (250)
#define MAXIMUM_PEERDB_SIZE 1000
constexpr size_t MAX_BLOCKS_TO_HANDLE_AT_ONCE = 200;
constexpr size_t MAX_SYNC_BLOCKS_TO_PREFETCH = 10 * MAX_BLOCKS_TO_HANDLE_AT_ONCE;

View file

@ -61,7 +61,7 @@ namespace graphene { namespace net {
class node_delegate
{
public:
virtual ~node_delegate() = default;
virtual ~node_delegate(){}
/**
* If delegate has the item, the network has no need to fetch it.
@ -71,9 +71,7 @@ namespace graphene { namespace net {
/**
* @brief Called when a new block comes in from the network
*
* @param blk_msg the message which contains the block
* @param sync_mode true if the message was fetched through the sync process, false during normal operation
* @param contained_transaction_msg_ids container for the transactions to write back into
* @returns true if this message caused the blockchain to switch forks, false if it did not
*
* @throws exception if error validating the item, otherwise the item is
@ -197,7 +195,7 @@ namespace graphene { namespace net {
{
public:
node(const std::string& user_agent);
virtual ~node();
~node();
void close();
@ -215,34 +213,11 @@ namespace graphene { namespace net {
*/
void add_node( const fc::ip::endpoint& ep );
/*****
* @brief add a list of nodes to seed the p2p network
* @param seeds a vector of url strings
*/
void add_seed_nodes( std::vector<std::string> seeds );
/****
* @brief add a node to seed the p2p network
* @param in the url as a string
*/
void add_seed_node( const std::string& in);
/**
* Attempt to connect to the specified endpoint immediately.
*/
virtual void connect_to_endpoint( const fc::ip::endpoint& ep );
/**
* @brief Helper to convert a string to a collection of endpoints
*
* This converts a string (i.e. "bitshares.eu:665535" to a collection of endpoints.
* NOTE: Throws an exception if not in correct format or was unable to resolve URL.
*
* @param in the incoming string
* @returns a vector of endpoints
*/
static std::vector<fc::ip::endpoint> resolve_string_to_ip_endpoints( const std::string& in );
/**
* Specifies the network interface and port upon which incoming
* connections should be accepted.

View file

@ -62,7 +62,6 @@ namespace graphene { namespace net
class peer_connection_delegate
{
public:
virtual ~peer_connection_delegate() = default;
virtual void on_message(peer_connection* originating_peer,
const message& received_message) = 0;
virtual void on_connection_closed(peer_connection* originating_peer) = 0;
@ -126,7 +125,7 @@ namespace graphene { namespace net
* it is sitting on the queue
*/
virtual size_t get_size_in_queue() = 0;
virtual ~queued_message() = default;
virtual ~queued_message() {}
};
/* when you queue up a 'real_queued_message', a full copy of the message is

View file

@ -97,7 +97,7 @@ namespace graphene { namespace net {
{
public:
peer_database();
virtual ~peer_database();
~peer_database();
void open(const fc::path& databaseFilename);
void close();

File diff suppressed because it is too large Load diff

View file

@ -50,8 +50,7 @@ namespace graphene { namespace net {
indexed_by<ordered_non_unique<tag<last_seen_time_index>,
member<potential_peer_record,
fc::time_point_sec,
&potential_peer_record::last_seen_time>,
std::greater<fc::time_point_sec> >,
&potential_peer_record::last_seen_time> >,
hashed_unique<tag<endpoint_index>,
member<potential_peer_record,
fc::ip::endpoint,

View file

@ -85,7 +85,6 @@ void account_history_plugin_impl::update_account_histories( const signed_block&
vector<optional< operation_history_object > >& hist = db.get_applied_operations();
bool is_first = true;
auto skip_oho_id = [&is_first,&db,this]() {
const std::lock_guard<std::mutex> undo_db_lock{db._undo_db_mutex};
if( is_first && db._undo_db.enabled() ) // this ensures that the current id is rolled back on undo
{
db.remove( db.create<operation_history_object>( []( operation_history_object& obj) {} ) );

View file

@ -16,4 +16,3 @@ install( TARGETS
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
INSTALL( FILES ${HEADERS} DESTINATION "include/graphene/debug_witness" )

View file

@ -34,9 +34,7 @@ class debug_api_impl
};
debug_api_impl::debug_api_impl( graphene::app::application& _app ) : app( _app )
{
// Nothing else to do
}
{}
void debug_api_impl::debug_push_blocks( const std::string& src_filename, uint32_t count )

View file

@ -38,10 +38,7 @@ using std::vector;
namespace bpo = boost::program_options;
debug_witness_plugin::~debug_witness_plugin()
{
cleanup();
}
debug_witness_plugin::~debug_witness_plugin() {}
void debug_witness_plugin::plugin_set_program_options(
boost::program_options::options_description& command_line_options,
@ -65,7 +62,7 @@ void debug_witness_plugin::plugin_initialize(const boost::program_options::varia
ilog("debug_witness plugin: plugin_initialize() begin");
_options = &options;
if( options.count("debug-private-key") > 0 )
if( options.count("debug-private-key") )
{
const std::vector<std::string> key_id_to_wif_pair_strings = options["debug-private-key"].as<std::vector<std::string>>();
for (const std::string& key_id_to_wif_pair_string : key_id_to_wif_pair_strings)
@ -103,6 +100,7 @@ void debug_witness_plugin::plugin_startup()
_changed_objects_conn = db.changed_objects.connect([this](const std::vector<graphene::db::object_id_type>& ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts){ on_changed_objects(ids, impacted_accounts); });
_removed_objects_conn = db.removed_objects.connect([this](const std::vector<graphene::db::object_id_type>& ids, const std::vector<const graphene::db::object*>& objs, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts){ on_removed_objects(ids, objs, impacted_accounts); });
return;
}
void debug_witness_plugin::on_changed_objects( const std::vector<graphene::db::object_id_type>& ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts )
@ -157,15 +155,11 @@ void debug_witness_plugin::flush_json_object_stream()
}
void debug_witness_plugin::plugin_shutdown()
{
cleanup();
}
void debug_witness_plugin::cleanup()
{
if( _json_object_stream )
{
_json_object_stream->close();
_json_object_stream.reset();
}
return;
}

View file

@ -34,25 +34,23 @@ namespace graphene { namespace debug_witness_plugin {
class debug_witness_plugin : public graphene::app::plugin {
public:
using graphene::app::plugin::plugin;
~debug_witness_plugin() override;
~debug_witness_plugin();
std::string plugin_name()const override;
void plugin_set_program_options(
virtual void plugin_set_program_options(
boost::program_options::options_description &command_line_options,
boost::program_options::options_description &config_file_options
) override;
void plugin_initialize( const boost::program_options::variables_map& options ) override;
void plugin_startup() override;
void plugin_shutdown() override;
virtual void plugin_initialize( const boost::program_options::variables_map& options ) override;
virtual void plugin_startup() override;
virtual void plugin_shutdown() override;
void set_json_object_stream( const std::string& filename );
void flush_json_object_stream();
private:
void cleanup();
void on_changed_objects( const std::vector<graphene::db::object_id_type>& ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts );
void on_removed_objects( const std::vector<graphene::db::object_id_type>& ids, const std::vector<const graphene::db::object*> objs, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts );
@ -60,7 +58,7 @@ private:
boost::program_options::variables_map _options;
std::map<chain::public_key_type, fc::ecc::private_key, chain::pubkey_comparator> _private_keys;
std::map<chain::public_key_type, fc::ecc::private_key> _private_keys;
std::shared_ptr< std::ofstream > _json_object_stream;
boost::signals2::scoped_connection _applied_block_conn;

View file

@ -63,24 +63,8 @@ void delayed_node_plugin::plugin_set_program_options(bpo::options_description& c
void delayed_node_plugin::connect()
{
fc::http::websocket_connection_ptr con;
try
{
con = my->client.connect(my->remote_endpoint);
}
catch( const fc::exception& e )
{
wlog("Error while connecting: ${e}", ("e", e.to_detail_string()));
connection_failed();
return;
}
my->client_connection = std::make_shared<fc::rpc::websocket_api_connection>(
con, GRAPHENE_NET_MAX_NESTED_OBJECTS );
my->client_connection = std::make_shared<fc::rpc::websocket_api_connection>(my->client.connect(my->remote_endpoint), GRAPHENE_MAX_NESTED_OBJECTS);
my->database_api = my->client_connection->get_remote_api<graphene::app::database_api>(0);
my->database_api->set_block_applied_callback([this]( const fc::variant& block_id )
{
fc::from_variant( block_id, my->last_received_remote_head, GRAPHENE_MAX_NESTED_OBJECTS );
} );
my->client_connection_closed = my->client_connection->closed.connect([this] {
connection_failed();
});
@ -89,9 +73,7 @@ void delayed_node_plugin::connect()
void delayed_node_plugin::plugin_initialize(const boost::program_options::variables_map& options)
{
FC_ASSERT(options.count("trusted-node") > 0);
ilog("delayed_node_plugin: plugin_initialize() begin");
my->remote_endpoint = "ws://" + options.at("trusted-node").as<std::string>();
ilog("delayed_node_plugin: plugin_initialize() end");
}
void delayed_node_plugin::sync_with_trusted_node()
@ -118,11 +100,8 @@ void delayed_node_plugin::sync_with_trusted_node()
while( remote_dpo.last_irreversible_block_num > db.head_block_num() )
{
fc::optional<graphene::chain::signed_block> block = my->database_api->get_block( db.head_block_num()+1 );
// TODO: during sync, decouple requesting blocks from preprocessing + applying them
FC_ASSERT(block, "Trusted node claims it has blocks it doesn't actually have.");
ilog("Pushing block #${n}", ("n", block->block_num()));
// timur: failed to merge from bitshares, API n/a in peerplays
// db.precompute_parallel( *block, graphene::chain::database::skip_nothing ).wait();
db.push_block(*block);
synced_blocks++;
}
@ -157,12 +136,24 @@ void delayed_node_plugin::plugin_startup()
mainloop();
});
connect();
try
{
connect();
my->database_api->set_block_applied_callback([this]( const fc::variant& block_id )
{
fc::from_variant( block_id, my->last_received_remote_head, GRAPHENE_MAX_NESTED_OBJECTS );
} );
return;
}
catch (const fc::exception& e)
{
elog("Error during connection: ${e}", ("e", e.to_detail_string()));
}
fc::async([this]{connection_failed();});
}
void delayed_node_plugin::connection_failed()
{
my->last_received_remote_head = my->last_processed_remote_head;
elog("Connection to trusted node failed; retrying in 5 seconds...");
fc::schedule([this]{connect();}, fc::time_point::now() + fc::seconds(5));
}

View file

@ -127,7 +127,6 @@ bool elasticsearch_plugin_impl::update_account_histories( const signed_block& b
const vector<optional< operation_history_object > >& hist = db.get_applied_operations();
bool is_first = true;
auto skip_oho_id = [&is_first,&db,this]() {
const std::lock_guard<std::mutex> undo_db_lock{db._undo_db_mutex};
if( is_first && db._undo_db.enabled() ) // this ensures that the current id is rolled back on undo
{
db.remove( db.create<operation_history_object>( []( operation_history_object& obj) {} ) );

View file

@ -6,7 +6,6 @@ add_library( peerplays_sidechain
sidechain_net_handler_factory.cpp
sidechain_net_handler.cpp
sidechain_net_handler_bitcoin.cpp
sidechain_net_handler_ethereum.cpp
sidechain_net_handler_hive.cpp
sidechain_net_handler_peerplays.cpp
bitcoin/bech32.cpp
@ -17,14 +16,8 @@ add_library( peerplays_sidechain
bitcoin/utils.cpp
bitcoin/sign_bitcoin_transaction.cpp
bitcoin/libbitcoin_client.cpp
bitcoin/estimate_fee_external.cpp
common/rpc_client.cpp
common/utils.cpp
ethereum/encoders.cpp
ethereum/decoders.cpp
ethereum/transaction.cpp
ethereum/types.cpp
ethereum/utils.cpp
hive/asset.cpp
hive/operations.cpp
hive/transaction.cpp
@ -44,7 +37,7 @@ endif()
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS)
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE)
target_link_libraries( peerplays_sidechain PRIVATE curl graphene_plugin sha3 zmq bitcoin-system bitcoin-protocol bitcoin-client bitcoin-explorer )
target_link_libraries( peerplays_sidechain PRIVATE curl graphene_plugin zmq bitcoin-system bitcoin-protocol bitcoin-client bitcoin-explorer )
target_include_directories( peerplays_sidechain
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )

View file

@ -152,7 +152,7 @@ void bitcoin_transaction_builder::add_in(payment_type type, tx_in txin, const by
txin.scriptSig = script_code;
break;
default: {
if (txin.prevout.hash == fc::sha256("0000000000000000000000000000000000000000000000000000000000000000")) { // coinbase
if (txin.prevout.hash == fc::sha256("0000000000000000000000000000000000000000000000000000000000000000")) { //coinbase
FC_ASSERT(script_code != bytes());
txin.scriptSig = script_code;
}

View file

@ -1,157 +0,0 @@
#include <graphene/peerplays_sidechain/bitcoin/estimate_fee_external.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <fc/log/logger.hpp>
#include <iostream>
namespace graphene {
namespace peerplays_sidechain {
static size_t writeFunction(void *ptr, size_t size, size_t nmemb, std::string *data) {
data->append((char *)ptr, size * nmemb);
return size * nmemb;
}
estimate_fee_external::estimate_fee_external() {
curl = curl_easy_init();
}
estimate_fee_external::~estimate_fee_external() {
curl_easy_cleanup(curl);
}
std::vector<std::pair<std::string, uint64_t>> estimate_fee_external::get_fee_external(uint16_t target_block) {
std::vector<std::pair<std::string, uint64_t>> estimate_fee_external_collection;
this->target_block = target_block;
for (auto &url_fee_parser : url_get_fee_parsers) {
response = get_response(url_fee_parser.first);
uint64_t fee = url_fee_parser.second();
std::string url_str = url_fee_parser.first;
if (fee != 0) {
estimate_fee_external_collection.emplace_back(std::make_pair(url_fee_parser.first, fee));
}
}
return estimate_fee_external_collection;
}
std::string estimate_fee_external::get_response(std::string url) {
std::string response;
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(curl, CURLOPT_USERPWD, "user:pass");
curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/7.42.0");
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_perform(curl);
}
return response;
}
uint64_t estimate_fee_external::parse_and_get_fee_1() {
//"https://www.bitgo.com/api/v2/btc/tx/fee"
uint64_t founded_fee = 0;
if (response.empty()) {
return founded_fee;
}
std::stringstream response_ss(response);
boost::property_tree::ptree response_pt;
boost::property_tree::read_json(response_ss, response_pt);
for (const auto &tx_child : response_pt.get_child("feeByBlockTarget")) {
const auto &block_num = tx_child.first.data();
const auto &fee = tx_child.second.data();
founded_fee = std::stoi(fee);
if (std::stoi(block_num) >= target_block) {
return founded_fee;
}
}
return founded_fee;
}
uint64_t estimate_fee_external::parse_and_get_fee_2() {
// https://bitcoiner.live/api/fees/estimates/latest
uint64_t founded_fee = 0;
if (response.empty()) {
return founded_fee;
}
std::stringstream response_ss(response);
boost::property_tree::ptree response_pt;
boost::property_tree::read_json(response_ss, response_pt);
for (const auto &tx_child : response_pt.get_child("estimates")) {
const auto &time_str = tx_child.first.data();
auto time = std::stoi(time_str);
auto block_num = time / 30;
if (tx_child.second.count("sat_per_vbyte")) {
auto founded_fee_str = tx_child.second.get_child("sat_per_vbyte").data();
founded_fee = std::stoi(founded_fee_str) * 1000;
}
if (block_num >= target_block) {
return founded_fee;
}
}
return founded_fee;
}
uint64_t estimate_fee_external::parse_and_get_fee_3() {
// https://api.blockchain.info/mempool/fees
if (response.empty()) {
return 0;
}
std::stringstream response_ss(response);
boost::property_tree::ptree response_pt;
boost::property_tree::read_json(response_ss, response_pt);
if (response_pt.get_child("limits").count("min") && response_pt.get_child("limits").count("max")) {
auto limits_min_str = response_pt.get_child("limits.min").data();
auto limits_max_str = response_pt.get_child("limits.max").data();
auto limits_min = std::stoi(limits_min_str);
auto limits_max = std::stoi(limits_max_str);
auto priority_max = (limits_max - (limits_min - 1)) / 2;
if (response_pt.count("regular") && response_pt.count("priority")) {
auto regular_str = response_pt.get_child("regular").data();
auto priority_str = response_pt.get_child("priority").data();
auto regular = std::stoi(regular_str);
auto priority = std::stoi(priority_str);
if (target_block >= priority_max) {
return regular * 1000;
} else {
return priority * 1000;
}
}
}
return 0;
}
}} // namespace graphene::peerplays_sidechain

View file

@ -149,79 +149,8 @@ bool libbitcoin_client::get_is_test_net() {
obelisk_client.blockchain_fetch_block_header(error_handler, block_header_handler, 0);
obelisk_client.wait();
return result;
}
uint64_t libbitcoin_client::get_fee_from_trx(libbitcoin::chain::transaction trx) {
bool general_fee_est_error = false;
if (trx.is_coinbase()) {
return 0;
}
const auto total_output_value = trx.total_output_value();
// get the inputs and from inputs previous outputs
std::map<libbitcoin::hash_digest, std::vector<uint32_t>> prev_out_trxs;
for (auto &ins : trx.inputs()) {
const auto &prev_out = ins.previous_output();
prev_out_trxs[prev_out.hash()].emplace_back(prev_out.index());
}
// fetch the trx to get total input value
uint64_t total_input_value = 0;
auto transaction_handler = [&](const libbitcoin::chain::transaction &tx_handler) {
std::vector<uint32_t> indexes = prev_out_trxs[tx_handler.hash()];
for (auto &index : indexes) {
total_input_value += tx_handler.outputs()[index].value();
}
};
auto error_handler = [&](const std::error_code &ec) {
elog("error on fetching trx ${error_code}", ("error_code", ec.message()));
general_fee_est_error = true;
};
for (const auto &iter : prev_out_trxs) {
if (general_fee_est_error) {
break;
}
obelisk_client.blockchain_fetch_transaction2(error_handler, transaction_handler, iter.first);
obelisk_client.wait();
}
if (total_input_value >= total_output_value) {
return total_input_value - total_output_value;
} else {
// something is really wrong if this happens,so we are going to mark as an error
elog("On fee estimation something is wrong in total inputs and total outputs for trx hash: ${hash}",
("hash", libbitcoin::config::hash256(trx.hash()).to_string()));
return 0;
}
}
uint64_t libbitcoin_client::get_average_fee_from_trxs(std::vector<libbitcoin::chain::transaction> trx_list) {
std::vector<uint64_t> fee_per_trxs;
for (auto &trx : trx_list) {
uint64_t fee = get_fee_from_trx(trx);
if (fee > 0) {
fee_per_trxs.emplace_back(fee);
}
}
uint64_t average_estimated_fee = 0;
if (fee_per_trxs.size()) {
for (const auto &fee : fee_per_trxs) {
average_estimated_fee += fee;
}
average_estimated_fee /= fee_per_trxs.size();
}
return average_estimated_fee;
}
}} // namespace graphene::peerplays_sidechain
} // namespace graphene::peerplays_sidechain

View file

@ -2,56 +2,29 @@
#include <regex>
#include <sstream>
#include <string>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/xpressive/xpressive.hpp>
#include <boost/asio/buffers_iterator.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/beast/http.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/xpressive/xpressive.hpp>
#include <curl/curl.h>
#include <fc/crypto/base64.hpp>
#include <fc/log/logger.hpp>
#include <graphene/peerplays_sidechain/common/utils.hpp>
namespace graphene { namespace peerplays_sidechain {
struct rpc_reply {
uint16_t status;
std::string body;
};
class rpc_connection {
public:
rpc_connection(const rpc_credentials &_credentials, bool _debug_rpc_calls);
std::string send_post_request(std::string method, std::string params, bool show_log);
std::string get_url() const;
protected:
rpc_credentials credentials;
bool debug_rpc_calls;
std::string protocol;
std::string host;
std::string port;
std::string target;
std::string authorization;
uint32_t request_id;
private:
rpc_reply send_post_request(std::string body, bool show_log);
boost::beast::net::io_context ioc;
boost::beast::net::ip::tcp::resolver resolver;
boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp> results;
};
rpc_connection::rpc_connection(const rpc_credentials &_credentials, bool _debug_rpc_calls) :
credentials(_credentials),
rpc_client::rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls) :
url(_url),
user(_user),
password(_password),
debug_rpc_calls(_debug_rpc_calls),
request_id(0),
resolver(ioc) {
@ -61,7 +34,7 @@ rpc_connection::rpc_connection(const rpc_credentials &_credentials, bool _debug_
boost::xpressive::smatch sm;
if (boost::xpressive::regex_search(credentials.url, sm, sr)) {
if (boost::xpressive::regex_search(url, sm, sr)) {
protocol = sm["Protocol"];
if (protocol.empty()) {
protocol = "http";
@ -82,84 +55,59 @@ rpc_connection::rpc_connection(const rpc_credentials &_credentials, bool _debug_
target = "/";
}
authorization = "Basic " + base64_encode(credentials.user + ":" + credentials.password);
authorization = "Basic " + fc::base64_encode(user + ":" + password);
results = resolver.resolve(host, port);
} else {
elog("Invalid URL: ${url}", ("url", credentials.url));
elog("Invalid URL: ${url}", ("url", url));
}
}
std::string rpc_connection::get_url() const {
return credentials.url;
}
std::string rpc_client::retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx) {
if (reply_str.empty()) {
wlog("RPC call ${function}, empty reply string", ("function", __FUNCTION__));
std::stringstream ss(reply_str);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (json.find("result") == json.not_found()) {
return "";
}
try {
std::stringstream ss(reply_str);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (json.find("result") == json.not_found()) {
return "";
auto json_result = json.get_child_optional("result");
if (json_result) {
boost::property_tree::ptree array_ptree = json_result.get();
if (!array_path.empty()) {
array_ptree = json_result.get().get_child(array_path);
}
auto json_result = json.get_child_optional("result");
if (json_result) {
boost::property_tree::ptree array_ptree = json_result.get();
if (!array_path.empty()) {
array_ptree = json_result.get().get_child(array_path);
}
uint32_t array_el_idx = -1;
for (const auto &array_el : array_ptree) {
array_el_idx = array_el_idx + 1;
if (array_el_idx == idx) {
std::stringstream ss_res;
boost::property_tree::json_parser::write_json(ss_res, array_el.second);
return ss_res.str();
}
uint32_t array_el_idx = -1;
for (const auto &array_el : array_ptree) {
array_el_idx = array_el_idx + 1;
if (array_el_idx == idx) {
std::stringstream ss_res;
boost::property_tree::json_parser::write_json(ss_res, array_el.second);
return ss_res.str();
}
}
} catch (const boost::property_tree::json_parser::json_parser_error &e) {
wlog("RPC call ${function} failed: ${e}", ("function", __FUNCTION__)("e", e.what()));
}
return "";
}
std::string rpc_client::retrieve_value_from_reply(std::string reply_str, std::string value_path) {
if (reply_str.empty()) {
wlog("RPC call ${function}, empty reply string", ("function", __FUNCTION__));
std::stringstream ss(reply_str);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (json.find("result") == json.not_found()) {
return "";
}
try {
std::stringstream ss(reply_str);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (json.find("result") == json.not_found()) {
return "";
}
auto json_result = json.get_child_optional("result");
if (json_result) {
return json_result.get().get<std::string>(value_path);
}
return json.get<std::string>("result");
} catch (const boost::property_tree::json_parser::json_parser_error &e) {
wlog("RPC call ${function} failed: ${e}", ("function", __FUNCTION__)("e", e.what()));
auto json_result = json.get_child_optional("result");
if (json_result) {
return json_result.get().get<std::string>(value_path);
}
return "";
return json.get<std::string>("result");
}
std::string rpc_connection::send_post_request(std::string method, std::string params, bool show_log) {
std::string rpc_client::send_post_request(std::string method, std::string params, bool show_log) {
std::stringstream body;
request_id = request_id + 1;
@ -172,33 +120,29 @@ std::string rpc_connection::send_post_request(std::string method, std::string pa
body << " }";
try {
const auto reply = send_post_request(body.str(), show_log);
const auto reply = send_post_request(body.str(), show_log);
if (reply.body.empty()) {
wlog("RPC call ${function} failed", ("function", __FUNCTION__));
return "";
}
if (reply.body.empty()) {
wlog("RPC call ${function} failed", ("function", __FUNCTION__));
return "";
}
std::stringstream ss(std::string(reply.body.begin(), reply.body.end()));
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
std::stringstream ss(std::string(reply.body.begin(), reply.body.end()));
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (json.count("error") && !json.get_child("error").empty()) {
wlog("RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body.str())("msg", ss.str()));
}
if (json.count("error") && !json.get_child("error").empty()) {
wlog("RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body.str())("msg", ss.str()));
}
if (reply.status == 200) {
return ss.str();
}
} catch (const boost::system::system_error &e) {
elog("RPC call ${function} failed: ${e}", ("function", __FUNCTION__)("e", e.what()));
if (reply.status == 200) {
return ss.str();
}
return "";
}
rpc_reply rpc_connection::send_post_request(std::string body, bool show_log) {
rpc_reply rpc_client::send_post_request(std::string body, bool show_log) {
// These object is used as a context for ssl connection
boost::asio::ssl::context ctx(boost::asio::ssl::context::tlsv12_client);
@ -273,7 +217,7 @@ rpc_reply rpc_connection::send_post_request(std::string body, bool show_log) {
reply.body = rbody;
if (show_log) {
ilog("### Request URL: ${url}", ("url", credentials.url));
ilog("### Request URL: ${url}", ("url", url));
ilog("### Request: ${body}", ("body", body));
ilog("### Response: ${rbody}", ("rbody", rbody));
}
@ -281,113 +225,4 @@ rpc_reply rpc_connection::send_post_request(std::string body, bool show_log) {
return reply;
}
rpc_client::rpc_client(sidechain_type _sidechain, const std::vector<rpc_credentials> &_credentials, bool _debug_rpc_calls, bool _simulate_connection_reselection) :
sidechain(_sidechain),
debug_rpc_calls(_debug_rpc_calls),
simulate_connection_reselection(_simulate_connection_reselection) {
FC_ASSERT(_credentials.size());
for (size_t i = 0; i < _credentials.size(); i++)
connections.push_back(new rpc_connection(_credentials[i], _debug_rpc_calls));
n_active_conn = 0;
if (connections.size() > 1)
schedule_connection_selection();
}
void rpc_client::schedule_connection_selection() {
fc::time_point now = fc::time_point::now();
static const int64_t time_to_next_conn_selection = 10 * 1000 * 1000; // 10 sec
fc::time_point next_wakeup = now + fc::microseconds(time_to_next_conn_selection);
connection_selection_task = fc::schedule([this] {
select_connection();
},
next_wakeup, "SON RPC connection selection");
}
void rpc_client::select_connection() {
FC_ASSERT(connections.size() > 1);
const std::lock_guard<std::mutex> lock(conn_mutex);
static const int t_limit = 5 * 1000 * 1000, // 5 sec
quality_diff_threshold = 10 * 1000; // 10 ms
int best_n = -1;
int best_quality = -1;
std::vector<uint64_t> head_block_numbers;
head_block_numbers.resize(connections.size());
std::vector<int> qualities;
qualities.resize(connections.size());
for (size_t n = 0; n < connections.size(); n++) {
rpc_connection &conn = *connections[n];
int quality = 0;
head_block_numbers[n] = std::numeric_limits<uint64_t>::max();
// ping n'th node
if (debug_rpc_calls)
ilog("### Ping ${sidechain} node #${n}, ${url}", ("sidechain", fc::reflector<sidechain_type>::to_string(sidechain))("n", n)("url", conn.get_url()));
fc::time_point t_sent = fc::time_point::now();
uint64_t head_block_number = ping(conn);
fc::time_point t_received = fc::time_point::now();
int t = (t_received - t_sent).count();
// evaluate n'th node reply quality and switch to it if it's better
if (head_block_number != std::numeric_limits<uint64_t>::max()) {
if (simulate_connection_reselection)
t += rand() % 10;
FC_ASSERT(t != -1);
head_block_numbers[n] = head_block_number;
if (t < t_limit)
quality = t_limit - t; // the less time, the higher quality
// look for the best quality
if (quality > best_quality) {
best_n = n;
best_quality = quality;
}
}
qualities[n] = quality;
}
FC_ASSERT(best_n != -1 && best_quality != -1);
if (best_n != n_active_conn) { // if the best client is not the current one, ...
uint64_t active_head_block_number = head_block_numbers[n_active_conn];
if ((active_head_block_number == std::numeric_limits<uint64_t>::max() // ...and the current one has no known head block...
|| head_block_numbers[best_n] >= active_head_block_number) // ...or the best client's head is more recent than the current, ...
&& best_quality > qualities[n_active_conn] + quality_diff_threshold) { // ...and the new client's quality exceeds current more than by threshold
n_active_conn = best_n; // ...then select new one
if (debug_rpc_calls)
ilog("### Reselected ${sidechain} node to #${n}, ${url}", ("sidechain", fc::reflector<sidechain_type>::to_string(sidechain))("n", n_active_conn)("url", connections[n_active_conn]->get_url()));
}
}
schedule_connection_selection();
}
rpc_connection &rpc_client::get_active_connection() const {
return *connections[n_active_conn];
}
std::string rpc_client::send_post_request(std::string method, std::string params, bool show_log) {
const std::lock_guard<std::mutex> lock(conn_mutex);
return send_post_request(get_active_connection(), method, params, show_log);
}
std::string rpc_client::send_post_request(rpc_connection &conn, std::string method, std::string params, bool show_log) {
return conn.send_post_request(method, params, show_log);
}
rpc_client::~rpc_client() {
try {
if (connection_selection_task.valid())
connection_selection_task.cancel_and_wait(__FUNCTION__);
} catch (fc::canceled_exception &) {
// Expected exception. Move along.
} catch (fc::exception &e) {
edump((e.to_detail_string()));
}
}
}} // namespace graphene::peerplays_sidechain

View file

@ -1,64 +1,8 @@
#include <graphene/peerplays_sidechain/common/utils.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
namespace graphene { namespace peerplays_sidechain {
const std::string base64_padding[] = {"", "==", "="};
std::string base64_encode(const std::string &s) {
using namespace boost::archive::iterators;
typedef base64_from_binary<transform_width<const char *, 6, 8>> base64_enc;
std::stringstream os;
std::copy(base64_enc(s.c_str()), base64_enc(s.c_str() + s.size()), std::ostream_iterator<char>(os));
os << base64_padding[s.size() % 3];
return os.str();
}
std::string base64_decode(const std::string &s) {
using namespace boost::archive::iterators;
typedef transform_width<binary_from_base64<const char *>, 8, 6> base64_dec;
std::stringstream os;
unsigned int size = s.size();
if (size && s[size - 1] == '=') {
--size;
if (size && s[size - 1] == '=')
--size;
}
if (size == 0)
return std::string();
std::copy(base64_dec(s.data()), base64_dec(s.data() + size), std::ostream_iterator<char>(os));
return os.str();
}
std::string object_id_to_string(graphene::chain::object_id_type id) {
std::string object_id = fc::to_string(id.space()) + "." +
fc::to_string(id.type()) + "." +
fc::to_string(id.instance());
return object_id;
}
graphene::chain::object_id_type string_to_object_id(const std::string &id) {
std::vector<std::string> strs;
boost::split(strs, id, boost::is_any_of("."));
if (strs.size() != 3) {
elog("Wrong object_id format: ${id}", ("id", id));
return graphene::chain::object_id_type{};
}
auto s = boost::lexical_cast<int>(strs.at(0));
auto t = boost::lexical_cast<int>(strs.at(1));
return graphene::chain::object_id_type{(uint8_t)s, (uint8_t)t, boost::lexical_cast<uint64_t>(strs.at(2))};
}
}} // namespace graphene::peerplays_sidechain

View file

@ -1,267 +0,0 @@
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
#include <fc/exception/exception.hpp>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
//! base_decoder
boost::multiprecision::uint256_t base_decoder::decode_uint256(const std::string &value) {
boost::multiprecision::uint256_t result = 0;
boost::multiprecision::uint256_t power(1);
uint8_t digit;
int pos = value.size() - 1;
while (pos >= 0) {
digit = 0;
if ('0' <= value[pos] && value[pos] <= '9') {
digit = value[pos] - '0';
} else if ('a' <= value[pos] && value[pos] <= 'z') {
digit = value[pos] - 'a' + 10;
}
result += digit * power;
pos--;
power *= 16;
}
return result;
}
std::string base_decoder::decode_address(const std::string &value) {
return value.substr(24, 40);
}
//! deposit_erc20_decoder
const std::string deposit_erc20_decoder::function_signature = "97feb926"; //! depositERC20(address,uint256)
fc::optional<deposit_erc20_transaction> deposit_erc20_decoder::decode(const std::string &input) {
const auto input_without_0x = remove_0x(input);
if (function_signature != input_without_0x.substr(0, 8)) {
return fc::optional<deposit_erc20_transaction>{};
}
if (input_without_0x.size() != 136) {
return fc::optional<deposit_erc20_transaction>{};
}
deposit_erc20_transaction erc_20;
erc_20.token = add_0x(base_decoder::decode_address(input_without_0x.substr(8, 64)));
erc_20.amount = base_decoder::decode_uint256(input_without_0x.substr(72, 64));
return erc_20;
}
//! rlp_decoder
namespace {
const signed char p_util_hexdigit[256] =
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
}
std::vector<std::string> rlp_decoder::decode(const std::string &str) {
size_t consumed = 0;
const auto raw_vec = parse_hex(str);
const std::vector<std::string> rlp_array = decode_rlp(raw_vec.data(), raw_vec.size(), consumed);
std::vector<std::string> result_array;
for (const auto &rlp : decode_rlp(raw_vec.data(), raw_vec.size(), consumed)) {
result_array.emplace_back(bytes2hex(rlp));
}
return result_array;
}
std::vector<std::string> rlp_decoder::decode_rlp(const unsigned char *raw, size_t len, size_t &consumed) {
std::vector<std::string> rlp_result;
consumed = 0;
const unsigned char *end = raw + len;
const size_t prefixlen = 1;
unsigned char ch = *raw;
if (len < 1) {
return rlp_result;
}
// Case 1: [prefix is 1-byte data buffer]
if (ch <= 0x7f) {
const unsigned char *tok_start = raw;
const unsigned char *tok_end = tok_start + prefixlen;
FC_ASSERT(tok_end <= end);
// parsing done; assign data buffer value.
const std::vector<unsigned char> buf{tok_start, tok_end};
rlp_result.emplace_back(buf.cbegin(), buf.cend());
consumed = buf.size();
}
// Case 2: [prefix, including buffer length][data]
else if ((ch >= 0x80) && (ch <= 0xb7)) {
const size_t blen = ch - 0x80;
const size_t expected = prefixlen + blen;
if (len < expected)
return std::vector<std::string>{};
const unsigned char *tok_start = raw + 1;
const unsigned char *tok_end = tok_start + blen;
FC_ASSERT(tok_end <= end);
// require minimal encoding
if ((blen == 1) && (tok_start[0] <= 0x7f))
return std::vector<std::string>{};
// parsing done; assign data buffer value.
const std::vector<unsigned char> buf{tok_start, tok_end};
rlp_result.emplace_back(buf.cbegin(), buf.cend());
consumed = expected;
}
// Case 3: [prefix][buffer length][data]
else if ((ch >= 0xb8) && (ch <= 0xbf)) {
const size_t uintlen = ch - 0xb7;
size_t expected = prefixlen + uintlen;
if (len < expected)
return std::vector<std::string>{};
FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen);
const unsigned char *tok_start = raw + prefixlen;
if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes
return std::vector<std::string>{};
// read buffer length
const uint64_t slen = to_int(tok_start, uintlen);
// validate buffer length, including possible addition overflows.
expected = prefixlen + uintlen + slen;
if ((slen < (RLP_listStart - RLP_bufferLenStart - RLP_maxUintLen)) || (expected > len) || (slen > len))
return std::vector<std::string>{};
// parsing done; assign data buffer value.
tok_start = raw + prefixlen + uintlen;
const unsigned char *tok_end = tok_start + slen;
const std::vector<unsigned char> buf{tok_start, tok_end};
rlp_result.emplace_back(buf.cbegin(), buf.cend());
consumed = expected;
}
// Case 4: [prefix][list]
else if ((ch >= 0xc0) && (ch <= 0xf7)) {
const size_t payloadlen = ch - 0xc0;
const size_t expected = prefixlen + payloadlen;
// read list payload
const auto array = decode_array(raw, len, 0, payloadlen);
rlp_result.insert(rlp_result.end(), array.cbegin(), array.cend());
consumed = expected;
}
// Case 5: [prefix][list length][list]
else {
FC_ASSERT((ch >= 0xf8) && (ch <= 0xff));
const size_t uintlen = ch - 0xf7;
const size_t expected = prefixlen + uintlen;
if (len < expected)
return std::vector<std::string>{};
FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen);
const unsigned char *tok_start = raw + prefixlen;
if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes
return std::vector<std::string>{};
// read list length
const size_t payloadlen = to_int(tok_start, uintlen);
// special requirement for non-immediate length
if (payloadlen < (0x100 - RLP_listStart - RLP_maxUintLen))
return std::vector<std::string>{};
// read list payload
const auto array = decode_array(raw, len, uintlen, payloadlen);
rlp_result.insert(rlp_result.end(), array.cbegin(), array.cend());
consumed = prefixlen + uintlen + payloadlen;
}
return rlp_result;
}
std::vector<std::string> rlp_decoder::decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen) {
std::vector<std::string> rlp_result;
const size_t prefixlen = 1;
// validate list length, including possible addition overflows.
const size_t expected = prefixlen + uintlen + payloadlen;
if ((expected > len) || (payloadlen > len))
return std::vector<std::string>{};
size_t child_len = payloadlen;
const unsigned char *list_ent = raw + prefixlen + uintlen;
// recursively read until payloadlen bytes parsed, or error
while (child_len > 0) {
size_t child_consumed = 0;
const auto val = decode_rlp(list_ent, child_len, child_consumed);
rlp_result.insert(rlp_result.end(), val.cbegin(), val.cend());
list_ent += child_consumed;
child_len -= child_consumed;
}
return rlp_result;
}
uint64_t rlp_decoder::to_int(const unsigned char *raw, size_t len) {
if (len == 0)
return 0;
else if (len == 1)
return *raw;
else
return (raw[len - 1]) + (to_int(raw, len - 1) * 256);
}
std::vector<unsigned char> rlp_decoder::parse_hex(const std::string &str) {
return parse_hex(str.c_str());
}
std::vector<unsigned char> rlp_decoder::parse_hex(const char *psz) {
// convert hex dump to vector
std::vector<unsigned char> vch;
while (true) {
while (isspace(*psz))
psz++;
signed char c = hex_digit(*psz++);
if (c == (signed char)-1)
break;
unsigned char n = (c << 4);
c = hex_digit(*psz++);
if (c == (signed char)-1)
break;
n |= c;
vch.push_back(n);
}
return vch;
}
signed char rlp_decoder::hex_digit(char c) {
return p_util_hexdigit[(unsigned char)c];
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,171 +0,0 @@
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <boost/algorithm/hex.hpp>
#include <boost/format.hpp>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
//! base_encoder
std::string base_encoder::encode_uint256(boost::multiprecision::uint256_t value) {
return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str();
}
std::string base_encoder::encode_address(const std::string &value) {
return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str();
}
std::string base_encoder::encode_string(const std::string &value) {
std::string data = (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value.size())).str();
data += boost::algorithm::hex(value);
if (value.size() % 32 != 0) {
data += std::string((64 - value.size() * 2 % 64), '0');
}
return data;
}
//! update_owners_encoder
const std::string update_owners_encoder::function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string)
std::string update_owners_encoder::encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) {
std::string data = add_0x(function_signature);
data += base_encoder::encode_uint256(64);
data += base_encoder::encode_uint256((owners_weights.size() * 2 + 3) * 32);
data += base_encoder::encode_uint256(owners_weights.size());
for (const auto &owner : owners_weights) {
data += base_encoder::encode_address(owner.first);
data += base_encoder::encode_uint256(owner.second);
}
data += base_encoder::encode_string(object_id);
return data;
}
//! withdrawal_encoder
const std::string withdrawal_encoder::function_signature = "e088747b"; //! withdraw(address,uint256,string)
std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) {
std::string data = add_0x(function_signature);
data += base_encoder::encode_address(to);
data += base_encoder::encode_uint256(amount);
data += base_encoder::encode_uint256(32 * 3);
data += base_encoder::encode_string(object_id);
return data;
}
//! withdrawal_erc20_encoder
const std::string withdrawal_erc20_encoder::function_signature = "483c0467"; //! withdrawERC20(address,address,uint256,string)
std::string withdrawal_erc20_encoder::encode(const std::string &token, const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) {
std::string data = add_0x(function_signature);
data += base_encoder::encode_address(token);
data += base_encoder::encode_address(to);
data += base_encoder::encode_uint256(amount);
data += base_encoder::encode_uint256(32 * 4);
data += base_encoder::encode_string(object_id);
return data;
}
//! signature_encoder
const std::string update_owners_function_signature = "9d608673"; //! updateOwners((bytes,(uint8,bytes32,bytes32))[])
const std::string withdrawal_function_signature = "daac6c81"; //! withdraw((bytes,(uint8,bytes32,bytes32))[])
const std::string withdrawal_erc20_function_signature = "d2bf2866"; //! withdrawERC20((bytes,(uint8,bytes32,bytes32))[])
signature_encoder::signature_encoder(const std::string &function_hash) :
function_signature{function_hash} {
}
std::string signature_encoder::get_function_signature_from_transaction(const std::string &transaction) {
const std::string tr = remove_0x(transaction);
if (tr.substr(0, 8) == update_owners_encoder::function_signature)
return update_owners_function_signature;
if (tr.substr(0, 8) == withdrawal_encoder::function_signature)
return withdrawal_function_signature;
if (tr.substr(0, 8) == withdrawal_erc20_encoder::function_signature)
return withdrawal_erc20_function_signature;
return "";
}
std::string signature_encoder::encode(const std::vector<encoded_sign_transaction> &transactions) const {
std::string data = add_0x(function_signature);
data += base_encoder::encode_uint256(32);
data += base_encoder::encode_uint256(transactions.size());
size_t offset = (transactions.size()) * 32;
for (const auto &transaction : transactions) {
data += base_encoder::encode_uint256(offset);
const auto transaction_data = remove_0x(transaction.data);
offset += 5 * 32 + transaction_data.size() / 2;
if (transaction_data.size() / 2 % 32 != 0) {
offset += 32 - transaction_data.size() / 2 % 32;
}
}
for (const auto &transaction : transactions) {
data += base_encoder::encode_uint256(4 * 32);
data += base_encoder::encode_address(transaction.sign.v);
data += base_encoder::encode_address(transaction.sign.r);
data += base_encoder::encode_address(transaction.sign.s);
const auto transaction_data = remove_0x(transaction.data);
data += base_encoder::encode_uint256(transaction_data.size() / 2);
data += transaction_data;
if (transaction_data.size() % 64 != 0) {
data += std::string((64 - transaction_data.size() % 64), '0');
}
}
return data;
}
//! rlp_encoder
std::string rlp_encoder::encode(const std::string &s) {
return encode_rlp(hex2bytes(s));
}
std::string rlp_encoder::encode_length(int len, int offset) {
if (len < 56) {
std::string temp;
temp = (char)(len + offset);
return temp;
} else {
const std::string hexLength = to_hex(len);
const int lLength = hexLength.size() / 2;
const std::string fByte = to_hex(offset + 55 + lLength);
return hex2bytes(fByte + hexLength);
}
}
std::string rlp_encoder::hex2bytes(const std::string &s) {
std::string dest;
const auto s_final = s.size() % 2 == 0 ? s : "0" + s;
dest.resize(s_final.size() / 2);
hex2bin(s_final.c_str(), &dest[0]);
return dest;
}
std::string rlp_encoder::encode_rlp(const std::string &s) {
if (s.size() == 1 && (unsigned char)s[0] < 128)
return s;
else
return encode_length(s.size(), 128) + s;
}
int rlp_encoder::char2int(char input) {
if (input >= '0' && input <= '9')
return input - '0';
if (input >= 'A' && input <= 'F')
return input - 'A' + 10;
if (input >= 'a' && input <= 'f')
return input - 'a' + 10;
return -1;
}
void rlp_encoder::hex2bin(const char *src, char *target) {
while (*src && src[1]) {
*(target++) = char2int(*src) * 16 + char2int(src[1]);
src += 2;
}
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,243 +0,0 @@
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
#include <boost/algorithm/hex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <secp256k1_recovery.h>
#include <sha3/sha3.h>
#include <fc/crypto/elliptic.hpp>
#include <fc/crypto/hex.hpp>
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
const secp256k1_context *eth_context() {
static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
return ctx;
}
bytes keccak_hash(const std::string &data) {
bytes hash;
hash.resize(32);
const auto transaction_string = boost::algorithm::unhex(remove_0x(data));
keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data());
return hash;
}
signature sign_hash(const bytes &hash, const std::string &chain_id, const std::string &private_key) {
const bytes priv_key = parse_hex(private_key);
int recid = 0;
secp256k1_ecdsa_recoverable_signature sig;
FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), NULL, NULL));
fc::ecc::compact_signature result;
FC_ASSERT(secp256k1_ecdsa_recoverable_signature_serialize_compact(eth_context(), (unsigned char *)result.begin() + 1, &recid, &sig));
unsigned int v = recid + from_hex<unsigned int>(chain_id) * 2 + 35;
bytes r;
for (int i = 1; i < 33; i++)
r.emplace_back((char)result.at(i));
bytes s;
for (int i = 33; i < 65; i++)
s.emplace_back((char)result.at(i));
signature eth_sig;
eth_sig.v = to_hex(v);
eth_sig.r = fc::to_hex((char *)&r[0], r.size());
eth_sig.s = fc::to_hex((char *)&s[0], s.size());
return eth_sig;
}
//! base_transaction
base_transaction::base_transaction(const std::string &raw_tx) {
}
//! transaction
transaction::transaction(const std::string &raw_tx) :
base_transaction{raw_tx} {
deserialize(raw_tx);
}
const transaction &transaction::sign(const std::string &private_key) const {
return *this;
}
std::string transaction::serialize() const {
boost::property_tree::ptree pt;
pt.put("from", from);
pt.put("to", to);
pt.put("data", data);
std::stringstream ss;
boost::property_tree::json_parser::write_json(ss, pt);
return ss.str();
}
void transaction::deserialize(const std::string &raw_tx) {
std::stringstream ss_tx(raw_tx);
boost::property_tree::ptree tx_json;
boost::property_tree::read_json(ss_tx, tx_json);
if (tx_json.count("from"))
from = tx_json.get<std::string>("from");
if (tx_json.count("to"))
to = tx_json.get<std::string>("to");
if (tx_json.count("data"))
data = tx_json.get<std::string>("data");
}
//! raw_transaction
raw_transaction::raw_transaction(const std::string &raw_tx) :
base_transaction{raw_tx} {
deserialize(raw_tx);
}
bytes raw_transaction::hash() const {
return keccak_hash(serialize());
}
signed_transaction raw_transaction::sign(const std::string &private_key) const {
//! Prepare signed transaction
signed_transaction tr;
tr.nonce = nonce;
tr.gas_price = gas_price;
tr.gas_limit = gas_limit;
tr.to = to;
tr.value = value;
tr.data = data;
const auto sig = sign_hash(hash(), chain_id, private_key);
tr.v = sig.v;
tr.r = sig.r;
tr.s = sig.s;
return tr;
}
std::string raw_transaction::serialize() const {
const std::string serialized = rlp_encoder::encode(remove_0x(nonce)) +
rlp_encoder::encode(remove_0x(gas_price)) +
rlp_encoder::encode(remove_0x(gas_limit)) +
rlp_encoder::encode(remove_0x(to)) +
rlp_encoder::encode(remove_0x(value)) +
rlp_encoder::encode(remove_0x(data)) +
rlp_encoder::encode(remove_0x(chain_id)) +
rlp_encoder::encode("") +
rlp_encoder::encode("");
return add_0x(bytes2hex(rlp_encoder::encode_length(serialized.size(), 192) + serialized));
}
void raw_transaction::deserialize(const std::string &raw_tx) {
const auto rlp_array = rlp_decoder::decode(remove_0x(raw_tx));
FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format");
nonce = !rlp_array.at(0).empty() ? add_0x(rlp_array.at(0)) : add_0x("0");
boost::algorithm::to_lower(nonce);
gas_price = add_0x(rlp_array.at(1));
boost::algorithm::to_lower(gas_price);
gas_limit = add_0x(rlp_array.at(2));
boost::algorithm::to_lower(gas_limit);
to = add_0x(rlp_array.at(3));
boost::algorithm::to_lower(to);
value = !rlp_array.at(4).empty() ? add_0x(rlp_array.at(4)) : add_0x("0");
boost::algorithm::to_lower(value);
data = !rlp_array.at(5).empty() ? add_0x(rlp_array.at(5)) : "";
boost::algorithm::to_lower(data);
chain_id = add_0x(rlp_array.at(6));
boost::algorithm::to_lower(chain_id);
}
//! signed_transaction
signed_transaction::signed_transaction(const std::string &raw_tx) :
base_transaction{raw_tx} {
deserialize(raw_tx);
}
std::string signed_transaction::recover(const std::string &chain_id) const {
fc::ecc::compact_signature input64;
fc::from_hex(r, (char *)&input64.at(1), 32);
const int recid = from_hex<unsigned int>(v) - from_hex<unsigned int>(chain_id) * 2 - 35;
fc::from_hex(std::to_string(recid), (char *)&input64.at(0), 1);
fc::from_hex(s, (char *)&input64.at(33), 32);
secp256k1_ecdsa_recoverable_signature sig;
FC_ASSERT(secp256k1_ecdsa_recoverable_signature_parse_compact(eth_context(), &sig, (const unsigned char *)&input64.data[1], recid));
raw_transaction tr;
tr.nonce = nonce;
tr.gas_price = gas_price;
tr.gas_limit = gas_limit;
tr.to = to;
tr.value = value;
tr.data = data;
tr.chain_id = chain_id;
secp256k1_pubkey rawPubkey;
FC_ASSERT(secp256k1_ecdsa_recover(eth_context(), &rawPubkey, &sig, (const unsigned char *)tr.hash().data()));
std::array<uint8_t, 65> pubkey;
size_t biglen = 65;
FC_ASSERT(secp256k1_ec_pubkey_serialize(eth_context(), pubkey.data(), &biglen, &rawPubkey, SECP256K1_EC_UNCOMPRESSED));
const std::string out = std::string(pubkey.begin(), pubkey.end()).substr(1);
bytes hash;
hash.resize(32);
keccak_256((const unsigned char *)out.data(), out.size(), (unsigned char *)hash.data());
return add_0x(fc::to_hex((char *)&hash[0], hash.size()).substr(24));
}
std::string signed_transaction::serialize() const {
const std::string serialized = rlp_encoder::encode(remove_0x(nonce)) +
rlp_encoder::encode(remove_0x(gas_price)) +
rlp_encoder::encode(remove_0x(gas_limit)) +
rlp_encoder::encode(remove_0x(to)) +
rlp_encoder::encode(remove_0x(value)) +
rlp_encoder::encode(remove_0x(data)) +
rlp_encoder::encode(remove_0x(v)) +
rlp_encoder::encode(remove_leading_00(remove_0x(r))) +
rlp_encoder::encode(remove_leading_00(remove_0x(s)));
return add_0x(bytes2hex(rlp_encoder::encode_length(serialized.size(), 192) + serialized));
}
void signed_transaction::deserialize(const std::string &raw_tx) {
const auto rlp_array = rlp_decoder::decode(remove_0x(raw_tx));
FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format");
nonce = !rlp_array.at(0).empty() ? add_0x(rlp_array.at(0)) : add_0x("0");
boost::algorithm::to_lower(nonce);
gas_price = add_0x(rlp_array.at(1));
boost::algorithm::to_lower(gas_price);
gas_limit = add_0x(rlp_array.at(2));
boost::algorithm::to_lower(gas_limit);
to = add_0x(rlp_array.at(3));
boost::algorithm::to_lower(to);
value = !rlp_array.at(4).empty() ? add_0x(rlp_array.at(4)) : add_0x("0");
boost::algorithm::to_lower(value);
data = !rlp_array.at(5).empty() ? add_0x(rlp_array.at(5)) : "";
boost::algorithm::to_lower(data);
v = add_0x(rlp_array.at(6));
boost::algorithm::to_lower(v);
r = add_0x(add_leading_00(rlp_array.at(7)));
boost::algorithm::to_lower(r);
s = add_0x(add_leading_00(rlp_array.at(8)));
boost::algorithm::to_lower(s);
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,36 +0,0 @@
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
signature::signature(const std::string &sign) {
deserialize(sign);
}
std::string signature::serialize() const {
boost::property_tree::ptree pt;
pt.put("v", v);
pt.put("r", r);
pt.put("s", s);
std::stringstream ss;
boost::property_tree::json_parser::write_json(ss, pt);
return ss.str();
}
void signature::deserialize(const std::string &raw_tx) {
std::stringstream ss_tx(raw_tx);
boost::property_tree::ptree tx_json;
boost::property_tree::read_json(ss_tx, tx_json);
if (tx_json.count("v"))
v = tx_json.get<std::string>("v");
if (tx_json.count("r"))
r = tx_json.get<std::string>("r");
if (tx_json.count("s"))
s = tx_json.get<std::string>("s");
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,72 +0,0 @@
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
#include <fc/crypto/hex.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
bytes parse_hex(const std::string &str) {
bytes vec(str.size() / 2);
fc::from_hex(str, vec.data(), vec.size());
return vec;
}
std::string bytes2hex(const std::string &s) {
std::string dest;
for (const auto &i : s)
dest += uchar2Hex((unsigned char)i);
return dest;
}
std::string uchar2Hex(unsigned char n) {
std::string dest;
dest.resize(2);
sprintf(&dest[0], "%X", n);
if (n < (unsigned char)16) {
dest[1] = dest[0];
dest[0] = '0';
}
return dest;
}
std::string add_0x(const std::string &s) {
if (s.size() > 1) {
if (s.substr(0, 2) == "0x")
return s;
}
return "0x" + s;
}
std::string remove_0x(const std::string &s) {
if (s.size() > 1) {
if (s.substr(0, 2) == "0x")
return s.substr(2);
}
return s;
}
std::string add_leading_00(const std::string &s) {
std::string result = s;
while (result.size() < 64) {
result = "00" + result;
}
return result;
}
std::string remove_leading_00(const std::string &s) {
std::string result = s;
while (result.size() > 1 && result.substr(0, 2) == "00") {
result = result.substr(2);
}
return result;
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,39 +0,0 @@
#pragma once
#include <curl/curl.h>
#include <cstdint>
#include <functional>
#include <map>
#include <string>
#include <vector>
typedef std::function<uint64_t()> get_fee_func_type;
namespace graphene { namespace peerplays_sidechain {
class estimate_fee_external {
public:
estimate_fee_external();
~estimate_fee_external();
std::vector<std::pair<std::string, uint64_t>> get_fee_external(uint16_t target_block);
private:
std::string get_response(std::string url);
// Here add your custom parser for external url. Take care of incremental name
// and populate the list of url_parsers bellow paired with the function
uint64_t parse_and_get_fee_1();
uint64_t parse_and_get_fee_2();
uint64_t parse_and_get_fee_3();
const std::map<std::string, get_fee_func_type> url_get_fee_parsers{
{"https://www.bitgo.com/api/v2/btc/tx/fee", std::bind(&estimate_fee_external::parse_and_get_fee_1, this)},
{"https://bitcoiner.live/api/fees/estimates/latest", std::bind(&estimate_fee_external::parse_and_get_fee_2, this)},
{"https://api.blockchain.info/mempool/fees", std::bind(&estimate_fee_external::parse_and_get_fee_3, this)}};
std::string response;
uint16_t target_block;
CURL *curl{nullptr};
};
}} // namespace graphene::peerplays_sidechain

View file

@ -5,13 +5,9 @@
#include <bitcoin/system/chain/block.hpp>
#include <boost/signals2.hpp>
#include <mutex>
#define LIBBITCOIN_SERVER_TIMEOUT (10)
#define LIBBITCOIN_SERVER_RETRIES (100)
#define DEAFULT_LIBBITCOIN_TRX_FEE (20000)
#define MAX_TRXS_IN_MEMORY_POOL (30000)
#define MIN_TRXS_IN_BUCKET (100)
#define GENESIS_MAINNET_HASH "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
#define GENESIS_TESTNET_HASH "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
@ -34,8 +30,6 @@ public:
std::string send_transaction(const std::string tx);
libbitcoin::chain::output::list get_transaction(std::string tx_id, std::string &tx_hash, uint32_t &confirmitions);
std::vector<list_unspent_replay> listunspent(std::string address, double amount);
uint64_t get_average_fee_from_trxs(std::vector<libbitcoin::chain::transaction> trx_list);
uint64_t get_fee_from_trx(libbitcoin::chain::transaction trx);
bool get_is_test_net();
private:

View file

@ -1,5 +1,4 @@
#pragma once
#include <fc/crypto/elliptic.hpp>
#include <fc/crypto/hex.hpp>
#include <graphene/peerplays_sidechain/bitcoin/types.hpp>

View file

@ -3,52 +3,43 @@
#include <cstdint>
#include <string>
#include <fc/thread/future.hpp>
#include <fc/thread/thread.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/beast/core.hpp>
#include <graphene/peerplays_sidechain/defs.hpp>
namespace graphene { namespace peerplays_sidechain {
class rpc_connection;
struct rpc_credentials {
std::string url;
std::string user;
std::string password;
struct rpc_reply {
uint16_t status;
std::string body;
};
class rpc_client {
public:
const sidechain_type sidechain;
rpc_client(sidechain_type _sidechain, const std::vector<rpc_credentials> &_credentials, bool _debug_rpc_calls, bool _simulate_connection_reselection);
~rpc_client();
rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls);
protected:
bool debug_rpc_calls;
bool simulate_connection_reselection;
std::string retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx);
std::string retrieve_value_from_reply(std::string reply_str, std::string value_path);
std::string send_post_request(std::string method, std::string params, bool show_log);
static std::string send_post_request(rpc_connection &conn, std::string method, std::string params, bool show_log);
std::string url;
std::string protocol;
std::string host;
std::string port;
std::string target;
std::string authorization;
static std::string retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx);
static std::string retrieve_value_from_reply(std::string reply_str, std::string value_path);
std::string user;
std::string password;
bool debug_rpc_calls;
uint32_t request_id;
private:
std::vector<rpc_connection *> connections;
int n_active_conn;
fc::future<void> connection_selection_task;
std::mutex conn_mutex;
rpc_reply send_post_request(std::string body, bool show_log);
rpc_connection &get_active_connection() const;
void select_connection();
void schedule_connection_selection();
virtual uint64_t ping(rpc_connection &conn) const = 0;
boost::beast::net::io_context ioc;
boost::beast::net::ip::tcp::resolver resolver;
boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp> results;
};
}} // namespace graphene::peerplays_sidechain

View file

@ -2,12 +2,4 @@
#include <graphene/chain/protocol/asset.hpp>
namespace graphene { namespace peerplays_sidechain {
std::string base64_encode(const std::string &s);
std::string base64_decode(const std::string &s);
std::string object_id_to_string(graphene::chain::object_id_type id);
graphene::chain::object_id_type string_to_object_id(const std::string &id);
}} // namespace graphene::peerplays_sidechain

View file

@ -57,16 +57,10 @@ struct info_for_vin {
bool resend = false;
};
enum class sidechain_event_type {
deposit,
withdrawal
};
struct sidechain_event_data {
fc::time_point_sec timestamp;
uint32_t block_num;
sidechain_type sidechain;
sidechain_event_type type;
std::string sidechain_uid;
std::string sidechain_transaction_id;
std::string sidechain_from;

View file

@ -1,49 +0,0 @@
#pragma once
#include <boost/multiprecision/cpp_int.hpp>
#include <string>
#include <vector>
#include <fc/optional.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
class base_decoder {
public:
static boost::multiprecision::uint256_t decode_uint256(const std::string &value);
static std::string decode_address(const std::string &value);
};
struct deposit_erc20_transaction {
std::string token;
boost::multiprecision::uint256_t amount;
};
class deposit_erc20_decoder {
public:
static const std::string function_signature;
static fc::optional<deposit_erc20_transaction> decode(const std::string &input);
};
class rlp_decoder {
private:
enum RLP_constants {
RLP_maxUintLen = 8,
RLP_bufferLenStart = 0x80,
RLP_listStart = 0xc0,
};
public:
static std::vector<std::string> decode(const std::string &str);
private:
static std::vector<std::string> decode_rlp(const unsigned char *raw, size_t len, size_t &consumed);
static std::vector<std::string> decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen);
static uint64_t to_int(const unsigned char *raw, size_t len);
static std::vector<unsigned char> parse_hex(const std::string &str);
static std::vector<unsigned char> parse_hex(const char *psz);
static signed char hex_digit(char c);
};
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,67 +0,0 @@
#pragma once
#include <boost/multiprecision/cpp_int.hpp>
#include <string>
#include <vector>
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
struct encoded_sign_transaction {
std::string data;
signature sign;
};
class base_encoder {
public:
static std::string encode_uint256(boost::multiprecision::uint256_t value);
static std::string encode_address(const std::string &value);
static std::string encode_string(const std::string &value);
};
class update_owners_encoder {
public:
static const std::string function_signature;
static std::string encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id);
};
class withdrawal_encoder {
public:
static const std::string function_signature;
static std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id);
};
class withdrawal_erc20_encoder {
public:
static const std::string function_signature;
static std::string encode(const std::string &token, const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id);
};
class signature_encoder {
public:
const std::string function_signature;
signature_encoder(const std::string &function_hash);
static std::string get_function_signature_from_transaction(const std::string &transaction);
std::string encode(const std::vector<encoded_sign_transaction> &transactions) const;
};
class rlp_encoder {
public:
static std::string encode(const std::string &s);
static std::string encode_length(int len, int offset);
static std::string hex2bytes(const std::string &s);
private:
static std::string encode_rlp(const std::string &s);
static int char2int(char input);
static void hex2bin(const char *src, char *target);
};
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,80 +0,0 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
bytes keccak_hash(const std::string &data);
signature sign_hash(const bytes &hash, const std::string &chain_id, const std::string &private_key);
class base_transaction {
public:
base_transaction() = default;
base_transaction(const std::string &raw_tx);
virtual std::string serialize() const = 0;
virtual void deserialize(const std::string &raw_tx) = 0;
};
class transaction : base_transaction {
public:
std::string from;
std::string to;
std::string data;
transaction() = default;
transaction(const std::string &raw_tx);
const transaction &sign(const std::string &private_key) const;
virtual std::string serialize() const override;
virtual void deserialize(const std::string &raw_tx) override;
};
class signed_transaction;
class raw_transaction : base_transaction {
public:
std::string nonce;
std::string gas_price;
std::string gas_limit;
std::string to;
std::string value;
std::string data;
std::string chain_id;
raw_transaction() = default;
raw_transaction(const std::string &raw_tx);
bytes hash() const;
signed_transaction sign(const std::string &private_key) const;
virtual std::string serialize() const override;
virtual void deserialize(const std::string &raw_tx) override;
};
class signed_transaction : base_transaction {
public:
std::string nonce;
std::string gas_price;
std::string gas_limit;
std::string to;
std::string value;
std::string data;
std::string v;
std::string r;
std::string s;
signed_transaction() = default;
signed_transaction(const std::string &raw_tx);
std::string recover(const std::string &chain_id) const;
virtual std::string serialize() const override;
virtual void deserialize(const std::string &raw_tx) override;
};
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,25 +0,0 @@
#pragma once
#include <boost/multiprecision/cpp_int.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
typedef uint64_t chain_id_type;
typedef uint64_t network_id_type;
using bytes = std::vector<char>;
class signature {
public:
std::string v;
std::string r;
std::string s;
signature() = default;
signature(const std::string &sign);
std::string serialize() const;
void deserialize(const std::string &sign);
};
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,43 +0,0 @@
#pragma once
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
bytes parse_hex(const std::string &str);
std::string bytes2hex(const std::string &s);
std::string uchar2Hex(unsigned char n);
std::string add_0x(const std::string &s);
std::string remove_0x(const std::string &s);
std::string add_leading_00(const std::string &s);
std::string remove_leading_00(const std::string &s);
template <typename T>
std::string to_hex(const T &val, bool add_front_zero = true) {
std::stringstream stream;
stream << std::hex << val;
std::string result(stream.str());
if (add_front_zero) {
if (result.size() % 2)
result = "0" + result;
}
return result;
}
template <typename T>
T from_hex(const std::string &s) {
T val;
std::stringstream stream;
stream << std::hex << s;
stream >> val;
return val;
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -22,15 +22,15 @@ typedef fc::ecc::private_key private_key_type;
typedef fc::sha256 chain_id_type;
typedef std::string account_name_type;
typedef fc::ripemd160 block_id_type;
// typedef fc::ripemd160 checksum_type;
//typedef fc::ripemd160 checksum_type;
typedef fc::ripemd160 transaction_id_type;
typedef fc::sha256 digest_type;
typedef fc::ecc::compact_signature signature_type;
typedef fc::safe<int64_t> share_type;
// typedef safe<uint64_t> ushare_type;
// typedef uint16_t weight_type;
// typedef uint32_t contribution_id_type;
// typedef fixed_string<32> custom_id_type;
//typedef safe<uint64_t> ushare_type;
//typedef uint16_t weight_type;
//typedef uint32_t contribution_id_type;
//typedef fixed_string<32> custom_id_type;
struct public_key_type {

View file

@ -54,7 +54,6 @@ public:
void log_son_proposal_retry(sidechain_type sidechain, int op_type, object_id_type object_id);
bool can_son_participate(sidechain_type sidechain, int op_type, object_id_type object_id);
std::map<sidechain_type, std::vector<std::string>> get_son_listener_log();
optional<asset> estimate_withdrawal_transaction_fee(sidechain_type sidechain);
};
}} // namespace graphene::peerplays_sidechain

View file

@ -26,10 +26,9 @@ public:
std::shared_ptr<detail::sidechain_api_impl> my;
std::map<sidechain_type, std::vector<std::string>> get_son_listener_log();
optional<asset> estimate_withdrawal_transaction_fee(sidechain_type sidechain);
};
}} // namespace graphene::peerplays_sidechain
FC_API(graphene::peerplays_sidechain::sidechain_api,
(get_son_listener_log)(estimate_withdrawal_transaction_fee))
(get_son_listener_log))

View file

@ -16,17 +16,14 @@
namespace graphene { namespace peerplays_sidechain {
class sidechain_net_handler {
protected:
sidechain_net_handler(sidechain_type _sidechain, peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options);
public:
sidechain_net_handler(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options);
virtual ~sidechain_net_handler();
sidechain_type get_sidechain() const;
std::vector<std::string> get_sidechain_deposit_addresses() const;
std::vector<std::string> get_sidechain_withdraw_addresses() const;
std::vector<sidechain_transaction_object> get_sidechain_transaction_objects(sidechain_transaction_status status) const;
std::string get_private_key(std::string public_key) const;
sidechain_type get_sidechain();
std::vector<std::string> get_sidechain_deposit_addresses();
std::vector<std::string> get_sidechain_withdraw_addresses();
std::string get_private_key(std::string public_key);
bool proposal_exists(int32_t operation_tag, const object_id_type &object_id, boost::optional<chain::operation &> proposal_op = boost::none);
bool signer_expected(const sidechain_transaction_object &sto, son_id_type signer);
@ -53,12 +50,11 @@ public:
void add_to_son_listener_log(std::string trx_id);
std::vector<std::string> get_son_listener_log();
virtual optional<asset> estimate_withdrawal_transaction_fee() const = 0;
protected:
const sidechain_type sidechain;
peerplays_sidechain_plugin &plugin;
graphene::chain::database &database;
sidechain_type sidechain;
bool debug_rpc_calls;
bool use_bitcoind_client;

View file

@ -1,20 +1,19 @@
#pragma once
#include <graphene/peerplays_sidechain/common/rpc_client.hpp>
#include <graphene/peerplays_sidechain/sidechain_net_handler.hpp>
#include <graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp>
#include <mutex>
#include <string>
#include <thread>
#include <zmq_addon.hpp>
#include <boost/signals2.hpp>
#include <fc/network/http/connection.hpp>
#include <mutex>
#include <fc/network/http/connection.hpp>
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp>
#include <graphene/peerplays_sidechain/bitcoin/estimate_fee_external.hpp>
#include <graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp>
#include <graphene/peerplays_sidechain/common/rpc_client.hpp>
namespace graphene { namespace peerplays_sidechain {
@ -63,16 +62,13 @@ public:
std::string label;
};
virtual uint64_t estimatesmartfee(uint16_t conf_target = 1) = 0;
virtual uint64_t estimatesmartfee(uint16_t conf_target = 128) = 0;
virtual std::vector<info_for_vin> getblock(const block_data &block, int32_t verbosity = 2) = 0;
virtual btc_tx getrawtransaction(const std::string &txid, const bool verbose = false) = 0;
virtual void getnetworkinfo() = 0;
virtual std::string getblockchaininfo() = 0;
virtual std::vector<btc_txout> listunspent_by_address_and_amount(const std::string &address, double transfer_amount, const uint32_t minconf = 1, const uint32_t maxconf = 9999999) = 0;
virtual std::string sendrawtransaction(const std::string &tx_hex) = 0;
virtual void importmulti(const std::vector<multi_params> &address_or_script_array, const bool rescan = true) {
;
};
virtual std::string loadwallet(const std::string &filename) {
return "";
};
@ -82,25 +78,14 @@ public:
virtual bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60) {
return false;
};
void import_trx_to_memory_pool(const libbitcoin::chain::transaction &trx) {
std::unique_lock<std::mutex> lck(libbitcoin_event_mutex);
if (trx_memory_pool.size() < MAX_TRXS_IN_MEMORY_POOL) {
trx_memory_pool.emplace_back(trx);
}
}
protected:
std::vector<libbitcoin::chain::transaction> trx_memory_pool;
std::mutex libbitcoin_event_mutex;
};
class bitcoin_rpc_client : public bitcoin_client_base, public rpc_client {
public:
public:
bitcoin_rpc_client(const std::vector<rpc_credentials> &_credentials, bool _debug_rpc_calls, bool _simulate_connection_reselection);
bitcoin_rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls);
uint64_t estimatesmartfee(uint16_t conf_target = 1);
uint64_t estimatesmartfee(uint16_t conf_target = 128);
std::vector<info_for_vin> getblock(const block_data &block, int32_t verbosity = 2);
btc_tx getrawtransaction(const std::string &txid, const bool verbose = false);
void getnetworkinfo();
@ -113,13 +98,11 @@ public:
std::string walletlock();
bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60);
virtual uint64_t ping(rpc_connection &conn) const override;
private:
std::string ip;
std::string user;
std::string password;
std::string wallet_name;
std::string wallet;
std::string wallet_password;
uint32_t bitcoin_major_version;
};
@ -127,7 +110,7 @@ private:
class bitcoin_libbitcoin_client : public bitcoin_client_base, public libbitcoin_client {
public:
bitcoin_libbitcoin_client(std::string url);
uint64_t estimatesmartfee(uint16_t conf_target = 1);
uint64_t estimatesmartfee(uint16_t conf_target = 128);
std::vector<info_for_vin> getblock(const block_data &block, int32_t verbosity = 2);
btc_tx getrawtransaction(const std::string &txid, const bool verbose = false);
void getnetworkinfo();
@ -137,8 +120,6 @@ public:
private:
bool is_test_net = false;
std::unique_ptr<estimate_fee_external> estimate_fee_ext;
uint64_t current_internal_fee = DEAFULT_LIBBITCOIN_TRX_FEE;
};
// =============================================================================
@ -146,28 +127,24 @@ private:
class zmq_listener_base {
public:
virtual ~zmq_listener_base(){};
zmq_listener_base(std::string _ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port = 0) {
zmq_listener_base(std::string _ip, uint32_t _zmq) {
ip = _ip;
block_zmq_port = _block_zmq_port;
trx_zmq_port = _trx_zmq_port;
zmq_port = _zmq;
stopped = false;
};
virtual void start() = 0;
boost::signals2::signal<void(const block_data &)> block_event_received;
boost::signals2::signal<void(const libbitcoin::chain::transaction &)> trx_event_received;
boost::signals2::signal<void(const block_data &)> event_received;
protected:
std::string ip;
uint32_t block_zmq_port;
uint32_t trx_zmq_port;
uint32_t zmq_port;
std::atomic_bool stopped;
std::thread block_thr;
std::thread trx_thr;
std::thread thr;
};
class zmq_listener : public zmq_listener_base {
public:
zmq_listener(std::string _ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port = 0);
zmq_listener(std::string _ip, uint32_t _zmq);
virtual ~zmq_listener();
void start();
@ -181,20 +158,16 @@ private:
class zmq_listener_libbitcoin : public zmq_listener_base {
public:
zmq_listener_libbitcoin(std::string _ip, uint32_t _block_zmq_port = 9093, uint32_t _trx_zmq_port = 9094);
zmq_listener_libbitcoin(std::string _ip, uint32_t _zmq);
virtual ~zmq_listener_libbitcoin();
void start();
private:
void handle_block();
void handle_trx();
libbitcoin::protocol::zmq::context block_context;
libbitcoin::protocol::zmq::socket block_socket;
libbitcoin::protocol::zmq::poller block_poller;
libbitcoin::protocol::zmq::context trx_context;
libbitcoin::protocol::zmq::socket trx_socket;
libbitcoin::protocol::zmq::poller trx_poller;
libbitcoin::protocol::zmq::context context;
libbitcoin::protocol::zmq::socket socket;
libbitcoin::protocol::zmq::poller poller;
};
// =============================================================================
@ -212,29 +185,28 @@ public:
std::string process_sidechain_transaction(const sidechain_transaction_object &sto);
std::string send_sidechain_transaction(const sidechain_transaction_object &sto);
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
virtual optional<asset> estimate_withdrawal_transaction_fee() const override;
private:
std::vector<rpc_credentials> _rpc_credentials;
std::string bitcoin_node_ip;
std::string libbitcoin_server_ip;
uint32_t libbitcoin_block_zmq_port;
uint32_t libbitcoin_trx_zmq_port;
uint32_t libbitcoin_zmq_port;
uint32_t bitcoin_node_zmq_port;
std::string wallet_name;
uint32_t rpc_port;
std::string rpc_user;
std::string rpc_password;
std::string wallet;
std::string wallet_password;
std::unique_ptr<bitcoin_client_base> bitcoin_client;
std::unique_ptr<zmq_listener_base> listener;
fc::future<void> on_changed_objects_task;
bitcoin::bitcoin_address::network network_type;
uint32_t bitcoin_major_version;
std::mutex event_handler_mutex;
typedef std::lock_guard<decltype(event_handler_mutex)> scoped_lock;
std::string create_primary_wallet_address(const std::vector<son_sidechain_info> &son_pubkeys);
std::string create_primary_wallet_address(const std::vector<son_info> &son_pubkeys);
std::string create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address);
std::string create_deposit_transaction(const son_wallet_deposit_object &swdo);
@ -244,8 +216,7 @@ private:
std::string sign_transaction(const sidechain_transaction_object &sto);
std::string send_transaction(const sidechain_transaction_object &sto);
void block_handle_event(const block_data &event_data);
void trx_handle_event(const libbitcoin::chain::transaction &event_data);
void handle_event(const block_data &event_data);
std::string get_redeemscript_for_userdeposit(const std::string &user_address);
void on_changed_objects(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts);
void on_changed_objects_cb(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts);

View file

@ -1,83 +0,0 @@
#pragma once
#include <graphene/peerplays_sidechain/sidechain_net_handler.hpp>
#include <string>
#include <boost/bimap.hpp>
#include <boost/signals2.hpp>
#include <graphene/peerplays_sidechain/common/rpc_client.hpp>
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
namespace graphene { namespace peerplays_sidechain {
class ethereum_rpc_client : public rpc_client {
public:
ethereum_rpc_client(const std::vector<rpc_credentials> &credentials, bool debug_rpc_calls, bool simulate_connection_reselection);
std::string eth_blockNumber();
std::string eth_get_block_by_number(std::string block_number, bool full_block);
std::string eth_get_logs(std::string wallet_contract_address);
std::string eth_chainId();
std::string net_version();
std::string eth_get_transaction_count(const std::string &params);
std::string eth_gas_price();
std::string eth_estimateGas(const std::string &params);
std::string get_chain_id();
std::string get_network_id();
std::string get_nonce(const std::string &address);
std::string get_gas_price();
std::string get_gas_limit();
std::string get_estimate_gas(const std::string &params);
std::string eth_send_transaction(const std::string &params);
std::string eth_send_raw_transaction(const std::string &params);
std::string eth_get_transaction_receipt(const std::string &params);
std::string eth_get_transaction_by_hash(const std::string &params);
virtual uint64_t ping(rpc_connection &conn) const override;
};
class sidechain_net_handler_ethereum : public sidechain_net_handler {
public:
sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options);
virtual ~sidechain_net_handler_ethereum();
bool process_proposal(const proposal_object &po);
void process_primary_wallet();
void process_sidechain_addresses();
bool process_deposit(const son_wallet_deposit_object &swdo);
bool process_withdrawal(const son_wallet_withdraw_object &swwo);
std::string process_sidechain_transaction(const sidechain_transaction_object &sto);
std::string send_sidechain_transaction(const sidechain_transaction_object &sto);
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
virtual optional<asset> estimate_withdrawal_transaction_fee() const override;
private:
std::vector<rpc_credentials> _rpc_credentials;
std::string wallet_contract_address;
using bimap_type = boost::bimap<std::string, std::string>;
bimap_type erc20_addresses;
ethereum_rpc_client *rpc_client;
ethereum::chain_id_type chain_id;
ethereum::network_id_type network_id;
std::string create_primary_wallet_transaction(const std::vector<son_sidechain_info> &son_pubkeys, const std::string &object_id);
std::string create_deposit_transaction(const son_wallet_deposit_object &swdo);
std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo);
std::string sign_transaction(const sidechain_transaction_object &sto);
uint64_t last_block_received;
fc::future<void> _listener_task;
boost::signals2::signal<void(const std::string &)> event_received;
void schedule_ethereum_listener();
void ethereum_listener_loop();
void handle_event(const std::string &block_number);
};
}} // namespace graphene::peerplays_sidechain

View file

@ -6,14 +6,15 @@
#include <boost/signals2.hpp>
#include <fc/network/http/connection.hpp>
#include <graphene/peerplays_sidechain/common/rpc_client.hpp>
#include <graphene/peerplays_sidechain/hive/types.hpp>
namespace graphene { namespace peerplays_sidechain {
class hive_rpc_client : public rpc_client {
class hive_node_rpc_client : public rpc_client {
public:
hive_rpc_client(const std::vector<rpc_credentials> &credentials, bool debug_rpc_calls, bool simulate_connection_reselection);
hive_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls);
std::string account_history_api_get_transaction(std::string transaction_id);
std::string block_api_get_block(uint32_t block_number);
@ -30,8 +31,6 @@ public:
std::string get_head_block_time();
std::string get_is_test_net();
std::string get_last_irreversible_block_num();
virtual uint64_t ping(rpc_connection &conn) const override;
};
class sidechain_net_handler_hive : public sidechain_net_handler {
@ -47,14 +46,12 @@ public:
std::string process_sidechain_transaction(const sidechain_transaction_object &sto);
std::string send_sidechain_transaction(const sidechain_transaction_object &sto);
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
virtual optional<asset> estimate_withdrawal_transaction_fee() const override;
private:
std::vector<rpc_credentials> _rpc_credentials;
std::string wallet_account_name;
hive_rpc_client *rpc_client;
std::string node_rpc_url;
std::string node_rpc_user;
std::string node_rpc_password;
hive_node_rpc_client *node_rpc_client;
hive::chain_id_type chain_id;
hive::network network_type;

View file

@ -19,7 +19,6 @@ public:
std::string process_sidechain_transaction(const sidechain_transaction_object &sto);
std::string send_sidechain_transaction(const sidechain_transaction_object &sto);
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
virtual optional<asset> estimate_withdrawal_transaction_fee() const override;
private:
};

View file

@ -48,7 +48,6 @@ public:
void log_son_proposal_retry(sidechain_type sidechain, int op_type, object_id_type object_id);
bool can_son_participate(sidechain_type sidechain, int op_type, object_id_type object_id);
std::map<sidechain_type, std::vector<std::string>> get_son_listener_log();
optional<asset> estimate_withdrawal_transaction_fee(sidechain_type sidechain);
void schedule_heartbeat_loop();
void heartbeat_loop();
@ -88,9 +87,7 @@ private:
std::mutex access_db_mutex;
std::mutex access_approve_prop_mutex;
std::mutex access_son_down_prop_mutex;
std::mutex access_son_deregister_prop_mutex;
std::map<sidechain_type, bool> sidechain_enabled;
std::map<sidechain_type, std::unique_ptr<sidechain_net_handler>> net_handlers;
std::set<chain::son_id_type> sons;
std::map<chain::public_key_type, fc::ecc::private_key> private_keys;
@ -100,7 +97,6 @@ private:
uint16_t retries_threshold = 150;
bool first_block_skipped;
bool son_processing_enabled;
void on_applied_block(const signed_block &b);
};
@ -117,27 +113,19 @@ peerplays_sidechain_plugin_impl::peerplays_sidechain_plugin_impl(peerplays_sidec
sidechain_enabled_peerplays(false),
current_son_id([] {
std::map<sidechain_type, son_id_type> current_son_id;
for (const auto &active_sidechain_type : all_sidechain_types) {
for (const auto &active_sidechain_type : active_sidechain_types) {
current_son_id.emplace(active_sidechain_type, son_id_type(std::numeric_limits<uint32_t>().max()));
}
return current_son_id;
}()),
sidechain_enabled([] {
std::map<sidechain_type, bool> sidechain_enabled;
for (const auto &active_sidechain_type : all_sidechain_types) {
sidechain_enabled.emplace(active_sidechain_type, false);
}
return sidechain_enabled;
}()),
net_handlers([] {
std::map<sidechain_type, std::unique_ptr<sidechain_net_handler>> net_handlers;
for (const auto &active_sidechain_type : all_sidechain_types) {
for (const auto &active_sidechain_type : active_sidechain_types) {
net_handlers.emplace(active_sidechain_type, nullptr);
}
return net_handlers;
}()),
first_block_skipped(false),
son_processing_enabled(false) {
first_block_skipped(false) {
}
peerplays_sidechain_plugin_impl::~peerplays_sidechain_plugin_impl() {
@ -145,18 +133,18 @@ peerplays_sidechain_plugin_impl::~peerplays_sidechain_plugin_impl() {
if (_heartbeat_task.valid())
_heartbeat_task.cancel_and_wait(__FUNCTION__);
} catch (fc::canceled_exception &) {
// Expected exception. Move along.
//Expected exception. Move along.
} catch (fc::exception &e) {
edump((e.to_detail_string()));
}
try {
for (const auto &active_sidechain_type : all_sidechain_types) {
for (const auto &active_sidechain_type : active_sidechain_types) {
if (_son_processing_task.count(active_sidechain_type) != 0 && _son_processing_task.at(active_sidechain_type).valid())
_son_processing_task.at(active_sidechain_type).wait();
}
} catch (fc::canceled_exception &) {
// Expected exception. Move along.
//Expected exception. Move along.
} catch (fc::exception &e) {
edump((e.to_detail_string()));
}
@ -177,38 +165,26 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
cli.add_options()("sidechain-retry-threshold", bpo::value<uint16_t>()->default_value(150), "Sidechain retry throttling threshold");
cli.add_options()("debug-rpc-calls", bpo::value<bool>()->default_value(false), "Outputs RPC calls to console");
cli.add_options()("simulate-rpc-connection-reselection", bpo::value<bool>()->default_value(false), "Simulate RPC connection reselection by altering their response times by a random value");
cli.add_options()("use-bitcoind-client", bpo::value<bool>()->default_value(false), "Use bitcoind client instead of libbitcoin client");
cli.add_options()("bitcoin-sidechain-enabled", bpo::value<bool>()->default_value(false), "Bitcoin sidechain handler enabled");
cli.add_options()("bitcoin-node-ip", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR("127.0.0.1"), "IP address of Bitcoin node");
cli.add_options()("use-bitcoind-client", bpo::value<bool>()->default_value(false), "Use bitcoind client instead of libbitcoin client");
cli.add_options()("libbitcoin-server-ip", bpo::value<string>()->default_value("127.0.0.1"), "Libbitcoin server IP address");
cli.add_options()("libbitcoin-server-block-zmq-port", bpo::value<uint32_t>()->default_value(9093), "Block ZMQ port of libbitcoin server");
cli.add_options()("libbitcoin-server-trx-zmq-port", bpo::value<uint32_t>()->default_value(9094), "Trx ZMQ port of libbitcoin server");
cli.add_options()("bitcoin-node-ip", bpo::value<string>()->default_value("127.0.0.1"), "IP address of Bitcoin node");
cli.add_options()("bitcoin-node-zmq-port", bpo::value<uint32_t>()->default_value(11111), "ZMQ port of Bitcoin node");
cli.add_options()("bitcoin-node-rpc-port", bpo::value<uint32_t>()->default_value(8332), "RPC port of Bitcoin node");
cli.add_options()("bitcoin-node-rpc-user", bpo::value<string>()->default_value("1"), "Bitcoin RPC user");
cli.add_options()("bitcoin-node-rpc-password", bpo::value<string>()->default_value("1"), "Bitcoin RPC password");
cli.add_options()("bitcoin-wallet-name", bpo::value<string>(), "Bitcoin wallet name");
cli.add_options()("libbitcoin-server-ip", bpo::value<string>()->default_value("127.0.0.1"), "Libbitcoin server IP address");
cli.add_options()("libbitcoin-server-zmq-port", bpo::value<uint32_t>()->default_value(9093), "ZMQ port of libbitcoin server");
cli.add_options()("bitcoin-wallet", bpo::value<string>(), "Bitcoin wallet");
cli.add_options()("bitcoin-wallet-password", bpo::value<string>(), "Bitcoin wallet password");
cli.add_options()("bitcoin-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")),
"Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)");
cli.add_options()("ethereum-sidechain-enabled", bpo::value<bool>()->default_value(false), "Ethereum sidechain handler enabled");
cli.add_options()("ethereum-node-rpc-url", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR("127.0.0.1:8545"), "Ethereum node RPC URL [http[s]://]host[:port]");
cli.add_options()("ethereum-node-rpc-user", bpo::value<string>(), "Ethereum RPC user");
cli.add_options()("ethereum-node-rpc-password", bpo::value<string>(), "Ethereum RPC password");
cli.add_options()("ethereum-wallet-contract-address", bpo::value<string>(), "Ethereum wallet contract address");
cli.add_options()("ethereum-erc-20-address", bpo::value<vector<string>>()->composing()->multitoken(),
"Tuple of [ERC-20 symbol, ERC-20 address] (may specify multiple times)");
cli.add_options()("ethereum-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", "9bedac2bd8fe2a6f6528e066c67fc8ac0622e96828d40c0e820d83c5bd2b0589")),
"Tuple of [Ethereum public key, Ethereum private key] (may specify multiple times)");
cli.add_options()("hive-sidechain-enabled", bpo::value<bool>()->default_value(false), "Hive sidechain handler enabled");
cli.add_options()("hive-node-rpc-url", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]");
cli.add_options()("hive-node-rpc-url", bpo::value<string>()->default_value("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]");
cli.add_options()("hive-node-rpc-user", bpo::value<string>(), "Hive node RPC user");
cli.add_options()("hive-node-rpc-password", bpo::value<string>(), "Hive node RPC password");
cli.add_options()("hive-wallet-account-name", bpo::value<string>(), "Hive wallet account name");
cli.add_options()("hive-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", "5JNHfZYKGaomSFvd4NUdQ9qMcEAC43kujbfjueTHpVapX1Kzq2n")),
"Tuple of [Hive public key, Hive private key] (may specify multiple times)");
@ -256,47 +232,49 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt
}
sidechain_enabled_bitcoin = options.at("bitcoin-sidechain-enabled").as<bool>();
config_ready_bitcoin = (((options.count("libbitcoin-server-ip") && options.count("libbitcoin-server-zmq-port")) ||
(options.count("bitcoin-node-ip") && options.count("bitcoin-node-zmq-port") &&
options.count("bitcoin-node-rpc-port") && options.count("bitcoin-node-rpc-user") &&
options.count("bitcoin-node-rpc-password") && options.count("bitcoin-wallet-name") &&
options.count("bitcoin-wallet-password"))) &&
options.count("bitcoin-node-rpc-password"))) &&
/*options.count("bitcoin-wallet") && options.count("bitcoin-wallet-password") &&*/
options.count("bitcoin-private-key"));
if (!config_ready_bitcoin) {
wlog("Haven't set up Bitcoin sidechain parameters");
}
sidechain_enabled_ethereum = options.at("ethereum-sidechain-enabled").as<bool>();
config_ready_ethereum = options.count("ethereum-node-rpc-url") &&
/*options.count("ethereum-node-rpc-user") && options.count("ethereum-node-rpc-password") &&*/
options.count("ethereum-wallet-contract-address") &&
options.count("ethereum-private-key");
if (sidechain_enabled_ethereum && !config_ready_ethereum) {
wlog("Haven't set up Ethereum sidechain parameters");
}
//sidechain_enabled_ethereum = options.at("ethereum-sidechain-enabled").as<bool>();
//config_ready_ethereum = options.count("ethereum-node-ip") &&
// options.count("ethereum-address") &&
// options.count("ethereum-public-key") && options.count("ethereum-private-key");
//if (!config_ready_ethereum) {
// wlog("Haven't set up Ethereum sidechain parameters");
//}
sidechain_enabled_hive = options.at("hive-sidechain-enabled").as<bool>();
config_ready_hive = options.count("hive-node-rpc-url") &&
/*options.count("hive-node-rpc-user") && options.count("hive-node-rpc-password") &&*/
options.count("hive-wallet-account-name") &&
options.count("hive-private-key");
if (sidechain_enabled_hive && !config_ready_hive) {
if (!config_ready_hive) {
wlog("Haven't set up Hive sidechain parameters");
}
#ifdef ENABLE_PEERPLAYS_ASSET_DEPOSITS
sidechain_enabled_peerplays = true;
sidechain_enabled_peerplays = true; //options.at("peerplays-sidechain-enabled").as<bool>();
#else
sidechain_enabled_peerplays = false;
#endif
config_ready_peerplays = true;
if (sidechain_enabled_peerplays && !config_ready_peerplays) {
if (!config_ready_peerplays) {
wlog("Haven't set up Peerplays sidechain parameters");
}
if (options.at("simulate-rpc-connection-reselection").as<bool>())
ilog("### RPC connection reselection will be simulated");
if (!(config_ready_bitcoin &&
/*config_ready_ethereum &&*/
config_ready_hive &&
config_ready_peerplays)) {
wlog("Haven't set up any sidechain parameters");
throw;
}
}
void peerplays_sidechain_plugin_impl::plugin_startup() {
@ -312,25 +290,21 @@ void peerplays_sidechain_plugin_impl::plugin_startup() {
sidechain_net_handler_factory net_handler_factory(plugin);
if (sidechain_enabled_bitcoin && config_ready_bitcoin) {
sidechain_enabled.at(sidechain_type::bitcoin) = true;
net_handlers.at(sidechain_type::bitcoin) = net_handler_factory.create_handler(sidechain_type::bitcoin, options);
ilog("Bitcoin sidechain handler running");
}
if (sidechain_enabled_ethereum && config_ready_ethereum) {
sidechain_enabled.at(sidechain_type::ethereum) = true;
net_handlers.at(sidechain_type::ethereum) = net_handler_factory.create_handler(sidechain_type::ethereum, options);
ilog("Ethereum sidechain handler running");
}
//if (sidechain_enabled_ethereum && config_ready_ethereum) {
// net_manager->create_handler(sidechain_type::ethereum, options);
// ilog("Ethereum sidechain handler running");
//}
if (sidechain_enabled_hive && config_ready_hive) {
sidechain_enabled.at(sidechain_type::hive) = true;
net_handlers.at(sidechain_type::hive) = net_handler_factory.create_handler(sidechain_type::hive, options);
ilog("Hive sidechain handler running");
}
if (sidechain_enabled_peerplays && config_ready_peerplays) {
sidechain_enabled.at(sidechain_type::peerplays) = true;
net_handlers.at(sidechain_type::peerplays) = net_handler_factory.create_handler(sidechain_type::peerplays, options);
ilog("Peerplays sidechain handler running");
}
@ -374,7 +348,7 @@ bool peerplays_sidechain_plugin_impl::is_active_son(sidechain_type sidechain, so
set<son_id_type> active_son_ids;
std::transform(gpo.active_sons.at(sidechain).cbegin(), gpo.active_sons.at(sidechain).cend(),
std::inserter(active_son_ids, active_son_ids.end()),
[](const son_sidechain_info &swi) {
[](const son_info &swi) {
return swi.son_id;
});
@ -412,14 +386,14 @@ bool peerplays_sidechain_plugin_impl::is_son_down_op_valid(const chain::operatio
const chain::global_property_object &gpo = d.get_global_properties();
const chain::dynamic_global_property_object &dgpo = d.get_dynamic_global_properties();
const auto &idx = d.get_index_type<chain::son_index>().indices().get<by_id>();
const son_report_down_operation down_op = op.get<son_report_down_operation>();
const auto son_obj = idx.find(down_op.son_id);
son_report_down_operation down_op = op.get<son_report_down_operation>();
auto son_obj = idx.find(down_op.son_id);
if (son_obj == idx.end()) {
return false;
}
const auto stats = son_obj->statistics(d);
const fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval;
const int64_t down_threshold = gpo.parameters.son_down_time();
auto stats = son_obj->statistics(d);
fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval;
int64_t down_threshold = gpo.parameters.son_down_time();
bool status_son_down_op_valid = true;
for (const auto &status : son_obj->statuses) {
@ -427,12 +401,10 @@ bool peerplays_sidechain_plugin_impl::is_son_down_op_valid(const chain::operatio
status_son_down_op_valid = false;
}
if (status_son_down_op_valid) {
for (const auto &active_sidechain_type : active_sidechain_types(d.head_block_time())) {
if (stats.last_active_timestamp.contains(active_sidechain_type)) {
const fc::time_point_sec last_active_ts = ((stats.last_active_timestamp.at(active_sidechain_type) > last_maintenance_time) ? stats.last_active_timestamp.at(active_sidechain_type) : last_maintenance_time);
if (((fc::time_point::now() - last_active_ts) <= fc::seconds(down_threshold))) {
status_son_down_op_valid = false;
}
for (const auto &active_sidechain_type : active_sidechain_types) {
fc::time_point_sec last_active_ts = ((stats.last_active_timestamp.at(active_sidechain_type) > last_maintenance_time) ? stats.last_active_timestamp.at(active_sidechain_type) : last_maintenance_time);
if (((fc::time_point::now() - last_active_ts) <= fc::seconds(down_threshold))) {
status_son_down_op_valid = false;
}
}
}
@ -480,11 +452,9 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop() {
//! Check that son is active (at least for one sidechain_type)
bool is_son_active = false;
for (const auto &active_sidechain_type : active_sidechain_types(d.head_block_time())) {
if (sidechain_enabled.at(active_sidechain_type)) {
if (is_active_son(active_sidechain_type, son_id))
is_son_active = true;
}
for (const auto &active_sidechain_type : active_sidechain_types) {
if (is_active_son(active_sidechain_type, son_id))
is_son_active = true;
}
if (is_son_active || status_in_maintenance) {
@ -518,17 +488,10 @@ void peerplays_sidechain_plugin_impl::schedule_son_processing() {
const auto next_wakeup = now + std::chrono::microseconds(time_to_next_son_processing);
for (const auto &active_sidechain_type : active_sidechain_types(plugin.database().head_block_time())) {
if (_son_processing_task.count(active_sidechain_type) != 0 && _son_processing_task.at(active_sidechain_type).wait_for(std::chrono::seconds{0}) != std::future_status::ready) {
wlog("Son doesn't process in time for sidechain: ${active_sidechain_type}", ("active_sidechain_type", active_sidechain_type));
_son_processing_task.at(active_sidechain_type).wait();
}
for (const auto &active_sidechain_type : active_sidechain_types) {
_son_processing_task[active_sidechain_type] = std::async(std::launch::async, [this, next_wakeup, active_sidechain_type] {
if (sidechain_enabled.at(active_sidechain_type)) {
std::this_thread::sleep_until(next_wakeup);
son_processing(active_sidechain_type);
}
std::this_thread::sleep_until(next_wakeup);
son_processing(active_sidechain_type);
});
}
}
@ -540,11 +503,11 @@ void peerplays_sidechain_plugin_impl::son_processing(sidechain_type sidechain) {
return;
}
// fc::time_point now_fine = fc::time_point::now();
// fc::time_point_sec now = now_fine + fc::microseconds(500000);
// if (plugin.database().get_slot_time(1) < now) {
// return; // Not synced
// }
//fc::time_point now_fine = fc::time_point::now();
//fc::time_point_sec now = now_fine + fc::microseconds(500000);
//if (plugin.database().get_slot_time(1) < now) {
// return; // Not synced
//}
const fc::time_point now_fine = fc::time_point::now();
const fc::time_point_sec now = now_fine - fc::milliseconds(3000);
@ -635,35 +598,19 @@ bool peerplays_sidechain_plugin_impl::can_son_participate(sidechain_type sidecha
std::map<sidechain_type, std::vector<std::string>> peerplays_sidechain_plugin_impl::get_son_listener_log() {
std::map<sidechain_type, std::vector<std::string>> result;
for (const auto &active_sidechain_type : active_sidechain_types(plugin.database().head_block_time())) {
if (net_handlers.at(active_sidechain_type)) {
result.emplace(active_sidechain_type, net_handlers.at(active_sidechain_type)->get_son_listener_log());
}
for (const auto &active_sidechain_type : active_sidechain_types) {
result.emplace(active_sidechain_type, net_handlers.at(active_sidechain_type)->get_son_listener_log());
}
return result;
}
optional<asset> peerplays_sidechain_plugin_impl::estimate_withdrawal_transaction_fee(sidechain_type sidechain) {
if (net_handlers.count(sidechain) == 0) {
wlog("No net handler for sidechain: ${sidechain}", ("sidechain", sidechain));
return optional<asset>();
}
if (!net_handlers.at(sidechain)) {
wlog("Net handler is null for sidechain: ${sidechain}", ("sidechain", sidechain));
return optional<asset>();
}
return net_handlers.at(sidechain)->estimate_withdrawal_transaction_fee();
}
void peerplays_sidechain_plugin_impl::approve_proposals(sidechain_type sidechain) {
// prevent approving duplicate proposals with lock for parallel execution.
// We can have the same propsals, but in the case of parallel execution we can run
// into problem of approving the same propsal since it might happens that previous
// approved proposal didn't have time or chance to populate the list of available
// active proposals which is consulted here in the code.
const std::lock_guard<std::mutex> lck{access_approve_prop_mutex};
std::lock_guard<std::mutex> lck(access_approve_prop_mutex);
auto check_approve_proposal = [&](const chain::son_id_type &son_id, const chain::proposal_object &proposal) {
if (!is_valid_son_proposal(proposal)) {
return;
@ -713,7 +660,7 @@ void peerplays_sidechain_plugin_impl::approve_proposals(sidechain_type sidechain
}
void peerplays_sidechain_plugin_impl::create_son_down_proposals(sidechain_type sidechain) {
const std::lock_guard<std::mutex> lck{access_son_down_prop_mutex};
std::lock_guard<std::mutex> lck(access_son_down_prop_mutex);
auto create_son_down_proposal = [&](chain::son_id_type son_id, fc::time_point_sec last_active_ts) {
chain::database &d = plugin.database();
const chain::global_property_object &gpo = d.get_global_properties();
@ -726,7 +673,7 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals(sidechain_type s
proposal_create_operation proposal_op;
proposal_op.fee_paying_account = get_current_son_object(sidechain).son_account;
proposal_op.proposed_ops.emplace_back(op_wrapper(son_down_op));
const uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
proposal_op.expiration_time = time_point_sec(d.head_block_time().sec_since_epoch() + lifetime);
return proposal_op;
};
@ -735,27 +682,19 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals(sidechain_type s
const chain::global_property_object &gpo = d.get_global_properties();
const chain::dynamic_global_property_object &dgpo = d.get_dynamic_global_properties();
const auto &idx = d.get_index_type<chain::son_index>().indices().get<by_id>();
const std::set<son_id_type> sons_being_reported_down = d.get_sons_being_reported_down();
const chain::son_id_type my_son_id = get_current_son_id(sidechain);
std::set<son_id_type> sons_being_reported_down = d.get_sons_being_reported_down();
chain::son_id_type my_son_id = get_current_son_id(sidechain);
//! Fixme - check this part of the code
for (auto son_inf : gpo.active_sons.at(sidechain)) {
if (my_son_id == son_inf.son_id || (sons_being_reported_down.find(son_inf.son_id) != sons_being_reported_down.end())) {
continue;
}
const auto son_obj = idx.find(son_inf.son_id);
const auto stats = son_obj->statistics(d);
const fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval;
const fc::time_point_sec last_active_ts = [&stats, &sidechain, &last_maintenance_time] {
fc::time_point_sec last_active_ts;
if (stats.last_active_timestamp.contains(sidechain)) {
last_active_ts = (stats.last_active_timestamp.at(sidechain) > last_maintenance_time) ? stats.last_active_timestamp.at(sidechain) : last_maintenance_time;
} else
last_active_ts = last_maintenance_time;
return last_active_ts;
}();
const int64_t down_threshold = gpo.parameters.son_down_time();
auto son_obj = idx.find(son_inf.son_id);
auto stats = son_obj->statistics(d);
fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval;
fc::time_point_sec last_active_ts = ((stats.last_active_timestamp.at(sidechain) > last_maintenance_time) ? stats.last_active_timestamp.at(sidechain) : last_maintenance_time);
int64_t down_threshold = gpo.parameters.son_down_time();
bool status_son_down_valid = true;
for (const auto &status : son_obj->statuses) {
@ -785,7 +724,6 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals(sidechain_type s
}
void peerplays_sidechain_plugin_impl::create_son_deregister_proposals(sidechain_type sidechain) {
const std::lock_guard<std::mutex> lck{access_son_deregister_prop_mutex};
chain::database &d = plugin.database();
std::set<son_id_type> sons_to_be_dereg = d.get_sons_to_be_deregistered();
chain::son_id_type my_son_id = get_current_son_id(sidechain);
@ -824,65 +762,40 @@ void peerplays_sidechain_plugin_impl::create_son_deregister_proposals(sidechain_
}
void peerplays_sidechain_plugin_impl::process_proposals(sidechain_type sidechain) {
if (net_handlers.at(sidechain)) {
net_handlers.at(sidechain)->process_proposals();
}
net_handlers.at(sidechain)->process_proposals();
}
void peerplays_sidechain_plugin_impl::process_active_sons_change(sidechain_type sidechain) {
if (net_handlers.at(sidechain)) {
net_handlers.at(sidechain)->process_active_sons_change();
}
net_handlers.at(sidechain)->process_active_sons_change();
}
void peerplays_sidechain_plugin_impl::create_deposit_addresses(sidechain_type sidechain) {
if (net_handlers.at(sidechain)) {
net_handlers.at(sidechain)->create_deposit_addresses();
}
net_handlers.at(sidechain)->create_deposit_addresses();
}
void peerplays_sidechain_plugin_impl::process_deposits(sidechain_type sidechain) {
if (net_handlers.at(sidechain)) {
net_handlers.at(sidechain)->process_deposits();
}
net_handlers.at(sidechain)->process_deposits();
}
void peerplays_sidechain_plugin_impl::process_withdrawals(sidechain_type sidechain) {
if (net_handlers.at(sidechain)) {
net_handlers.at(sidechain)->process_withdrawals();
}
net_handlers.at(sidechain)->process_withdrawals();
}
void peerplays_sidechain_plugin_impl::process_sidechain_transactions(sidechain_type sidechain) {
if (net_handlers.at(sidechain)) {
net_handlers.at(sidechain)->process_sidechain_transactions();
}
net_handlers.at(sidechain)->process_sidechain_transactions();
}
void peerplays_sidechain_plugin_impl::send_sidechain_transactions(sidechain_type sidechain) {
if (net_handlers.at(sidechain)) {
net_handlers.at(sidechain)->send_sidechain_transactions();
}
net_handlers.at(sidechain)->send_sidechain_transactions();
}
void peerplays_sidechain_plugin_impl::settle_sidechain_transactions(sidechain_type sidechain) {
if (net_handlers.at(sidechain)) {
net_handlers.at(sidechain)->settle_sidechain_transactions();
}
net_handlers.at(sidechain)->settle_sidechain_transactions();
}
void peerplays_sidechain_plugin_impl::on_applied_block(const signed_block &b) {
if (first_block_skipped) {
if (son_processing_enabled) {
schedule_son_processing();
} else {
const fc::time_point now_fine = fc::time_point::now();
const fc::time_point_sec now = now_fine + fc::microseconds(500000);
if (plugin.database().get_slot_time(1) >= now) {
son_processing_enabled = true;
schedule_son_processing();
}
}
schedule_son_processing();
} else {
first_block_skipped = true;
}
@ -970,8 +883,4 @@ std::map<sidechain_type, std::vector<std::string>> peerplays_sidechain_plugin::g
return my->get_son_listener_log();
}
optional<asset> peerplays_sidechain_plugin::estimate_withdrawal_transaction_fee(sidechain_type sidechain) {
return my->estimate_withdrawal_transaction_fee(sidechain);
}
}} // namespace graphene::peerplays_sidechain

View file

@ -12,7 +12,6 @@ public:
std::shared_ptr<graphene::peerplays_sidechain::peerplays_sidechain_plugin> get_plugin();
std::map<sidechain_type, std::vector<std::string>> get_son_listener_log();
optional<asset> estimate_withdrawal_transaction_fee(sidechain_type sidechain);
private:
app::application &app;
@ -33,10 +32,6 @@ std::map<sidechain_type, std::vector<std::string>> sidechain_api_impl::get_son_l
return get_plugin()->get_son_listener_log();
}
optional<asset> sidechain_api_impl::estimate_withdrawal_transaction_fee(sidechain_type sidechain) {
return get_plugin()->estimate_withdrawal_transaction_fee(sidechain);
}
} // namespace detail
sidechain_api::sidechain_api(graphene::app::application &_app) :
@ -50,8 +45,4 @@ std::map<sidechain_type, std::vector<std::string>> sidechain_api::get_son_listen
return my->get_son_listener_log();
}
optional<asset> sidechain_api::estimate_withdrawal_transaction_fee(sidechain_type sidechain) {
return my->estimate_withdrawal_transaction_fee(sidechain);
}
}} // namespace graphene::peerplays_sidechain

View file

@ -9,8 +9,7 @@
namespace graphene { namespace peerplays_sidechain {
sidechain_net_handler::sidechain_net_handler(sidechain_type _sidechain, peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
sidechain(_sidechain),
sidechain_net_handler::sidechain_net_handler(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
plugin(_plugin),
database(_plugin.database()) {
@ -22,11 +21,11 @@ sidechain_net_handler::sidechain_net_handler(sidechain_type _sidechain, peerplay
sidechain_net_handler::~sidechain_net_handler() {
}
sidechain_type sidechain_net_handler::get_sidechain() const {
sidechain_type sidechain_net_handler::get_sidechain() {
return sidechain;
}
std::vector<std::string> sidechain_net_handler::get_sidechain_deposit_addresses() const {
std::vector<std::string> sidechain_net_handler::get_sidechain_deposit_addresses() {
std::vector<std::string> result;
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>();
@ -39,7 +38,7 @@ std::vector<std::string> sidechain_net_handler::get_sidechain_deposit_addresses(
return result;
}
std::vector<std::string> sidechain_net_handler::get_sidechain_withdraw_addresses() const {
std::vector<std::string> sidechain_net_handler::get_sidechain_withdraw_addresses() {
std::vector<std::string> result;
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>();
@ -52,20 +51,7 @@ std::vector<std::string> sidechain_net_handler::get_sidechain_withdraw_addresses
return result;
}
std::vector<sidechain_transaction_object> sidechain_net_handler::get_sidechain_transaction_objects(sidechain_transaction_status status) const {
std::vector<sidechain_transaction_object> result;
const auto &idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_sidechain_and_status>();
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, status));
std::for_each(idx_range.first, idx_range.second,
[&result](const sidechain_transaction_object &sto) {
result.push_back(sto);
});
return result;
}
std::string sidechain_net_handler::get_private_key(std::string public_key) const {
std::string sidechain_net_handler::get_private_key(std::string public_key) {
auto private_key_itr = private_keys.find(public_key);
if (private_key_itr != private_keys.end()) {
return private_key_itr->second;
@ -184,32 +170,26 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
bool enable_peerplays_asset_deposits = false;
#ifdef ENABLE_PEERPLAYS_ASSET_DEPOSITS
// enable_peerplays_asset_deposits = (sed.sidechain == sidechain_type::peerplays) &&
// (sed.sidechain_currency.compare("BTC") != 0) &&
// (sed.sidechain_currency.compare("ETH") != 0) &&
// (sed.sidechain_currency.compare("HBD") != 0) &&
// (sed.sidechain_currency.compare("HIVE") != 0);
//enable_peerplays_asset_deposits = (sed.sidechain == sidechain_type::peerplays) &&
// (sed.sidechain_currency.compare("BTC") != 0) &&
// (sed.sidechain_currency.compare("HBD") != 0) &&
// (sed.sidechain_currency.compare("HIVE") != 0);
#endif
const bool deposit_condition = (sed.peerplays_to == gpo.parameters.son_account()) &&
(sed.sidechain == sidechain) &&
(sed.type == sidechain_event_type::deposit) &&
(((sed.sidechain == sidechain_type::bitcoin) && (sed.sidechain_currency.compare("BTC") == 0)) ||
((sed.sidechain == sidechain_type::ethereum) && (!sed.sidechain_currency.empty())) ||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HBD") == 0)) ||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HIVE") == 0)) ||
enable_peerplays_asset_deposits);
bool deposit_condition = (sed.peerplays_to == gpo.parameters.son_account()) &&
(((sed.sidechain == sidechain_type::bitcoin) && (sed.sidechain_currency.compare("BTC") == 0)) ||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HBD") == 0)) ||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HIVE") == 0)) ||
enable_peerplays_asset_deposits);
const bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) &&
(sed.sidechain == sidechain) &&
(sed.type == sidechain_event_type::withdrawal) &&
(((sed.sidechain == sidechain_type::bitcoin) && (sed.sidechain_currency == object_id_to_string(gpo.parameters.btc_asset()))) ||
((sed.sidechain == sidechain_type::ethereum) && (!sed.sidechain_currency.empty())) ||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset()))) ||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency == object_id_to_string(gpo.parameters.hive_asset()))));
bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain == sidechain) && //! Fixme -> sidechain_type::peerplays
((sed.sidechain_currency == object_id_to_string(gpo.parameters.btc_asset())) ||
(sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset())) ||
(sed.sidechain_currency == object_id_to_string(gpo.parameters.hive_asset())));
// Deposit request
if (deposit_condition) {
for (son_id_type son_id : plugin.get_sons()) {
if (plugin.is_active_son(sidechain, son_id)) {
@ -260,10 +240,6 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
withdraw_currency = "BTC";
withdraw_currency_price = database.get<asset_object>(database.get_global_properties().parameters.btc_asset()).options.core_exchange_rate;
}
if (sed.sidechain_currency == object_id_to_string(gpo.parameters.eth_asset())) {
withdraw_currency = "ETH";
withdraw_currency_price = database.get<asset_object>(database.get_global_properties().parameters.eth_asset()).options.core_exchange_rate;
}
if (sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset())) {
withdraw_currency = "HBD";
withdraw_currency_price = database.get<asset_object>(database.get_global_properties().parameters.hbd_asset()).options.core_exchange_rate;
@ -273,17 +249,7 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
withdraw_currency_price = database.get<asset_object>(database.get_global_properties().parameters.hive_asset()).options.core_exchange_rate;
}
if (withdraw_currency.empty()) {
//! This is ERC-20 withdrawal
const auto asset_object_id = string_to_object_id(sed.sidechain_currency);
const auto &assets_by_id = database.get_index_type<asset_index>().indices().get<by_id>();
const auto asset_itr = assets_by_id.find(asset_object_id);
if (asset_itr == assets_by_id.end()) {
wlog("Could not find asset: ${asset_object_id}", ("asset_object_id", asset_object_id));
return;
}
withdraw_currency = asset_itr->symbol;
withdraw_currency_price = asset_itr->options.core_exchange_rate;
return;
}
for (son_id_type son_id : plugin.get_sons()) {
@ -451,7 +417,7 @@ void sidechain_net_handler::process_deposits() {
if (swdo.id == object_id_type(0, 0, 0) || !plugin.can_son_participate(sidechain, chain::operation::tag<chain::son_wallet_deposit_process_operation>::value, swdo.id)) {
return;
}
// Ignore the deposits which are not valid anymore, considered refunds.
//Ignore the deposits which are not valid anymore, considered refunds.
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();
const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, swdo.sidechain_from, time_point_sec::maximum()));
if (addr_itr == sidechain_addresses_idx.end()) {
@ -500,9 +466,10 @@ void sidechain_net_handler::process_withdrawals() {
}
void sidechain_net_handler::process_sidechain_transactions() {
const auto stos = get_sidechain_transaction_objects(sidechain_transaction_status::valid);
const auto &idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_sidechain_and_status>();
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, sidechain_transaction_status::valid));
std::for_each(stos.cbegin(), stos.cend(), [&](const sidechain_transaction_object &sto) {
std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) {
if ((sto.id == object_id_type(0, 0, 0)) || !signer_expected(sto, plugin.get_current_son_id(sidechain))) {
return;
}
@ -546,9 +513,10 @@ void sidechain_net_handler::process_sidechain_transactions() {
}
void sidechain_net_handler::send_sidechain_transactions() {
const auto stos = get_sidechain_transaction_objects(sidechain_transaction_status::complete);
const auto &idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_sidechain_and_status>();
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, sidechain_transaction_status::complete));
std::for_each(stos.cbegin(), stos.cend(), [&](const sidechain_transaction_object &sto) {
std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) {
if (sto.id == object_id_type(0, 0, 0)) {
return;
}
@ -580,9 +548,10 @@ void sidechain_net_handler::send_sidechain_transactions() {
}
void sidechain_net_handler::settle_sidechain_transactions() {
const auto stos = get_sidechain_transaction_objects(sidechain_transaction_status::sent);
const auto &idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_sidechain_and_status>();
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, sidechain_transaction_status::sent));
std::for_each(stos.cbegin(), stos.cend(), [&](const sidechain_transaction_object &sto) {
std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) {
if (sto.id == object_id_type(0, 0, 0)) {
return;
}
@ -677,10 +646,8 @@ void sidechain_net_handler::on_applied_block(const signed_block &b) {
continue;
}
const bool is_tracked_asset =
bool is_tracked_asset =
((sidechain == sidechain_type::bitcoin) && (transfer_op.amount.asset_id == gpo.parameters.btc_asset())) ||
((sidechain == sidechain_type::ethereum) && (transfer_op.amount.asset_id == gpo.parameters.eth_asset())) ||
((sidechain == sidechain_type::ethereum) && (transfer_op.amount.asset_id != gpo.parameters.btc_asset()) && (transfer_op.amount.asset_id != gpo.parameters.hbd_asset()) && (transfer_op.amount.asset_id != gpo.parameters.hive_asset()) && (transfer_op.amount.asset_id != asset_id_type())) ||
((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hbd_asset())) ||
((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hive_asset()));
@ -706,8 +673,7 @@ void sidechain_net_handler::on_applied_block(const signed_block &b) {
sidechain_event_data sed;
sed.timestamp = database.head_block_time();
sed.block_num = database.head_block_num();
sed.sidechain = sidechain;
sed.type = sidechain_event_type::withdrawal;
sed.sidechain = sidechain; //! Fixme -> sidechain_type::peerplays
sed.sidechain_uid = sidechain_uid;
sed.sidechain_transaction_id = trx.id().str();
sed.sidechain_from = sidechain_from;

View file

@ -13,7 +13,7 @@
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/protocol/son_wallet.hpp>
#include <graphene/chain/sidechain_transaction_object.hpp>
#include <graphene/chain/son_sidechain_info.hpp>
#include <graphene/chain/son_info.hpp>
#include <graphene/chain/son_wallet_object.hpp>
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp>
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_transaction.hpp>
@ -25,13 +25,13 @@ namespace graphene { namespace peerplays_sidechain {
// =============================================================================
bitcoin_rpc_client::bitcoin_rpc_client(const std::vector<rpc_credentials> &_credentials, bool _debug_rpc_calls, bool _simulate_connection_reselection) :
rpc_client(sidechain_type::bitcoin, _credentials, _debug_rpc_calls, _simulate_connection_reselection) {
bitcoin_rpc_client::bitcoin_rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls) :
rpc_client(_url, _user, _password, _debug_rpc_calls) {
}
uint64_t bitcoin_rpc_client::estimatesmartfee(uint16_t conf_target) {
const std::string params = std::string("[") + std::to_string(conf_target) + std::string("]");
const std::string str = send_post_request("estimatesmartfee", params, debug_rpc_calls);
std::string params = std::string("[") + std::to_string(conf_target) + std::string("]");
std::string str = send_post_request("estimatesmartfee", params, debug_rpc_calls);
if (str.length() == 0) {
wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__));
@ -157,8 +157,8 @@ btc_tx bitcoin_rpc_client::getrawtransaction(const std::string &txid, const bool
}
std::string bitcoin_rpc_client::getblockchaininfo() {
static const std::string params = std::string("[]");
const std::string str = send_post_request("getblockchaininfo", params, debug_rpc_calls);
std::string params = std::string("[]");
std::string str = send_post_request("getblockchaininfo", params, debug_rpc_calls);
std::string result;
@ -215,8 +215,8 @@ void bitcoin_rpc_client::importmulti(const std::vector<multi_params> &address_or
std::vector<btc_txout> bitcoin_rpc_client::listunspent(const uint32_t minconf, const uint32_t maxconf) {
std::vector<btc_txout> result;
const std::string params = std::string("[") + std::to_string(minconf) + "," + std::to_string(maxconf) + std::string("]");
const std::string str = send_post_request("listunspent", params, debug_rpc_calls);
std::string params = std::string("[") + std::to_string(minconf) + "," + std::to_string(maxconf) + std::string("]");
std::string str = send_post_request("listunspent", params, debug_rpc_calls);
if (str.length() == 0) {
wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__));
@ -252,7 +252,7 @@ std::vector<btc_txout> bitcoin_rpc_client::listunspent_by_address_and_amount(con
params += std::string("} ]");
std::vector<btc_txout> result;
const std::string str = send_post_request("listunspent", params, debug_rpc_calls);
std::string str = send_post_request("listunspent", params, debug_rpc_calls);
if (str.length() == 0) {
wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__));
@ -279,13 +279,16 @@ std::vector<btc_txout> bitcoin_rpc_client::listunspent_by_address_and_amount(con
}
std::string bitcoin_rpc_client::loadwallet(const std::string &filename) {
const std::string params = std::string("[\"") + filename + std::string("\"]");
return send_post_request("loadwallet", params, debug_rpc_calls);
std::string params = std::string("[\"") + filename + std::string("\"]");
std::string str = send_post_request("loadwallet", params, debug_rpc_calls);
return str;
}
std::string bitcoin_rpc_client::sendrawtransaction(const std::string &tx_hex) {
const std::string params = std::string("[\"") + tx_hex + std::string("\"]");
const std::string str = send_post_request("sendrawtransaction", params, debug_rpc_calls);
std::string params = std::string("[\"") + tx_hex + std::string("\"]");
std::string str = send_post_request("sendrawtransaction", params, debug_rpc_calls);
if (str.length() > 0) {
std::stringstream ss(str);
@ -307,8 +310,8 @@ std::string bitcoin_rpc_client::sendrawtransaction(const std::string &tx_hex) {
}
std::string bitcoin_rpc_client::walletlock() {
static const std::string params = std::string("[]");
const std::string str = send_post_request("walletlock", params, debug_rpc_calls);
std::string params = std::string("[]");
std::string str = send_post_request("walletlock", params, debug_rpc_calls);
if (str.length() == 0) {
wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__));
@ -325,8 +328,8 @@ std::string bitcoin_rpc_client::walletlock() {
}
bool bitcoin_rpc_client::walletpassphrase(const std::string &passphrase, uint32_t timeout) {
const std::string params = std::string("[\"") + passphrase + std::string("\",") + std::to_string(timeout) + std::string("]");
const std::string str = send_post_request("walletpassphrase", params, debug_rpc_calls);
std::string params = std::string("[\"") + passphrase + std::string("\",") + std::to_string(timeout) + std::string("]");
std::string str = send_post_request("walletpassphrase", params, debug_rpc_calls);
if (str.length() == 0)
return false;
else
@ -334,52 +337,14 @@ bool bitcoin_rpc_client::walletpassphrase(const std::string &passphrase, uint32_
}
bitcoin_libbitcoin_client::bitcoin_libbitcoin_client(std::string url) :
libbitcoin_client(url) {
estimate_fee_ext = std::unique_ptr<estimate_fee_external>(new estimate_fee_external());
}
uint64_t bitcoin_libbitcoin_client::estimatesmartfee(uint16_t conf_target) {
std::vector<std::pair<std::string, uint64_t>> fees = estimate_fee_ext->get_fee_external(conf_target);
std::vector<uint64_t> accumulated_fees;
for (auto &external_fees : fees) {
if (external_fees.second != 0) {
accumulated_fees.emplace_back(external_fees.second);
}
}
// we will rather pick minimal fee from external sources than internal fee calculation
if (accumulated_fees.empty()) {
accumulated_fees.emplace_back(current_internal_fee);
}
return *std::min_element(accumulated_fees.begin(), accumulated_fees.end());
// TODO for now it's hard-coded value until final implementation
return 20000;
}
std::vector<info_for_vin> bitcoin_libbitcoin_client::getblock(const block_data &block, int32_t verbosity) {
std::unique_lock<std::mutex> lck(libbitcoin_event_mutex);
// estimate fee
const auto &block_trxs = block.block.transactions();
std::vector<libbitcoin::chain::transaction> bucket_trxs;
for (auto &mem_pool_trx : trx_memory_pool) {
for (auto &trx : block_trxs) {
if (mem_pool_trx.hash() == trx.hash()) {
bucket_trxs.emplace_back(mem_pool_trx);
break;
}
}
}
uint64_t average_fee = get_average_fee_from_trxs(bucket_trxs);
if (average_fee > 0 && bucket_trxs.size() >= MIN_TRXS_IN_BUCKET) {
current_internal_fee = average_fee;
}
// We could consider accumulation which could spread to multiple blocks for better metric
// for now we only keep tracking for not confirmed transaction until we get next block
trx_memory_pool.clear();
std::vector<info_for_vin> result;
const libbitcoin::chain::transaction::list trx_list = block.block.transactions();
@ -498,17 +463,10 @@ std::string bitcoin_libbitcoin_client::sendrawtransaction(const std::string &tx_
return res;
}
uint64_t bitcoin_rpc_client::ping(rpc_connection &conn) const {
std::string str = send_post_request(conn, "getblockcount", "[]", debug_rpc_calls);
if (str.length() > 0)
return std::stoll(str);
return std::numeric_limits<uint64_t>::max();
}
// =============================================================================
zmq_listener::zmq_listener(std::string _ip, uint32_t _zmq_block_port, uint32_t _zmq_trx_port) :
zmq_listener_base(_ip, _zmq_block_port, _zmq_trx_port),
zmq_listener::zmq_listener(std::string _ip, uint32_t _zmq) :
zmq_listener_base(_ip, _zmq),
ctx(1),
socket(ctx, ZMQ_SUB) {
}
@ -524,16 +482,16 @@ void zmq_listener::start() {
// socket.setsockopt( ZMQ_SUBSCRIBE, "hashtx", 6 );
// socket.setsockopt( ZMQ_SUBSCRIBE, "rawblock", 8 );
// socket.setsockopt( ZMQ_SUBSCRIBE, "rawtx", 5 );
socket.connect("tcp://" + ip + ":" + std::to_string(block_zmq_port));
socket.connect("tcp://" + ip + ":" + std::to_string(zmq_port));
block_thr = std::thread(&zmq_listener::handle_zmq, this);
thr = std::thread(&zmq_listener::handle_zmq, this);
ilog("zmq_listener thread started");
}
zmq_listener::~zmq_listener() {
stopped = true;
block_thr.join();
thr.join();
}
std::vector<zmq::message_t> zmq_listener::receive_multipart() {
@ -563,7 +521,7 @@ void zmq_listener::handle_zmq() {
const auto block_hash = boost::algorithm::hex(std::string(static_cast<char *>(msg[1].data()), msg[1].size()));
block_data event_data;
event_data.block_hash = block_hash;
block_event_received(event_data);
event_received(event_data);
}
} catch (zmq::error_t &e) {
elog("handle_zmq recv_multipart exception ${str}", ("str", e.what()));
@ -577,68 +535,34 @@ void zmq_listener::handle_zmq() {
// =============================================================================
zmq_listener_libbitcoin::zmq_listener_libbitcoin(std::string _ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port) :
zmq_listener_base(_ip, _block_zmq_port, _trx_zmq_port),
block_socket(block_context, libbitcoin::protocol::zmq::socket::role::subscriber),
trx_socket(trx_context, libbitcoin::protocol::zmq::socket::role::subscriber) {
zmq_listener_libbitcoin::zmq_listener_libbitcoin(std::string _ip, uint32_t _zmq_port) :
zmq_listener_base(_ip, _zmq_port),
socket(context, libbitcoin::protocol::zmq::socket::role::subscriber) {
}
zmq_listener_libbitcoin::~zmq_listener_libbitcoin() {
stopped.store(true);
block_thr.join();
trx_thr.join();
thr.join();
}
void zmq_listener_libbitcoin::start() {
std::string endpoint_address = "tcp://" + ip;
libbitcoin::config::endpoint block_address(endpoint_address, block_zmq_port);
libbitcoin::config::endpoint trx_address(endpoint_address, trx_zmq_port);
block_socket.connect(block_address);
trx_socket.connect(trx_address);
block_thr = std::thread(&zmq_listener_libbitcoin::handle_block, this);
trx_thr = std::thread(&zmq_listener_libbitcoin::handle_trx, this);
}
void zmq_listener_libbitcoin::handle_trx() {
trx_poller.add(trx_socket);
while (!stopped.load()) {
const auto identifiers = trx_poller.wait(500);
if (identifiers.contains(trx_socket.id())) {
libbitcoin::protocol::zmq::message message;
trx_socket.receive(message);
std::vector<uint8_t> data;
for (int i = 0; i < 2; i++) {
data.clear();
message.dequeue(data);
}
libbitcoin::chain::transaction trx;
trx.from_data(data, true);
trx_event_received(trx);
}
}
ilog("zmq_listener_libbitcoin trx thread finished");
libbitcoin::config::endpoint address(endpoint_address, zmq_port);
socket.connect(address);
thr = std::thread(&zmq_listener_libbitcoin::handle_block, this);
}
void zmq_listener_libbitcoin::handle_block() {
block_poller.add(block_socket);
poller.add(socket);
while (!stopped.load()) {
const auto identifiers = block_poller.wait(500);
// FIXME change the hard-coded value
const auto identifiers = poller.wait(500);
if (identifiers.contains(block_socket.id())) {
if (identifiers.contains(socket.id())) {
libbitcoin::protocol::zmq::message message;
block_socket.receive(message);
socket.receive(message);
std::vector<uint8_t> data;
for (int i = 0; i < 3; i++) {
@ -652,40 +576,37 @@ void zmq_listener_libbitcoin::handle_block() {
block_data event_data;
event_data.block_hash = libbitcoin::config::hash256(block.hash()).to_string();
event_data.block = std::move(block);
block_event_received(event_data);
event_received(event_data);
}
}
ilog("zmq_listener_libbitcoin block thread finished");
ilog("zmq_listener_libbitcoin thread finished");
}
// =============================================================================
sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
sidechain_net_handler(sidechain_type::bitcoin, _plugin, options) {
sidechain_net_handler(_plugin, options) {
sidechain = sidechain_type::bitcoin;
if (options.count("debug-rpc-calls")) {
debug_rpc_calls = options.at("debug-rpc-calls").as<bool>();
}
bool simulate_connection_reselection = options.at("simulate-rpc-connection-reselection").as<bool>();
std::vector<std::string> ips = options.at("bitcoin-node-ip").as<std::vector<std::string>>();
bitcoin_node_zmq_port = options.at("bitcoin-node-zmq-port").as<uint32_t>();
uint32_t rpc_port = options.at("bitcoin-node-rpc-port").as<uint32_t>();
std::string rpc_user = options.at("bitcoin-node-rpc-user").as<std::string>();
std::string rpc_password = options.at("bitcoin-node-rpc-password").as<std::string>();
if (options.count("use-bitcoind-client")) {
use_bitcoind_client = options.at("use-bitcoind-client").as<bool>();
}
bitcoin_node_ip = options.at("bitcoin-node-ip").as<std::string>();
bitcoin_node_zmq_port = options.at("bitcoin-node-zmq-port").as<uint32_t>();
libbitcoin_server_ip = options.at("libbitcoin-server-ip").as<std::string>();
libbitcoin_block_zmq_port = options.at("libbitcoin-server-block-zmq-port").as<uint32_t>();
libbitcoin_trx_zmq_port = options.at("libbitcoin-server-trx-zmq-port").as<uint32_t>();
wallet_name = "";
if (options.count("bitcoin-wallet-name")) {
wallet_name = options.at("bitcoin-wallet-name").as<std::string>();
libbitcoin_zmq_port = options.at("libbitcoin-server-zmq-port").as<uint32_t>();
rpc_port = options.at("bitcoin-node-rpc-port").as<uint32_t>();
rpc_user = options.at("bitcoin-node-rpc-user").as<std::string>();
rpc_password = options.at("bitcoin-node-rpc-password").as<std::string>();
std::string wallet = "";
if (options.count("bitcoin-wallet")) {
wallet = options.at("bitcoin-wallet").as<std::string>();
}
wallet_password = "";
if (options.count("bitcoin-wallet-password")) {
@ -705,31 +626,21 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain
}
if (use_bitcoind_client) {
for (size_t i = 0; i < ips.size(); i++) {
std::string ip = ips[i];
std::string url = ip + ":" + std::to_string(rpc_port);
if (!wallet_name.empty()) {
url = url + "/wallet/" + wallet_name;
}
rpc_credentials creds;
creds.url = url;
creds.user = rpc_user;
creds.password = rpc_password;
_rpc_credentials.push_back(creds);
std::string url = bitcoin_node_ip + ":" + std::to_string(rpc_port);
if (wallet.length() > 0) {
url = url + "/wallet/" + wallet;
}
FC_ASSERT(!_rpc_credentials.empty());
bitcoin_client = std::unique_ptr<bitcoin_rpc_client>(new bitcoin_rpc_client(_rpc_credentials, debug_rpc_calls, simulate_connection_reselection));
if (!wallet_name.empty()) {
bitcoin_client->loadwallet(wallet_name);
bitcoin_client = std::unique_ptr<bitcoin_rpc_client>(new bitcoin_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls));
if (!wallet.empty()) {
bitcoin_client->loadwallet(wallet);
}
listener = std::unique_ptr<zmq_listener>(new zmq_listener(ips[0], bitcoin_node_zmq_port));
listener = std::unique_ptr<zmq_listener>(new zmq_listener(bitcoin_node_ip, bitcoin_node_zmq_port));
} else {
bitcoin_client = std::unique_ptr<bitcoin_libbitcoin_client>(new bitcoin_libbitcoin_client(libbitcoin_server_ip));
listener = std::unique_ptr<zmq_listener_libbitcoin>(new zmq_listener_libbitcoin(libbitcoin_server_ip, libbitcoin_block_zmq_port, libbitcoin_trx_zmq_port));
listener = std::unique_ptr<zmq_listener_libbitcoin>(new zmq_listener_libbitcoin(libbitcoin_server_ip, libbitcoin_zmq_port));
}
std::string chain_info = bitcoin_client->getblockchaininfo();
@ -745,15 +656,10 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain
bitcoin_client->getnetworkinfo();
listener->block_event_received.connect([this](const block_data &block_event_data) {
std::thread(&sidechain_net_handler_bitcoin::block_handle_event, this, block_event_data).detach();
});
listener->trx_event_received.connect([this](const libbitcoin::chain::transaction &trx_event_data) {
std::thread(&sidechain_net_handler_bitcoin::trx_handle_event, this, trx_event_data).detach();
});
listener->start();
listener->event_received.connect([this](const block_data &event_data) {
std::thread(&sidechain_net_handler_bitcoin::handle_event, this, event_data).detach();
});
database.changed_objects.connect([this](const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts) {
on_changed_objects(ids, accounts);
@ -774,7 +680,7 @@ sidechain_net_handler_bitcoin::~sidechain_net_handler_bitcoin() {
bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) {
ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id(sidechain)));
// ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id(sidechain)));
bool should_approve = false;
@ -804,15 +710,12 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
bool transaction_ok = false;
std::string new_pw_address = "";
son_wallet_id_type swo_id = op_obj_idx_0.get<son_wallet_update_operation>().son_wallet_id;
const auto ast = active_sidechain_types(database.head_block_time());
const auto id = (swo_id.instance.value - std::distance(ast.begin(), ast.find(sidechain))) / ast.size();
const son_wallet_id_type op_id{id};
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
const auto swo = idx.find(op_id);
const auto swo = idx.find(swo_id);
if (swo != idx.end()) {
const auto &active_sons = gpo.active_sons.at(sidechain);
const auto &wallet_sons = swo->sons.at(sidechain);
vector<son_info> wallet_sons = swo->sons.at(sidechain);
bool son_sets_equal = (active_sons.size() == wallet_sons.size());
@ -825,7 +728,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
if (son_sets_equal) {
const auto &active_sons = gpo.active_sons.at(sidechain);
vector<string> son_pubkeys_bitcoin;
for (const auto &si : active_sons) {
for (const son_info &si : active_sons) {
son_pubkeys_bitcoin.push_back(si.public_key);
}
@ -844,10 +747,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
}
if (po.proposed_transaction.operations.size() >= 2) {
const object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
const auto ast = active_sidechain_types(database.head_block_time());
const auto id = (object_id.instance() - std::distance(ast.begin(), ast.find(sidechain))) / ast.size();
const object_id_type obj_id{object_id.space(), object_id.type(), id};
object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
@ -856,9 +756,9 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
std::string tx_str = "";
if (obj_id.is<son_wallet_id_type>()) {
if (object_id.is<son_wallet_id_type>()) {
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
const auto swo = idx.find(obj_id);
const auto swo = idx.find(object_id);
if (swo != idx.end()) {
tx_str = create_primary_wallet_transaction(*swo, new_pw_address);
}
@ -908,6 +808,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
break;
}
}
tx_amount = input.tx_amount;
break;
}
@ -1056,22 +957,10 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() {
const auto &active_sw = swi.rbegin();
if (active_sw != swi.rend()) {
const auto &prev_sw = std::next(active_sw);
if (prev_sw != swi.rend() && active_sw->sons.at(sidechain) == prev_sw->sons.at(sidechain))
return;
if ((active_sw->addresses.find(sidechain) == active_sw->addresses.end()) ||
(active_sw->addresses.at(sidechain).empty())) {
const auto ast = active_sidechain_types(database.head_block_time());
const auto id = active_sw->id.instance() * ast.size() + std::distance(ast.begin(), ast.find(sidechain));
const object_id_type op_id{active_sw->id.space(), active_sw->id.type(), id};
if (proposal_exists(chain::operation::tag<chain::son_wallet_update_operation>::value, op_id)) {
return;
}
if (!plugin.can_son_participate(sidechain, chain::operation::tag<chain::son_wallet_update_operation>::value, op_id)) {
if (proposal_exists(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
return;
}
@ -1084,7 +973,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() {
boost::property_tree::ptree active_pw_pt;
boost::property_tree::read_json(active_pw_ss, active_pw_pt);
if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) {
if (!plugin.can_son_participate(sidechain, chain::operation::tag<chain::son_wallet_update_operation>::value, op_id)) {
if (!plugin.can_son_participate(sidechain, chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
return;
}
@ -1098,33 +987,23 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() {
son_wallet_update_operation swu_op;
swu_op.payer = gpo.parameters.son_account();
swu_op.son_wallet_id = op_id;
swu_op.son_wallet_id = active_sw->id;
swu_op.sidechain = sidechain;
swu_op.address = res.str();
proposal_op.proposed_ops.emplace_back(swu_op);
const auto &prev_sw = std::next(active_sw);
if (prev_sw != swi.rend()) {
std::string new_pw_address = active_pw_pt.get<std::string>("result.address");
std::string tx_str = create_primary_wallet_transaction(*prev_sw, new_pw_address);
if (!tx_str.empty()) {
const auto ast = active_sidechain_types(database.head_block_time());
const auto prev_id = prev_sw->id.instance() * ast.size() + std::distance(ast.begin(), ast.find(sidechain));
const object_id_type prev_op_id{prev_sw->id.space(), prev_sw->id.type(), prev_id};
sidechain_transaction_create_operation stc_op;
stc_op.payer = gpo.parameters.son_account();
stc_op.object_id = prev_op_id;
stc_op.object_id = prev_sw->id;
stc_op.sidechain = sidechain;
stc_op.transaction = tx_str;
for (const auto &signer : prev_sw->sons.at(sidechain)) {
son_info si;
si.son_id = signer.son_id;
si.weight = signer.weight;
si.signing_key = signer.signing_key;
si.sidechain_public_keys[sidechain] = signer.public_key;
stc_op.signers.emplace_back(std::move(si));
}
stc_op.signers = prev_sw->sons.at(sidechain);
proposal_op.proposed_ops.emplace_back(stc_op);
}
}
@ -1135,7 +1014,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() {
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
if (plugin.app().p2p_node())
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
plugin.log_son_proposal_retry(sidechain, chain::operation::tag<chain::son_wallet_update_operation>::value, op_id);
plugin.log_son_proposal_retry(sidechain, chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id);
} catch (fc::exception &e) {
elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what()));
return;
@ -1232,14 +1111,7 @@ bool sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_obj
stc_op.object_id = swdo.id;
stc_op.sidechain = sidechain;
stc_op.transaction = tx_str;
for (const auto &signer : gpo.active_sons.at(sidechain)) {
son_info si;
si.son_id = signer.son_id;
si.weight = signer.weight;
si.signing_key = signer.signing_key;
si.sidechain_public_keys[sidechain] = signer.public_key;
stc_op.signers.emplace_back(std::move(si));
}
stc_op.signers = gpo.active_sons.at(sidechain);
proposal_op.proposed_ops.emplace_back(stc_op);
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
@ -1283,14 +1155,7 @@ bool sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw
stc_op.object_id = swwo.id;
stc_op.sidechain = sidechain;
stc_op.transaction = tx_str;
for (const auto &signer : gpo.active_sons.at(sidechain)) {
son_info si;
si.son_id = signer.son_id;
si.weight = signer.weight;
si.signing_key = signer.signing_key;
si.sidechain_public_keys[sidechain] = signer.public_key;
stc_op.signers.emplace_back(std::move(si));
}
stc_op.signers = gpo.active_sons.at(sidechain);
proposal_op.proposed_ops.emplace_back(stc_op);
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
@ -1365,9 +1230,9 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain
break;
}
}
settle_amount = asset(tx_amount, database.get_global_properties().parameters.btc_asset());
return true;
}
settle_amount = asset(tx_amount, database.get_global_properties().parameters.btc_asset());
return true;
}
if (sto.object_id.is<son_wallet_withdraw_id_type>()) {
@ -1379,12 +1244,7 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain
return false;
}
optional<asset> sidechain_net_handler_bitcoin::estimate_withdrawal_transaction_fee() const {
wlog("estimate_withdrawal_transaction_fee not implemented for sidechain: ${sidechain}", ("sidechain", sidechain));
return optional<asset>{};
}
std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const std::vector<son_sidechain_info> &son_pubkeys) {
std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const std::vector<son_info> &son_pubkeys) {
using namespace bitcoin;
std::vector<std::pair<fc::ecc::public_key, uint16_t>> pubkey_weights;
@ -1432,11 +1292,11 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_transaction(con
}
uint64_t fee_rate = bitcoin_client->estimatesmartfee();
const uint64_t min_fee_rate = 1000;
uint64_t min_fee_rate = 1000;
fee_rate = std::max(fee_rate, min_fee_rate);
uint64_t total_amount = 0.0;
const std::vector<btc_txout> inputs = bitcoin_client->listunspent_by_address_and_amount(prev_pw_address, 0);
std::vector<btc_txout> inputs = bitcoin_client->listunspent_by_address_and_amount(prev_pw_address, 0);
if (inputs.size() == 0) {
elog("Failed to find UTXOs to spend for ${pw}", ("pw", prev_pw_address));
@ -1479,7 +1339,7 @@ std::string sidechain_net_handler_bitcoin::create_deposit_transaction(const son_
std::string nvout = suid.substr(suid.find_last_of("-") + 1);
uint64_t deposit_amount = swdo.sidechain_amount.value;
uint64_t fee_rate = bitcoin_client->estimatesmartfee();
const uint64_t min_fee_rate = 1000;
uint64_t min_fee_rate = 1000;
fee_rate = std::max(fee_rate, min_fee_rate);
if (fee_rate >= deposit_amount) {
@ -1522,11 +1382,11 @@ std::string sidechain_net_handler_bitcoin::create_withdrawal_transaction(const s
std::string redeem_script = json.get<std::string>("redeemScript");
int64_t fee_rate = bitcoin_client->estimatesmartfee();
const int64_t min_fee_rate = 1000;
int64_t min_fee_rate = 1000;
fee_rate = std::max(fee_rate, min_fee_rate);
int64_t total_amount = 0;
const std::vector<btc_txout> inputs = bitcoin_client->listunspent_by_address_and_amount(pw_address, 0);
std::vector<btc_txout> inputs = bitcoin_client->listunspent_by_address_and_amount(pw_address, 0);
if (inputs.size() == 0) {
elog("Failed to find UTXOs to spend for ${pw}", ("pw", pw_address));
@ -1655,7 +1515,7 @@ std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_tran
return tx.get_txid().str();
}
void sidechain_net_handler_bitcoin::block_handle_event(const block_data &event_data) {
void sidechain_net_handler_bitcoin::handle_event(const block_data &event_data) {
auto vins = bitcoin_client->getblock(event_data);
@ -1679,7 +1539,6 @@ void sidechain_net_handler_bitcoin::block_handle_event(const block_data &event_d
sed.timestamp = database.head_block_time();
sed.block_num = database.head_block_num();
sed.sidechain = addr_itr->sidechain;
sed.type = sidechain_event_type::deposit;
sed.sidechain_uid = sidechain_uid;
sed.sidechain_transaction_id = v.out.hash_tx;
sed.sidechain_from = v.address;
@ -1697,10 +1556,6 @@ void sidechain_net_handler_bitcoin::block_handle_event(const block_data &event_d
}
}
void sidechain_net_handler_bitcoin::trx_handle_event(const libbitcoin::chain::transaction &trx_data) {
bitcoin_client->import_trx_to_memory_pool(trx_data);
}
std::string sidechain_net_handler_bitcoin::get_redeemscript_for_userdeposit(const std::string &user_address) {
using namespace bitcoin;
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();
@ -1777,7 +1632,7 @@ void sidechain_net_handler_bitcoin::on_changed_objects_cb(const vector<object_id
}
//! importmulti
bitcoin_client->importmulti(address_or_script_array);
// bitcoin_client->importmulti(address_or_script_array);
//! Lock wallet
bitcoin_client->walletlock();

View file

@ -1,992 +0,0 @@
#include <graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp>
#include <algorithm>
#include <thread>
#include <boost/algorithm/string.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <fc/crypto/base64.hpp>
#include <fc/log/logger.hpp>
#include <fc/network/ip.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/protocol/son_wallet.hpp>
#include <graphene/chain/sidechain_transaction_object.hpp>
#include <graphene/chain/son_sidechain_info.hpp>
#include <graphene/chain/son_wallet_object.hpp>
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
#define SEND_RAW_TRANSACTION 1
namespace graphene { namespace peerplays_sidechain {
ethereum_rpc_client::ethereum_rpc_client(const std::vector<rpc_credentials> &credentials, bool debug_rpc_calls, bool simulate_connection_reselection) :
rpc_client(sidechain_type::ethereum, credentials, debug_rpc_calls, simulate_connection_reselection) {
}
std::string ethereum_rpc_client::eth_blockNumber() {
const std::string reply_str = send_post_request("eth_blockNumber", "", debug_rpc_calls);
return retrieve_value_from_reply(reply_str, "");
}
std::string ethereum_rpc_client::eth_get_block_by_number(std::string block_number, bool full_block) {
const std::string params = "[ \"" + block_number + "\", " + (full_block ? "true" : "false") + "]";
return send_post_request("eth_getBlockByNumber", params, debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_get_logs(std::string wallet_contract_address) {
const std::string params = "[{\"address\": \"" + wallet_contract_address + "\"}]";
const std::string reply_str = send_post_request("eth_getLogs", params, debug_rpc_calls);
return retrieve_value_from_reply(reply_str, "");
}
std::string ethereum_rpc_client::eth_chainId() {
return send_post_request("eth_chainId", "", debug_rpc_calls);
}
std::string ethereum_rpc_client::net_version() {
return send_post_request("net_version", "", debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_get_transaction_count(const std::string &params) {
return send_post_request("eth_getTransactionCount", params, debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_gas_price() {
return send_post_request("eth_gasPrice", "", debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_estimateGas(const std::string &params) {
return send_post_request("eth_estimateGas", params, debug_rpc_calls);
}
std::string ethereum_rpc_client::get_chain_id() {
const std::string reply_str = eth_chainId();
const auto chain_id_string = retrieve_value_from_reply(reply_str, "");
return chain_id_string.empty() ? "" : std::to_string(ethereum::from_hex<long long>(chain_id_string));
}
std::string ethereum_rpc_client::get_network_id() {
const std::string reply_str = net_version();
return retrieve_value_from_reply(reply_str, "");
}
std::string ethereum_rpc_client::get_nonce(const std::string &address) {
const std::string reply_str = eth_get_transaction_count("[\"" + address + "\", \"pending\"]");
const auto nonce_string = retrieve_value_from_reply(reply_str, "");
if (!nonce_string.empty()) {
const auto nonce_val = ethereum::from_hex<boost::multiprecision::uint256_t>(nonce_string);
return nonce_val == 0 ? ethereum::add_0x("0") : ethereum::add_0x(ethereum::to_hex(nonce_val));
}
return "";
}
std::string ethereum_rpc_client::get_gas_price() {
const std::string reply_str = eth_gas_price();
return retrieve_value_from_reply(reply_str, "");
}
std::string ethereum_rpc_client::get_gas_limit() {
const std::string reply_str = eth_get_block_by_number("latest", false);
if (!reply_str.empty()) {
std::stringstream ss(reply_str);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (json.count("result")) {
std::string gas_limit_s = json.get<std::string>("result.gasLimit");
return gas_limit_s;
}
}
return std::string{};
}
std::string ethereum_rpc_client::get_estimate_gas(const std::string &params) {
const std::string reply_str = eth_estimateGas(params);
return retrieve_value_from_reply(reply_str, "");
}
std::string ethereum_rpc_client::eth_send_transaction(const std::string &params) {
return send_post_request("eth_sendTransaction", "[" + params + "]", debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_send_raw_transaction(const std::string &params) {
return send_post_request("eth_sendRawTransaction", "[ \"" + params + "\" ]", debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_get_transaction_receipt(const std::string &params) {
return send_post_request("eth_getTransactionReceipt", "[\"" + params + "\"]", debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_get_transaction_by_hash(const std::string &params) {
return send_post_request("eth_getTransactionByHash", "[\"" + params + "\"]", debug_rpc_calls);
}
uint64_t ethereum_rpc_client::ping(rpc_connection &conn) const {
std::string reply = send_post_request(conn, "eth_blockNumber", "", debug_rpc_calls);
if (!reply.empty())
return ethereum::from_hex<uint64_t>(retrieve_value_from_reply(reply, ""));
return std::numeric_limits<uint64_t>::max();
}
sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
sidechain_net_handler(sidechain_type::ethereum, _plugin, options) {
if (options.count("debug-rpc-calls")) {
debug_rpc_calls = options.at("debug-rpc-calls").as<bool>();
}
bool simulate_connection_reselection = options.at("simulate-rpc-connection-reselection").as<bool>();
std::vector<std::string> rpc_urls = options.at("ethereum-node-rpc-url").as<std::vector<std::string>>();
std::string rpc_user;
if (options.count("ethereum-node-rpc-user")) {
rpc_user = options.at("ethereum-node-rpc-user").as<std::string>();
} else {
rpc_user = "";
}
std::string rpc_password;
if (options.count("ethereum-node-rpc-password")) {
rpc_password = options.at("ethereum-node-rpc-password").as<std::string>();
} else {
rpc_password = "";
}
wallet_contract_address = options.at("ethereum-wallet-contract-address").as<std::string>();
if (options.count("ethereum-erc-20-address")) {
const std::vector<std::string> symbol_addresses = options["ethereum-erc-20-address"].as<std::vector<std::string>>();
for (const std::string &itr : symbol_addresses) {
auto itr_pair = graphene::app::dejsonify<std::pair<std::string, std::string>>(itr, 5);
ilog("ERC-20 symbol: ${symbol}, address: ${address}", ("symbol", itr_pair.first)("address", itr_pair.second));
if (!itr_pair.first.length() || !itr_pair.second.length()) {
FC_THROW("Invalid symbol address pair.");
}
auto address = itr_pair.second;
std::transform(address.begin(), address.end(), address.begin(), ::tolower);
erc20_addresses.insert(bimap_type::value_type{itr_pair.first, address});
}
}
if (options.count("ethereum-private-key")) {
const std::vector<std::string> pub_priv_keys = options["ethereum-private-key"].as<std::vector<std::string>>();
for (const std::string &itr_key_pair : pub_priv_keys) {
auto key_pair = graphene::app::dejsonify<std::pair<std::string, std::string>>(itr_key_pair, 5);
ilog("Ethereum Public Key: ${public}", ("public", key_pair.first));
if (!key_pair.first.length() || !key_pair.second.length()) {
FC_THROW("Invalid public private key pair.");
}
private_keys[key_pair.first] = key_pair.second;
}
}
for (size_t i = 0; i < rpc_urls.size(); i++) {
rpc_credentials creds;
creds.url = rpc_urls[i];
creds.user = rpc_user;
creds.password = rpc_password;
_rpc_credentials.push_back(creds);
}
FC_ASSERT(!_rpc_credentials.empty());
rpc_client = new ethereum_rpc_client(_rpc_credentials, debug_rpc_calls, simulate_connection_reselection);
const std::string chain_id_str = rpc_client->get_chain_id();
if (chain_id_str.empty()) {
elog("No Ethereum node running at ${url}", ("url", _rpc_credentials[0].url));
FC_ASSERT(false);
}
chain_id = std::stoll(chain_id_str);
const std::string network_id_str = rpc_client->get_network_id();
if (network_id_str.empty()) {
elog("No Ethereum node running at ${url}", ("url", _rpc_credentials[0].url));
FC_ASSERT(false);
}
network_id = std::stoll(network_id_str);
ilog("Running on Ethereum network, chain id ${chain_id_str}, network id ${network_id_str}", ("chain_id_str", chain_id_str)("network_id_str", network_id_str));
const auto block_number = rpc_client->eth_blockNumber();
last_block_received = !block_number.empty() ? ethereum::from_hex<uint64_t>(block_number) : 0;
schedule_ethereum_listener();
event_received.connect([this](const std::string &event_data) {
std::thread(&sidechain_net_handler_ethereum::handle_event, this, event_data).detach();
});
}
sidechain_net_handler_ethereum::~sidechain_net_handler_ethereum() {
}
bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) {
ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id(sidechain)));
bool should_approve = false;
const chain::global_property_object &gpo = database.get_global_properties();
int32_t op_idx_0 = -1;
chain::operation op_obj_idx_0;
if (po.proposed_transaction.operations.size() >= 1) {
op_idx_0 = po.proposed_transaction.operations[0].which();
op_obj_idx_0 = po.proposed_transaction.operations[0];
}
int32_t op_idx_1 = -1;
chain::operation op_obj_idx_1;
(void)op_idx_1;
if (po.proposed_transaction.operations.size() >= 2) {
op_idx_1 = po.proposed_transaction.operations[1].which();
op_obj_idx_1 = po.proposed_transaction.operations[1];
}
switch (op_idx_0) {
case chain::operation::tag<chain::son_wallet_update_operation>::value: {
bool address_ok = false;
bool transaction_ok = false;
const son_wallet_id_type swo_id = op_obj_idx_0.get<son_wallet_update_operation>().son_wallet_id;
const auto ast = active_sidechain_types(database.head_block_time());
const auto id = (swo_id.instance.value - std::distance(ast.begin(), ast.find(sidechain))) / ast.size();
const son_wallet_id_type op_id{id};
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
const auto swo = idx.find(op_id);
if (swo != idx.end()) {
const auto active_sons = gpo.active_sons.at(sidechain);
const vector<son_sidechain_info> wallet_sons = swo->sons.at(sidechain);
bool son_sets_equal = (active_sons.size() == wallet_sons.size());
if (son_sets_equal) {
for (size_t i = 0; i < active_sons.size(); i++) {
son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i);
}
}
if (son_sets_equal) {
address_ok = (op_obj_idx_0.get<son_wallet_update_operation>().address == wallet_contract_address);
}
if (po.proposed_transaction.operations.size() >= 2) {
const object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
const auto id = (object_id.instance() - std::distance(ast.begin(), ast.find(sidechain))) / ast.size();
const object_id_type obj_id{object_id.space(), object_id.type(), id};
const std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
const auto st = st_idx.find(object_id);
if (st == st_idx.end()) {
std::string tx_str = "";
if (obj_id.is<son_wallet_id_type>()) {
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
const auto swo = idx.find(obj_id);
if (swo != idx.end()) {
tx_str = create_primary_wallet_transaction(gpo.active_sons.at(sidechain), object_id.operator std::string());
}
}
transaction_ok = (op_tx_str == tx_str);
}
} else {
transaction_ok = true;
}
}
should_approve = address_ok &&
transaction_ok;
break;
}
case chain::operation::tag<chain::son_wallet_deposit_process_operation>::value: {
bool process_ok = false;
const son_wallet_deposit_id_type swdo_id = op_obj_idx_0.get<son_wallet_deposit_process_operation>().son_wallet_deposit_id;
const auto &idx = database.get_index_type<son_wallet_deposit_index>().indices().get<by_id>();
const auto swdo = idx.find(swdo_id);
if (swdo != idx.end()) {
const std::string swdo_txid = swdo->sidechain_transaction_id;
const std::string swdo_sidechain_from = swdo->sidechain_from;
const std::string swdo_sidechain_currency = swdo->sidechain_currency;
const uint64_t swdo_sidechain_amount = swdo->sidechain_amount.value;
const std::string tx_str = rpc_client->eth_get_transaction_by_hash(swdo_txid);
if (tx_str != "") {
std::stringstream ss_tx(tx_str);
boost::property_tree::ptree tx;
boost::property_tree::read_json(ss_tx, tx);
if (tx.get<std::string>("result") != "null") {
const std::string sidechain_from = tx.get<std::string>("result.from");
const std::string sidechain_to = tx.get<std::string>("result.to");
std::string cmp_sidechain_to = sidechain_to;
std::transform(cmp_sidechain_to.begin(), cmp_sidechain_to.end(), cmp_sidechain_to.begin(), ::toupper);
std::string cmp_wallet_contract_address = wallet_contract_address;
std::transform(cmp_wallet_contract_address.begin(), cmp_wallet_contract_address.end(), cmp_wallet_contract_address.begin(), ::toupper);
//! Check whether it is ERC-20 token deposit
std::string symbol;
boost::multiprecision::uint256_t amount;
bool error_in_deposit = false;
const auto deposit_erc_20 = ethereum::deposit_erc20_decoder::decode(tx.get<std::string>("result.input"));
if (deposit_erc_20.valid()) {
std::string cmp_token = deposit_erc_20->token;
std::transform(cmp_token.begin(), cmp_token.end(), cmp_token.begin(), ::tolower);
const auto it = erc20_addresses.right.find(cmp_token);
if (it == erc20_addresses.right.end()) {
wlog("No erc-20 token with address: ${address}", ("address", cmp_token));
error_in_deposit = true;
}
symbol = it->second;
amount = deposit_erc_20->amount;
} else {
symbol = "ETH";
const std::string value_s = tx.get<std::string>("result.value");
amount = boost::multiprecision::uint256_t{value_s};
amount = amount / 100000;
amount = amount / 100000;
}
process_ok = (!error_in_deposit) &&
(swdo_sidechain_from == sidechain_from) &&
(cmp_sidechain_to == cmp_wallet_contract_address) &&
(swdo_sidechain_currency == symbol) &&
(swdo_sidechain_amount == fc::safe<uint64_t>{amount}.value);
}
}
}
should_approve = process_ok;
break;
}
case chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value: {
bool process_ok = false;
bool transaction_ok = false;
const son_wallet_withdraw_id_type swwo_id = op_obj_idx_0.get<son_wallet_withdraw_process_operation>().son_wallet_withdraw_id;
const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
const auto swwo = idx.find(swwo_id);
if (swwo != idx.end()) {
const uint32_t swwo_block_num = swwo->block_num;
const std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id;
const uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1));
const auto &block = database.fetch_block_by_number(swwo_block_num);
for (const auto &tx : block->transactions) {
if (tx.id().str() == swwo_peerplays_transaction_id) {
const operation op = tx.operations[swwo_op_idx];
const transfer_operation t_op = op.get<transfer_operation>();
const price asset_price = database.get<asset_object>(t_op.amount.asset_id).options.core_exchange_rate;
const asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount);
process_ok = (t_op.to == gpo.parameters.son_account()) &&
(swwo->peerplays_from == t_op.from) &&
(swwo->peerplays_asset == peerplays_asset);
break;
}
}
const object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
const std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
const auto st = st_idx.find(object_id);
if (st == st_idx.end()) {
std::string tx_str = "";
if (object_id.is<son_wallet_withdraw_id_type>()) {
const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
const auto swwo = idx.find(object_id);
if (swwo != idx.end()) {
tx_str = create_withdrawal_transaction(*swwo);
}
}
transaction_ok = (op_tx_str == tx_str);
}
}
should_approve = process_ok &&
transaction_ok;
break;
}
case chain::operation::tag<chain::sidechain_transaction_sign_operation>::value: {
should_approve = true;
const son_id_type signer = op_obj_idx_0.get<sidechain_transaction_sign_operation>().signer;
const std::string signature = op_obj_idx_0.get<sidechain_transaction_sign_operation>().signature;
const sidechain_transaction_id_type sidechain_transaction_id = op_obj_idx_0.get<sidechain_transaction_sign_operation>().sidechain_transaction_id;
const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_id>();
const auto sto = st_idx.find(sidechain_transaction_id);
if (sto == st_idx.end()) {
should_approve = false;
break;
}
const auto &s_idx = database.get_index_type<son_index>().indices().get<by_id>();
const auto son = s_idx.find(signer);
if (son == s_idx.end()) {
should_approve = false;
break;
}
break;
}
case chain::operation::tag<chain::sidechain_transaction_settle_operation>::value: {
should_approve = true;
break;
}
default:
should_approve = false;
elog("==================================================");
elog("Proposal not considered for approval ${po}", ("po", po));
elog("==================================================");
}
return should_approve;
}
void sidechain_net_handler_ethereum::process_primary_wallet() {
const auto &swi = database.get_index_type<son_wallet_index>().indices().get<by_id>();
const auto &active_sw = swi.rbegin();
if (active_sw != swi.rend()) {
const auto &prev_sw = std::next(active_sw);
if (prev_sw != swi.rend() && active_sw->sons.at(sidechain) == prev_sw->sons.at(sidechain))
return;
if ((active_sw->addresses.find(sidechain) == active_sw->addresses.end()) ||
(active_sw->addresses.at(sidechain).empty())) {
const auto ast = active_sidechain_types(database.head_block_time());
const auto id = active_sw->id.instance() * ast.size() + std::distance(ast.begin(), ast.find(sidechain));
const object_id_type op_id{active_sw->id.space(), active_sw->id.type(), id};
if (proposal_exists(chain::operation::tag<chain::son_wallet_update_operation>::value, op_id)) {
return;
}
if (!plugin.can_son_participate(sidechain, chain::operation::tag<chain::son_wallet_update_operation>::value, op_id)) {
return;
}
const chain::global_property_object &gpo = database.get_global_properties();
proposal_create_operation proposal_op;
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
const uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
son_wallet_update_operation swu_op;
swu_op.payer = gpo.parameters.son_account();
swu_op.son_wallet_id = op_id;
swu_op.sidechain = sidechain;
swu_op.address = wallet_contract_address;
proposal_op.proposed_ops.emplace_back(swu_op);
const auto signers = [this, &prev_sw, &active_sw, &swi] {
std::vector<son_sidechain_info> signers;
//! Check if we don't have any previous set of active SONs use the current one
if (prev_sw != swi.rend()) {
if (!prev_sw->sons.at(sidechain).empty())
signers = prev_sw->sons.at(sidechain);
else
signers = active_sw->sons.at(sidechain);
} else {
signers = active_sw->sons.at(sidechain);
}
return signers;
}();
std::string tx_str = create_primary_wallet_transaction(gpo.active_sons.at(sidechain), op_id.operator std::string());
if (!tx_str.empty()) {
sidechain_transaction_create_operation stc_op;
stc_op.payer = gpo.parameters.son_account();
stc_op.object_id = op_id;
stc_op.sidechain = sidechain;
stc_op.transaction = tx_str;
for (const auto &signer : signers) {
son_info si;
si.son_id = signer.son_id;
si.weight = signer.weight;
si.signing_key = signer.signing_key;
si.sidechain_public_keys[sidechain] = signer.public_key;
stc_op.signers.emplace_back(std::move(si));
}
proposal_op.proposed_ops.emplace_back(stc_op);
}
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
try {
trx.validate();
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
if (plugin.app().p2p_node())
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
plugin.log_son_proposal_retry(sidechain, chain::operation::tag<chain::son_wallet_update_operation>::value, op_id);
} catch (fc::exception &e) {
elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what()));
return;
}
}
}
}
void sidechain_net_handler_ethereum::process_sidechain_addresses() {
}
bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) {
if (proposal_exists(chain::operation::tag<chain::son_wallet_deposit_process_operation>::value, swdo.id)) {
return false;
}
const chain::global_property_object &gpo = database.get_global_properties();
const auto &assets_by_symbol = database.get_index_type<asset_index>().indices().get<by_symbol>();
const auto asset_itr = assets_by_symbol.find(swdo.sidechain_currency);
if (asset_itr == assets_by_symbol.end()) {
wlog("Could not find asset: ${symbol}", ("symbol", swdo.sidechain_currency));
return false;
}
const price asset_price = asset_itr->options.core_exchange_rate;
const asset asset_to_issue = asset(swdo.peerplays_asset.amount * asset_price.quote.amount / asset_price.base.amount, asset_itr->get_id());
proposal_create_operation proposal_op;
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
const uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
son_wallet_deposit_process_operation swdp_op;
swdp_op.payer = gpo.parameters.son_account();
swdp_op.son_wallet_deposit_id = swdo.id;
proposal_op.proposed_ops.emplace_back(swdp_op);
asset_issue_operation ai_op;
ai_op.fee = database.current_fee_schedule().calculate_fee(ai_op);
ai_op.issuer = gpo.parameters.son_account();
ai_op.asset_to_issue = asset_to_issue;
ai_op.issue_to_account = swdo.peerplays_from;
proposal_op.proposed_ops.emplace_back(ai_op);
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
try {
trx.validate();
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
if (plugin.app().p2p_node())
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
return true;
} catch (fc::exception &e) {
elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what()));
return false;
}
return false;
}
bool sidechain_net_handler_ethereum::process_withdrawal(const son_wallet_withdraw_object &swwo) {
if (proposal_exists(chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value, swwo.id)) {
return false;
}
std::string tx_str = create_withdrawal_transaction(swwo);
if (!tx_str.empty()) {
const chain::global_property_object &gpo = database.get_global_properties();
proposal_create_operation proposal_op;
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
const uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
son_wallet_withdraw_process_operation swwp_op;
swwp_op.payer = gpo.parameters.son_account();
swwp_op.son_wallet_withdraw_id = swwo.id;
proposal_op.proposed_ops.emplace_back(swwp_op);
sidechain_transaction_create_operation stc_op;
stc_op.payer = gpo.parameters.son_account();
stc_op.object_id = swwo.id;
stc_op.sidechain = sidechain;
stc_op.transaction = tx_str;
for (const auto &signer : gpo.active_sons.at(sidechain)) {
son_info si;
si.son_id = signer.son_id;
si.weight = signer.weight;
si.signing_key = signer.signing_key;
si.sidechain_public_keys[sidechain] = signer.public_key;
stc_op.signers.emplace_back(std::move(si));
}
proposal_op.proposed_ops.emplace_back(stc_op);
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
try {
trx.validate();
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
if (plugin.app().p2p_node())
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
return true;
} catch (fc::exception &e) {
elog("Sending proposal for withdraw sidechain transaction create operation failed with exception ${e}", ("e", e.what()));
return false;
}
}
return false;
}
std::string sidechain_net_handler_ethereum::process_sidechain_transaction(const sidechain_transaction_object &sto) {
return sign_transaction(sto);
}
std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sidechain_transaction_object &sto) {
boost::property_tree::ptree pt;
boost::property_tree::ptree pt_array;
std::vector<ethereum::encoded_sign_transaction> transactions;
for (const auto &signature : sto.signatures) {
//! Check if we have this signed transaction, if not, don't send it
if (signature.second.empty())
continue;
ethereum::encoded_sign_transaction transaction{sto.transaction, ethereum::signature{signature.second}};
transactions.emplace_back(transaction);
}
const auto &current_son = plugin.get_current_son_object(sidechain);
FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account));
const auto &public_key = current_son.sidechain_public_keys.at(sidechain);
const auto function_signature = ethereum::signature_encoder::get_function_signature_from_transaction(sto.transaction);
if (function_signature.empty()) {
elog("Function signature is empty for transaction id ${id}, transaction ${transaction}", ("id", sto.id)("transaction", sto.transaction));
return std::string{}; //! Return empty string, as we have error in sending
}
const ethereum::signature_encoder encoder{function_signature};
#ifdef SEND_RAW_TRANSACTION
const auto data = encoder.encode(transactions);
const std::string params = "[{\"from\":\"" + ethereum::add_0x(public_key) + "\", \"to\":\"" + wallet_contract_address + "\", \"data\":\"" + data + "\"}]";
ethereum::raw_transaction raw_tr;
raw_tr.nonce = rpc_client->get_nonce(ethereum::add_0x(public_key));
raw_tr.gas_price = rpc_client->get_gas_price();
raw_tr.gas_limit = rpc_client->get_estimate_gas(params);
if (raw_tr.gas_limit.empty())
raw_tr.gas_limit = rpc_client->get_gas_limit();
raw_tr.to = wallet_contract_address;
raw_tr.value = "";
raw_tr.data = data;
raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id));
const auto sign_tr = raw_tr.sign(get_private_key(public_key));
const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(sign_tr.serialize());
#else
ethereum::transaction raw_tr;
raw_tr.data = encoder.encode(transactions);
raw_tr.to = wallet_contract_address;
raw_tr.from = ethereum::add_0x(public_key);
const auto sign_tr = raw_tr.sign(get_private_key(public_key));
const std::string sidechain_transaction = rpc_client->eth_send_transaction(sign_tr.serialize());
#endif
std::stringstream ss_tx(sidechain_transaction);
boost::property_tree::ptree tx_json;
boost::property_tree::read_json(ss_tx, tx_json);
if (tx_json.count("result") && !tx_json.count("error")) {
boost::property_tree::ptree node;
node.put("transaction", sto.transaction);
node.put("sidechain_transaction", sidechain_transaction);
node.put("transaction_receipt", tx_json.get<std::string>("result"));
pt_array.push_back(std::make_pair("", node));
} else {
//! Fixme
//! How should we proceed with error in eth_send_transaction
elog("Error in eth send transaction for transaction id ${id}, transaction ${transaction}, sidechain_transaction ${sidechain_transaction}", ("id", sto.id)("transaction", sto.transaction)("sidechain_transaction", sidechain_transaction));
return std::string{}; //! Return empty string, as we have error in sending
}
pt.add_child("result_array", pt_array);
std::stringstream ss;
boost::property_tree::json_parser::write_json(ss, pt);
return ss.str();
}
bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) {
std::stringstream ss(sto.sidechain_transaction);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (!json.count("result_array")) {
return false;
}
size_t count = 0;
for (const auto &entry : json.get_child("result_array")) {
const std::string receipt = rpc_client->eth_get_transaction_receipt(entry.second.get<std::string>("transaction_receipt"));
std::stringstream ss_receipt(receipt);
boost::property_tree::ptree json_receipt;
boost::property_tree::read_json(ss_receipt, json_receipt);
if (json_receipt.get<std::string>("result") == "null") {
wlog("Block is not minted yet for transaction ${id}", ("id", sto.id));
return false;
}
if ("0x1" == json_receipt.get<std::string>("result.status")) {
count += 1;
//! Fixme - compare data somehow?
// if( sto.transaction == entry_receipt.second.get<std::string>("data") ) {
// }
}
}
//! Check that we have all transactions
if (count != json.get_child("result_array").size()) {
wlog("Not all receipts received for transaction ${id}", ("id", sto.id));
return false;
} else {
if (sto.object_id.is<son_wallet_id_type>()) {
settle_amount = asset(0, database.get_global_properties().parameters.eth_asset());
}
if (sto.object_id.is<son_wallet_withdraw_id_type>()) {
auto swwo = database.get<son_wallet_withdraw_object>(sto.object_id);
const auto &assets_by_symbol = database.get_index_type<asset_index>().indices().get<by_symbol>();
const auto asset_itr = assets_by_symbol.find(swwo.withdraw_currency);
if (asset_itr == assets_by_symbol.end()) {
wlog("Could not find asset: ${symbol}", ("symbol", swwo.withdraw_currency));
return false;
}
settle_amount = asset(swwo.withdraw_amount, asset_itr->get_id());
}
return true;
}
return false;
}
optional<asset> sidechain_net_handler_ethereum::estimate_withdrawal_transaction_fee() const {
const auto &gpo = database.get_global_properties();
if (gpo.active_sons.at(sidechain).empty()) {
wlog("No active sons for sidechain: ${sidechain}", ("sidechain", sidechain));
return optional<asset>{};
}
const auto &active_son = gpo.active_sons.at(sidechain).at(0);
const auto &s_idx = database.get_index_type<son_index>().indices().get<by_id>();
const auto son = s_idx.find(active_son.son_id);
if (son == s_idx.end()) {
wlog("Can't find son for id: ${son_id}", ("son_id", active_son.son_id));
return optional<asset>{};
}
if (!son->sidechain_public_keys.contains(sidechain)) {
wlog("No public keys for current son: ${account_id}", ("account_id", son->son_account));
return optional<asset>{};
}
const auto &public_key = son->sidechain_public_keys.at(sidechain);
const auto data = ethereum::withdrawal_encoder::encode(public_key, boost::multiprecision::uint256_t{1} * boost::multiprecision::uint256_t{10000000000}, "0");
const std::string params = "[{\"from\":\"" + ethereum::add_0x(public_key) + "\", \"to\":\"" + wallet_contract_address + "\", \"data\":\"" + data + "\"}]";
const auto estimate_gas = ethereum::from_hex<int64_t>(rpc_client->get_estimate_gas(params));
const auto gas_price = ethereum::from_hex<int64_t>(rpc_client->get_gas_price());
const auto eth_gas_fee = double(estimate_gas * gas_price) / double{1000000000000000000};
const auto asset = database.get<asset_object>(database.get_global_properties().parameters.eth_asset());
return asset.amount_from_string(std::to_string(eth_gas_fee));
}
std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const std::vector<son_sidechain_info> &son_pubkeys, const std::string &object_id) {
std::vector<std::pair<std::string, uint16_t>> owners_weights;
for (auto &son : son_pubkeys) {
const std::string pub_key_str = son.public_key;
owners_weights.emplace_back(std::make_pair(pub_key_str, son.weight));
}
return ethereum::update_owners_encoder::encode(owners_weights, object_id);
}
std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) {
if (swwo.withdraw_currency == "ETH") {
return ethereum::withdrawal_encoder::encode(ethereum::remove_0x(swwo.withdraw_address), boost::multiprecision::uint256_t{swwo.withdraw_amount.value} * boost::multiprecision::uint256_t{10000000000}, swwo.id.operator std::string());
} else {
const auto it = erc20_addresses.left.find(swwo.withdraw_currency);
if (it == erc20_addresses.left.end()) {
elog("No erc-20 token: ${symbol}", ("symbol", swwo.withdraw_currency));
return "";
}
return ethereum::withdrawal_erc20_encoder::encode(ethereum::remove_0x(it->second), ethereum::remove_0x(swwo.withdraw_address), boost::multiprecision::uint256_t{swwo.withdraw_amount.value}, swwo.id.operator std::string());
}
return "";
}
std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) {
const auto &current_son = plugin.get_current_son_object(sidechain);
FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account));
const auto &public_key = current_son.sidechain_public_keys.at(sidechain);
//! We need to change v value according to chain_id
auto signature = ethereum::sign_hash(ethereum::keccak_hash(sto.transaction), ethereum::add_0x(ethereum::to_hex(chain_id)), get_private_key(public_key));
signature.v = ethereum::to_hex(ethereum::from_hex<unsigned int>(signature.v) - 2 * chain_id - 35 + 27);
return signature.serialize();
}
void sidechain_net_handler_ethereum::schedule_ethereum_listener() {
const fc::time_point now = fc::time_point::now();
const int64_t time_to_next = 5000;
const fc::time_point next_wakeup(now + fc::milliseconds(time_to_next));
_listener_task = fc::schedule([this] {
ethereum_listener_loop();
},
next_wakeup, "SON Ethereum listener task");
}
void sidechain_net_handler_ethereum::ethereum_listener_loop() {
schedule_ethereum_listener();
const auto reply = rpc_client->eth_blockNumber();
if (!reply.empty()) {
const uint64_t head_block_number = ethereum::from_hex<uint64_t>(reply);
if (head_block_number != last_block_received) {
//! Check that current block number is greater than last one
if (head_block_number < last_block_received) {
wlog("Head block ${head_block_number} is greater than last received block ${last_block_received}", ("head_block_number", head_block_number)("last_block_received", last_block_received));
return;
}
//! Send event data for all blocks that passed
for (uint64_t i = last_block_received + 1; i <= head_block_number; ++i) {
const std::string block_number = ethereum::add_0x(ethereum::to_hex(i, false));
handle_event(block_number);
}
last_block_received = head_block_number;
}
}
}
void sidechain_net_handler_ethereum::handle_event(const std::string &block_number) {
const std::string block = rpc_client->eth_get_block_by_number(block_number, true);
if (block != "") {
add_to_son_listener_log("BLOCK : " + block_number);
std::stringstream ss(block);
boost::property_tree::ptree block_json;
boost::property_tree::read_json(ss, block_json);
if (block_json.get<string>("result") == "null") {
wlog("No data for block ${block_number}", ("block_number", block_number));
return;
}
size_t tx_idx = -1;
for (const auto &tx_child : block_json.get_child("result.transactions")) {
const boost::property_tree::ptree tx = tx_child.second;
tx_idx = tx_idx + 1;
const std::string to = tx.get<std::string>("to");
std::string from = tx.get<std::string>("from");
std::transform(from.begin(), from.end(), from.begin(), ::tolower);
std::string cmp_to = to;
std::transform(cmp_to.begin(), cmp_to.end(), cmp_to.begin(), ::toupper);
std::string cmp_wallet_contract_address = wallet_contract_address;
std::transform(cmp_wallet_contract_address.begin(), cmp_wallet_contract_address.end(), cmp_wallet_contract_address.begin(), ::toupper);
if (cmp_to == cmp_wallet_contract_address) {
//! Check whether it is ERC-20 token deposit
std::string symbol;
boost::multiprecision::uint256_t amount;
const auto deposit_erc_20 = ethereum::deposit_erc20_decoder::decode(tx.get<std::string>("input"));
if (deposit_erc_20.valid()) {
std::string cmp_token = deposit_erc_20->token;
std::transform(cmp_token.begin(), cmp_token.end(), cmp_token.begin(), ::tolower);
const auto it = erc20_addresses.right.find(cmp_token);
if (it == erc20_addresses.right.end()) {
wlog("No erc-20 token with address: ${address}", ("address", cmp_token));
continue;
}
symbol = it->second;
amount = deposit_erc_20->amount;
} else {
symbol = "ETH";
const std::string value_s = tx.get<std::string>("value");
amount = boost::multiprecision::uint256_t{value_s};
amount = amount / 100000;
amount = amount / 100000;
}
const auto &assets_by_symbol = database.get_index_type<asset_index>().indices().get<by_symbol>();
const auto asset_itr = assets_by_symbol.find(symbol);
if (asset_itr == assets_by_symbol.end()) {
wlog("Could not find asset: ${symbol}", ("symbol", symbol));
continue;
}
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();
const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, from, time_point_sec::maximum()));
if (addr_itr == sidechain_addresses_idx.end()) {
continue;
}
std::stringstream ss;
ss << "ethereum"
<< "-" << tx.get<std::string>("hash") << "-" << tx_idx;
sidechain_event_data sed;
sed.timestamp = database.head_block_time();
sed.block_num = database.head_block_num();
sed.sidechain = sidechain;
sed.type = sidechain_event_type::deposit;
sed.sidechain_uid = ss.str();
sed.sidechain_transaction_id = tx.get<std::string>("hash");
sed.sidechain_from = from;
sed.sidechain_to = to;
sed.sidechain_currency = symbol;
sed.sidechain_amount = amount;
sed.peerplays_from = addr_itr->sidechain_address_account;
sed.peerplays_to = database.get_global_properties().parameters.son_account();
const price price = asset_itr->options.core_exchange_rate;
sed.peerplays_asset = asset(sed.sidechain_amount * price.base.amount / price.quote.amount);
add_to_son_listener_log("TRX : " + sed.sidechain_transaction_id);
sidechain_event_data_received(sed);
}
}
}
}
}} // namespace graphene::peerplays_sidechain

View file

@ -1,7 +1,6 @@
#include <graphene/peerplays_sidechain/sidechain_net_handler_factory.hpp>
#include <graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp>
#include <graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp>
#include <graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp>
#include <graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp>
@ -19,9 +18,6 @@ std::unique_ptr<sidechain_net_handler> sidechain_net_handler_factory::create_han
case sidechain_type::hive: {
return std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_hive(plugin, options));
}
case sidechain_type::ethereum: {
return std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_ethereum(plugin, options));
}
case sidechain_type::peerplays: {
return std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_peerplays(plugin, options));
}

Some files were not shown because too many files have changed in this diff Show more