Bitcoin SON based on libbitcoin
This commit is contained in:
parent
9c9aaa03d3
commit
e9c7021e16
18 changed files with 1396 additions and 423 deletions
96
Dockerfile
96
Dockerfile
|
|
@ -1,5 +1,4 @@
|
||||||
FROM ubuntu:20.04
|
FROM ubuntu:20.04
|
||||||
MAINTAINER Peerplays Blockchain Standards Association
|
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# Ubuntu setup
|
# Ubuntu setup
|
||||||
|
|
@ -51,69 +50,102 @@ RUN echo 'peerplays:peerplays' | chpasswd
|
||||||
# SSH
|
# SSH
|
||||||
EXPOSE 22
|
EXPOSE 22
|
||||||
|
|
||||||
|
WORKDIR /home/peerplays/src
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# Boost setup
|
# Boost setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \
|
wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \
|
||||||
tar -xzvf boost_1_72_0.tar.gz boost_1_72_0 && \
|
tar -xzf boost_1_72_0.tar.gz && \
|
||||||
cd boost_1_72_0/ && \
|
cd boost_1_72_0 && \
|
||||||
./bootstrap.sh && \
|
./bootstrap.sh && \
|
||||||
./b2 install
|
./b2 install && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# cmake setup
|
# cmake setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
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 && \
|
wget https://github.com/Kitware/CMake/releases/download/v3.24.2/cmake-3.24.2-linux-x86_64.sh && \
|
||||||
chmod 755 ./cmake-3.23.1-linux-x86_64.sh && \
|
chmod 755 ./cmake-3.24.2-linux-x86_64.sh && \
|
||||||
./cmake-3.23.1-linux-x86_64.sh --prefix=/usr/ --skip-license && \
|
./cmake-3.24.2-linux-x86_64.sh --prefix=/usr --skip-license && \
|
||||||
cmake --version
|
cmake --version && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# libzmq setup
|
# libzmq setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip && \
|
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.tar.gz && \
|
||||||
unzip v4.3.4.zip && \
|
tar -xzvf v4.3.4.tar.gz && \
|
||||||
cd libzmq-4.3.4 && \
|
cd libzmq-4.3.4 && \
|
||||||
mkdir build && \
|
mkdir build && \
|
||||||
cd build && \
|
cd build && \
|
||||||
cmake .. && \
|
cmake .. && \
|
||||||
make -j$(nproc) install && \
|
make -j$(nproc) && \
|
||||||
ldconfig
|
make install && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# cppzmq setup
|
# cppzmq setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip && \
|
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.9.0.tar.gz && \
|
||||||
unzip v4.8.1.zip && \
|
tar -xzvf v4.9.0.tar.gz && \
|
||||||
cd cppzmq-4.8.1 && \
|
cd cppzmq-4.9.0 && \
|
||||||
mkdir build && \
|
mkdir build && \
|
||||||
cd build && \
|
cd build && \
|
||||||
cmake .. && \
|
cmake .. && \
|
||||||
make -j$(nproc) install && \
|
make -j$(nproc) && \
|
||||||
ldconfig
|
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 https://github.com/libbitcoin/libbitcoin-build.git && \
|
||||||
|
cd libbitcoin-build && \
|
||||||
|
./generate3.sh && \
|
||||||
|
cd ../libbitcoin-explorer && \
|
||||||
|
./install.sh && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# Doxygen setup
|
# Doxygen setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
sudo apt install -y bison flex && \
|
sudo apt install -y bison flex && \
|
||||||
wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \
|
wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \
|
||||||
|
|
@ -129,8 +161,6 @@ RUN \
|
||||||
# Perl setup
|
# Perl setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \
|
wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \
|
||||||
tar -xvf v5.30.0.tar.gz && \
|
tar -xvf v5.30.0.tar.gz && \
|
||||||
|
|
@ -143,8 +173,6 @@ RUN \
|
||||||
# Peerplays setup
|
# Peerplays setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
## Clone Peerplays
|
## Clone Peerplays
|
||||||
#RUN \
|
#RUN \
|
||||||
# git clone https://gitlab.com/PBSA/peerplays.git && \
|
# git clone https://gitlab.com/PBSA/peerplays.git && \
|
||||||
|
|
@ -176,8 +204,8 @@ WORKDIR /home/peerplays/peerplays-network
|
||||||
|
|
||||||
# Setup Peerplays runimage
|
# Setup Peerplays runimage
|
||||||
RUN \
|
RUN \
|
||||||
ln -s /home/peerplays/peerplays/build/programs/cli_wallet/cli_wallet ./ && \
|
ln -s /home/peerplays/src/peerplays/build/programs/cli_wallet/cli_wallet ./ && \
|
||||||
ln -s /home/peerplays/peerplays/build/programs/witness_node/witness_node ./
|
ln -s /home/peerplays/src/peerplays/build/programs/witness_node/witness_node ./
|
||||||
|
|
||||||
RUN ./witness_node --create-genesis-json genesis.json && \
|
RUN ./witness_node --create-genesis-json genesis.json && \
|
||||||
rm genesis.json
|
rm genesis.json
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
FROM ubuntu:18.04
|
FROM ubuntu:18.04
|
||||||
MAINTAINER Peerplays Blockchain Standards Association
|
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# Ubuntu setup
|
# Ubuntu setup
|
||||||
|
|
@ -51,69 +50,102 @@ RUN echo 'peerplays:peerplays' | chpasswd
|
||||||
# SSH
|
# SSH
|
||||||
EXPOSE 22
|
EXPOSE 22
|
||||||
|
|
||||||
|
WORKDIR /home/peerplays/src
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# Boost setup
|
# Boost setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \
|
wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \
|
||||||
tar -xzvf boost_1_72_0.tar.gz boost_1_72_0 && \
|
tar -xzf boost_1_72_0.tar.gz && \
|
||||||
cd boost_1_72_0/ && \
|
cd boost_1_72_0 && \
|
||||||
./bootstrap.sh && \
|
./bootstrap.sh && \
|
||||||
./b2 install
|
./b2 install && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# cmake setup
|
# cmake setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
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 && \
|
wget https://github.com/Kitware/CMake/releases/download/v3.24.2/cmake-3.24.2-linux-x86_64.sh && \
|
||||||
chmod 755 ./cmake-3.23.1-linux-x86_64.sh && \
|
chmod 755 ./cmake-3.24.2-linux-x86_64.sh && \
|
||||||
./cmake-3.23.1-linux-x86_64.sh --prefix=/usr/ --skip-license && \
|
./cmake-3.24.2-linux-x86_64.sh --prefix=/usr --skip-license && \
|
||||||
cmake --version
|
cmake --version && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# libzmq setup
|
# libzmq setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip && \
|
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.tar.gz && \
|
||||||
unzip v4.3.4.zip && \
|
tar -xzvf v4.3.4.tar.gz && \
|
||||||
cd libzmq-4.3.4 && \
|
cd libzmq-4.3.4 && \
|
||||||
mkdir build && \
|
mkdir build && \
|
||||||
cd build && \
|
cd build && \
|
||||||
cmake .. && \
|
cmake .. && \
|
||||||
make -j$(nproc) install && \
|
make -j$(nproc) && \
|
||||||
ldconfig
|
make install && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# cppzmq setup
|
# cppzmq setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip && \
|
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.9.0.tar.gz && \
|
||||||
unzip v4.8.1.zip && \
|
tar -xzvf v4.9.0.tar.gz && \
|
||||||
cd cppzmq-4.8.1 && \
|
cd cppzmq-4.9.0 && \
|
||||||
mkdir build && \
|
mkdir build && \
|
||||||
cd build && \
|
cd build && \
|
||||||
cmake .. && \
|
cmake .. && \
|
||||||
make -j$(nproc) install && \
|
make -j$(nproc) && \
|
||||||
ldconfig
|
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 https://github.com/libbitcoin/libbitcoin-build.git && \
|
||||||
|
cd libbitcoin-build && \
|
||||||
|
./generate3.sh && \
|
||||||
|
cd ../libbitcoin-explorer && \
|
||||||
|
./install.sh && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# Doxygen setup
|
# Doxygen setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
sudo apt install -y bison flex && \
|
sudo apt install -y bison flex && \
|
||||||
wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \
|
wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \
|
||||||
|
|
@ -129,8 +161,6 @@ RUN \
|
||||||
# Perl setup
|
# Perl setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \
|
wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \
|
||||||
tar -xvf v5.30.0.tar.gz && \
|
tar -xvf v5.30.0.tar.gz && \
|
||||||
|
|
@ -143,8 +173,6 @@ RUN \
|
||||||
# Peerplays setup
|
# Peerplays setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
## Clone Peerplays
|
## Clone Peerplays
|
||||||
#RUN \
|
#RUN \
|
||||||
# git clone https://gitlab.com/PBSA/peerplays.git && \
|
# git clone https://gitlab.com/PBSA/peerplays.git && \
|
||||||
|
|
@ -176,8 +204,8 @@ WORKDIR /home/peerplays/peerplays-network
|
||||||
|
|
||||||
# Setup Peerplays runimage
|
# Setup Peerplays runimage
|
||||||
RUN \
|
RUN \
|
||||||
ln -s /home/peerplays/peerplays/build/programs/cli_wallet/cli_wallet ./ && \
|
ln -s /home/peerplays/src/peerplays/build/programs/cli_wallet/cli_wallet ./ && \
|
||||||
ln -s /home/peerplays/peerplays/build/programs/witness_node/witness_node ./
|
ln -s /home/peerplays/src/peerplays/build/programs/witness_node/witness_node ./
|
||||||
|
|
||||||
RUN ./witness_node --create-genesis-json genesis.json && \
|
RUN ./witness_node --create-genesis-json genesis.json && \
|
||||||
rm genesis.json
|
rm genesis.json
|
||||||
|
|
|
||||||
152
README.md
152
README.md
|
|
@ -8,100 +8,41 @@ 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.
|
Officially supported OS are Ubuntu 20.04 and Ubuntu 18.04.
|
||||||
|
|
||||||
## Ubuntu 20.04
|
## Ubuntu 20.04 and 18.04
|
||||||
|
|
||||||
Following dependencies are needed for a clean install of Ubuntu 20.04:
|
Following dependencies are needed for a clean install of Ubuntu 20.04 and Ubuntu 18.04:
|
||||||
```
|
```
|
||||||
sudo apt-get install \
|
sudo apt-get install \
|
||||||
apt-utils autoconf bash build-essential ca-certificates clang-format cmake \
|
autoconf bash bison build-essential ca-certificates dnsutils expect flex git \
|
||||||
dnsutils doxygen expect git graphviz libboost-all-dev libbz2-dev \
|
graphviz libbz2-dev libcurl4-openssl-dev libncurses-dev libpcre3-dev \
|
||||||
libcurl4-openssl-dev libncurses-dev libsnappy-dev \
|
libsnappy-dev libsodium-dev libssl-dev libtool libzip-dev locales lsb-release \
|
||||||
libssl-dev libtool libzip-dev locales lsb-release mc nano net-tools ntp \
|
mc nano net-tools ntp openssh-server pkg-config python3 python3-jinja2 sudo \
|
||||||
openssh-server pkg-config perl python3 python3-jinja2 sudo \
|
|
||||||
systemd-coredump wget
|
systemd-coredump wget
|
||||||
```
|
```
|
||||||
|
|
||||||
Install libzmq from source:
|
Boost libraries setup:
|
||||||
```
|
```
|
||||||
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip
|
wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz
|
||||||
unzip v4.3.4.zip
|
tar -xzf boost_1_72_0.tar.gz boost_1_72_0
|
||||||
cd libzmq-4.3.4
|
cd boost_1_72_0
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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
|
./bootstrap.sh
|
||||||
|
./b2
|
||||||
sudo ./b2 install
|
sudo ./b2 install
|
||||||
|
sudo ldconfig
|
||||||
```
|
```
|
||||||
|
|
||||||
Install cmake
|
cmake setup:
|
||||||
```
|
```
|
||||||
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
|
wget https://github.com/Kitware/CMake/releases/download/v3.24.2/cmake-3.24.2-linux-x86_64.sh
|
||||||
chmod 755 ./cmake-3.23.1-linux-x86_64.sh
|
chmod 755 ./cmake-3.24.2-linux-x86_64.sh
|
||||||
sudo ./cmake-3.23.1-linux-x86_64.sh --prefix=/usr/ --skip-license
|
sudo ./cmake-3.24.2-linux-x86_64.sh --prefix=/usr --skip-license
|
||||||
|
cmake --version
|
||||||
```
|
```
|
||||||
|
|
||||||
Install libzmq from source:
|
libzmq setup:
|
||||||
```
|
```
|
||||||
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip
|
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.tar.gz
|
||||||
unzip v4.3.4.zip
|
tar -xzvf v4.3.4.tar.gz
|
||||||
cd libzmq-4.3.4
|
cd libzmq-4.3.4
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
|
|
@ -111,11 +52,11 @@ sudo make install
|
||||||
sudo ldconfig
|
sudo ldconfig
|
||||||
```
|
```
|
||||||
|
|
||||||
Install cppzmq from source:
|
cppzmq setup:
|
||||||
```
|
```
|
||||||
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip
|
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.9.0.tar.gz
|
||||||
unzip v4.8.1.zip
|
tar -xzvf v4.9.0.tar.gz
|
||||||
cd cppzmq-4.8.1
|
cd cppzmq-4.9.0
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
|
|
@ -124,6 +65,50 @@ sudo make install
|
||||||
sudo ldconfig
|
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 https://github.com/libbitcoin/libbitcoin-build.git
|
||||||
|
cd libbitcoin-build
|
||||||
|
./generate3.sh
|
||||||
|
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
|
Building Peerplays
|
||||||
```
|
```
|
||||||
git clone https://gitlab.com/PBSA/peerplays.git
|
git clone https://gitlab.com/PBSA/peerplays.git
|
||||||
|
|
@ -146,7 +131,6 @@ make -j$(nproc)
|
||||||
sudo make install # this can install the executable files under /usr/local
|
sudo make install # this can install the executable files under /usr/local
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Docker images
|
## Docker images
|
||||||
|
|
||||||
Install docker, and add current user to docker group.
|
Install docker, and add current user to docker group.
|
||||||
|
|
|
||||||
|
|
@ -2340,7 +2340,7 @@ votes_info database_api_impl::get_votes(const string &account_name_or_id) const
|
||||||
votes_for_sons[sidechain].reserve(sidechain_ids.size());
|
votes_for_sons[sidechain].reserve(sidechain_ids.size());
|
||||||
for (const auto &son : sidechain_ids) {
|
for (const auto &son : sidechain_ids) {
|
||||||
const auto &son_obj = son.as<son_object>(6);
|
const auto &son_obj = son.as<son_object>(6);
|
||||||
if(son_obj.get_sidechain_vote_id(sidechain).valid()) {
|
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});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
libraries/plugins/peerplays_sidechain/CMakeLists.txt
Executable file → Normal file
4
libraries/plugins/peerplays_sidechain/CMakeLists.txt
Executable file → Normal file
|
|
@ -16,6 +16,8 @@ add_library( peerplays_sidechain
|
||||||
bitcoin/segwit_addr.cpp
|
bitcoin/segwit_addr.cpp
|
||||||
bitcoin/utils.cpp
|
bitcoin/utils.cpp
|
||||||
bitcoin/sign_bitcoin_transaction.cpp
|
bitcoin/sign_bitcoin_transaction.cpp
|
||||||
|
bitcoin/libbitcoin_client.cpp
|
||||||
|
bitcoin/estimate_fee_external.cpp
|
||||||
common/rpc_client.cpp
|
common/rpc_client.cpp
|
||||||
common/utils.cpp
|
common/utils.cpp
|
||||||
ethereum/encoders.cpp
|
ethereum/encoders.cpp
|
||||||
|
|
@ -42,7 +44,7 @@ endif()
|
||||||
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS)
|
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS)
|
||||||
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE)
|
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE)
|
||||||
|
|
||||||
target_link_libraries( peerplays_sidechain PRIVATE graphene_plugin sha3 zmq )
|
target_link_libraries( peerplays_sidechain PRIVATE curl graphene_plugin sha3 zmq bitcoin-system bitcoin-protocol bitcoin-client bitcoin-explorer )
|
||||||
target_include_directories( peerplays_sidechain
|
target_include_directories( peerplays_sidechain
|
||||||
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
|
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -242,12 +242,12 @@ bytes btc_multisig_segwit_address::get_address_bytes(const bytes &script_hash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
btc_weighted_multisig_address::btc_weighted_multisig_address(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
|
btc_weighted_multisig_address::btc_weighted_multisig_address(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
|
||||||
network ntype) {
|
network ntype, payment_type type) {
|
||||||
network_type = ntype;
|
network_type = ntype;
|
||||||
|
this->type = type;
|
||||||
create_redeem_script(keys_data);
|
create_redeem_script(keys_data);
|
||||||
create_witness_script();
|
create_witness_script();
|
||||||
create_segwit_address();
|
create_segwit_address();
|
||||||
type = payment_type::P2WSH;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void btc_weighted_multisig_address::create_redeem_script(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data) {
|
void btc_weighted_multisig_address::create_redeem_script(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data) {
|
||||||
|
|
@ -278,26 +278,43 @@ void btc_weighted_multisig_address::create_witness_script() {
|
||||||
script_builder builder;
|
script_builder builder;
|
||||||
builder << op::_0;
|
builder << op::_0;
|
||||||
builder << fc::sha256::hash(redeem_script_.data(), redeem_script_.size());
|
builder << fc::sha256::hash(redeem_script_.data(), redeem_script_.size());
|
||||||
|
|
||||||
witness_script_ = builder;
|
witness_script_ = builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
void btc_weighted_multisig_address::create_segwit_address() {
|
void btc_weighted_multisig_address::create_segwit_address() {
|
||||||
std::string hrp;
|
std::string hrp;
|
||||||
|
address_types byte_version;
|
||||||
switch (network_type) {
|
switch (network_type) {
|
||||||
case (network::mainnet):
|
case (network::mainnet):
|
||||||
hrp = "bc";
|
hrp = "bc";
|
||||||
|
byte_version = address_types::MAINNET_SCRIPT;
|
||||||
break;
|
break;
|
||||||
case (network::testnet):
|
case (network::testnet):
|
||||||
hrp = "tb";
|
hrp = "tb";
|
||||||
|
byte_version = address_types::TESTNET_SCRIPT;
|
||||||
break;
|
break;
|
||||||
case (network::regtest):
|
case (network::regtest):
|
||||||
hrp = "bcrt";
|
hrp = "bcrt";
|
||||||
|
byte_version = address_types::TESTNET_SCRIPT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size());
|
|
||||||
std::vector<uint8_t> hash_data(sh.data(), sh.data() + sh.data_size());
|
if (type == payment_type::P2WSH) {
|
||||||
address = segwit_addr::encode(hrp, 0, hash_data);
|
fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size());
|
||||||
|
std::vector<uint8_t> hash_data(sh.data(), sh.data() + sh.data_size());
|
||||||
|
address = segwit_addr::encode(hrp, 0, hash_data);
|
||||||
|
} else if (type == payment_type::P2SH_WSH) {
|
||||||
|
fc::sha256 hash256 = fc::sha256::hash(&witness_script_[0], witness_script_.size());
|
||||||
|
fc::ripemd160 hash160 = fc::ripemd160::hash(hash256.data(), hash256.data_size());
|
||||||
|
raw_address = bytes(hash160.data(), hash160.data() + hash160.data_size());
|
||||||
|
bytes address_bytes(1, byte_version); // 1 byte version
|
||||||
|
address_bytes.insert(address_bytes.end(), raw_address.begin(), raw_address.end());
|
||||||
|
fc::sha256 hash256_1 = fc::sha256::hash(fc::sha256::hash(address_bytes.data(), address_bytes.size()));
|
||||||
|
address_bytes.insert(address_bytes.end(), hash256_1.data(), hash256_1.data() + 4); // 4 byte checksum
|
||||||
|
address = fc::to_base58(address_bytes);
|
||||||
|
} else {
|
||||||
|
wlog("Unsupported payment type of address");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
btc_one_or_m_of_n_multisig_address::btc_one_or_m_of_n_multisig_address(const fc::ecc::public_key &user_key_data,
|
btc_one_or_m_of_n_multisig_address::btc_one_or_m_of_n_multisig_address(const fc::ecc::public_key &user_key_data,
|
||||||
|
|
@ -353,12 +370,12 @@ void btc_one_or_m_of_n_multisig_address::create_segwit_address() {
|
||||||
|
|
||||||
btc_one_or_weighted_multisig_address::btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data,
|
btc_one_or_weighted_multisig_address::btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data,
|
||||||
const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
|
const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
|
||||||
bitcoin_address::network ntype) {
|
bitcoin_address::network ntype, payment_type type) {
|
||||||
network_type = ntype;
|
network_type = ntype;
|
||||||
|
this->type = type;
|
||||||
create_redeem_script(user_key_data, keys_data);
|
create_redeem_script(user_key_data, keys_data);
|
||||||
create_witness_script();
|
create_witness_script();
|
||||||
create_segwit_address();
|
create_segwit_address();
|
||||||
type = payment_type::P2WSH;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void btc_one_or_weighted_multisig_address::create_redeem_script(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data) {
|
void btc_one_or_weighted_multisig_address::create_redeem_script(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data) {
|
||||||
|
|
@ -398,20 +415,39 @@ void btc_one_or_weighted_multisig_address::create_witness_script() {
|
||||||
|
|
||||||
void btc_one_or_weighted_multisig_address::create_segwit_address() {
|
void btc_one_or_weighted_multisig_address::create_segwit_address() {
|
||||||
std::string hrp;
|
std::string hrp;
|
||||||
|
address_types byte_version;
|
||||||
switch (network_type) {
|
switch (network_type) {
|
||||||
case (network::mainnet):
|
case (network::mainnet):
|
||||||
|
byte_version = address_types::MAINNET_SCRIPT;
|
||||||
hrp = "bc";
|
hrp = "bc";
|
||||||
break;
|
break;
|
||||||
case (network::testnet):
|
case (network::testnet):
|
||||||
|
byte_version = address_types::TESTNET_SCRIPT;
|
||||||
hrp = "tb";
|
hrp = "tb";
|
||||||
break;
|
break;
|
||||||
case (network::regtest):
|
case (network::regtest):
|
||||||
|
byte_version = address_types::TESTNET_SCRIPT;
|
||||||
hrp = "bcrt";
|
hrp = "bcrt";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size());
|
|
||||||
std::vector<uint8_t> hash_data(sh.data(), sh.data() + sh.data_size());
|
if (type == payment_type::P2WSH) {
|
||||||
address = segwit_addr::encode(hrp, 0, hash_data);
|
fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size());
|
||||||
|
std::vector<uint8_t> hash_data(sh.data(), sh.data() + sh.data_size());
|
||||||
|
address = segwit_addr::encode(hrp, 0, hash_data);
|
||||||
|
} else if (type == payment_type::P2SH_WSH) {
|
||||||
|
fc::sha256 hash256 = fc::sha256::hash(&witness_script_[0], witness_script_.size());
|
||||||
|
fc::ripemd160 hash160 = fc::ripemd160::hash(hash256.data(), hash256.data_size());
|
||||||
|
raw_address = bytes(hash160.data(), hash160.data() + hash160.data_size());
|
||||||
|
|
||||||
|
bytes address_bytes(1, byte_version); // 1 byte version test net
|
||||||
|
address_bytes.insert(address_bytes.end(), raw_address.begin(), raw_address.end());
|
||||||
|
fc::sha256 hash256_1 = fc::sha256::hash(fc::sha256::hash(address_bytes.data(), address_bytes.size()));
|
||||||
|
address_bytes.insert(address_bytes.end(), hash256_1.data(), hash256_1.data() + 4); // 4 byte checksum
|
||||||
|
address = fc::to_base58(address_bytes);
|
||||||
|
} else {
|
||||||
|
elog("Unsupported payment type of address");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
btc_timelocked_one_or_weighted_multisig_address::btc_timelocked_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, uint32_t latency, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data, bitcoin_address::network ntype) :
|
btc_timelocked_one_or_weighted_multisig_address::btc_timelocked_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, uint32_t latency, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data, bitcoin_address::network ntype) :
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,157 @@
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
@ -0,0 +1,227 @@
|
||||||
|
|
||||||
|
#include <graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp>
|
||||||
|
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
|
#include <bitcoin/explorer/config/transaction.hpp>
|
||||||
|
#include <bitcoin/system/config/hash256.hpp>
|
||||||
|
|
||||||
|
#include <boost/xpressive/xpressive.hpp>
|
||||||
|
|
||||||
|
#include <fc/crypto/hex.hpp>
|
||||||
|
#include <fc/log/logger.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
|
libbitcoin_client::libbitcoin_client(std::string url) :
|
||||||
|
obelisk_client(LIBBITCOIN_SERVER_TIMEOUT, LIBBITCOIN_SERVER_RETRIES) {
|
||||||
|
|
||||||
|
std::string reg_expr = "^((?P<Protocol>https|http|tcp):\\/\\/)?(?P<Host>[a-zA-Z0-9\\-\\.]+)(:(?P<Port>\\d{1,5}))?(?P<Target>\\/.+)?";
|
||||||
|
boost::xpressive::sregex sr = boost::xpressive::sregex::compile(reg_expr);
|
||||||
|
|
||||||
|
boost::xpressive::smatch sm;
|
||||||
|
|
||||||
|
if (boost::xpressive::regex_search(url, sm, sr)) {
|
||||||
|
protocol = sm["Protocol"];
|
||||||
|
if (protocol.empty()) {
|
||||||
|
protocol = "tcp";
|
||||||
|
}
|
||||||
|
|
||||||
|
host = sm["Host"];
|
||||||
|
if (host.empty()) {
|
||||||
|
host + "localhost";
|
||||||
|
}
|
||||||
|
|
||||||
|
port = sm["Port"];
|
||||||
|
if (port.empty()) {
|
||||||
|
port = "9091";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t port_num = std::stoi(port);
|
||||||
|
std::string final_url = protocol + "://" + host;
|
||||||
|
|
||||||
|
libbitcoin::config::endpoint address(final_url, port_num);
|
||||||
|
|
||||||
|
libbitcoin::client::connection_type connection;
|
||||||
|
connection.retries = LIBBITCOIN_SERVER_RETRIES;
|
||||||
|
connection.server = address;
|
||||||
|
|
||||||
|
if (!obelisk_client.connect(connection)) {
|
||||||
|
elog("Can't connect libbitcoin for url: ${url}", ("url", final_url));
|
||||||
|
}
|
||||||
|
|
||||||
|
is_connected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string libbitcoin_client::send_transaction(std::string tx) {
|
||||||
|
|
||||||
|
std::string res;
|
||||||
|
|
||||||
|
auto error_handler = [&](const std::error_code &ec) {
|
||||||
|
elog("error on sending bitcoin transaction ${error_code}", ("error_code", ec.message()));
|
||||||
|
};
|
||||||
|
|
||||||
|
auto result_handler = [&](libbitcoin::code result_code) {
|
||||||
|
ilog("result code on sending transaction ${result_code}", ("result_code", result_code.message()));
|
||||||
|
res = std::to_string(result_code.value());
|
||||||
|
};
|
||||||
|
|
||||||
|
libbitcoin::explorer::config::transaction transaction(tx);
|
||||||
|
|
||||||
|
libbitcoin::chain::transaction trx;
|
||||||
|
|
||||||
|
// This validates the tx, submits it to local tx pool, and notifies peers.
|
||||||
|
obelisk_client.transaction_pool_broadcast(error_handler, result_handler, transaction);
|
||||||
|
obelisk_client.wait();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
libbitcoin::chain::output::list libbitcoin_client::get_transaction(std::string tx_id, std::string &tx_hash, uint32_t &confirmitions) {
|
||||||
|
|
||||||
|
libbitcoin::chain::output::list outs;
|
||||||
|
|
||||||
|
auto error_handler = [&](const std::error_code &ec) {
|
||||||
|
elog("error on fetch_trx_by_hash: ${hash} ${error_code}", ("hash", tx_id)("error_code", ec.message()));
|
||||||
|
};
|
||||||
|
|
||||||
|
auto transaction_handler = [&](const libbitcoin::chain::transaction &tx_handler) {
|
||||||
|
tx_hash = libbitcoin::config::hash256(tx_handler.hash(false)).to_string();
|
||||||
|
// TODO try to find this value (confirmitions)
|
||||||
|
confirmitions = 1;
|
||||||
|
outs = tx_handler.outputs();
|
||||||
|
};
|
||||||
|
|
||||||
|
libbitcoin::hash_digest hash = libbitcoin::config::hash256(tx_id);
|
||||||
|
|
||||||
|
// obelisk_client.blockchain_fetch_transaction (error_handler, transaction_handler,hash);
|
||||||
|
obelisk_client.blockchain_fetch_transaction2(error_handler, transaction_handler, hash);
|
||||||
|
|
||||||
|
obelisk_client.wait();
|
||||||
|
|
||||||
|
return outs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<list_unspent_replay> libbitcoin_client::listunspent(std::string address, double amount) {
|
||||||
|
std::vector<list_unspent_replay> result;
|
||||||
|
|
||||||
|
auto error_handler = [&](const std::error_code &ec) {
|
||||||
|
elog("error on list_unspent ${error_code}", ("error_code", ec.message()));
|
||||||
|
};
|
||||||
|
|
||||||
|
auto replay_handler = [&](const libbitcoin::chain::points_value &points) {
|
||||||
|
for (auto &point : points.points) {
|
||||||
|
list_unspent_replay output;
|
||||||
|
output.hash = libbitcoin::config::hash256(point.hash()).to_string();
|
||||||
|
output.value = point.value();
|
||||||
|
output.index = point.index();
|
||||||
|
result.emplace_back(output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
libbitcoin::wallet::payment_address payment_address(address);
|
||||||
|
uint64_t satoshi = 100000000 * amount;
|
||||||
|
|
||||||
|
obelisk_client.blockchain_fetch_unspent_outputs(error_handler,
|
||||||
|
replay_handler, payment_address, satoshi, libbitcoin::wallet::select_outputs::algorithm::individual);
|
||||||
|
|
||||||
|
obelisk_client.wait();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libbitcoin_client::get_is_test_net() {
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
auto error_handler = [&](const std::error_code &ec) {
|
||||||
|
elog("error on fetching genesis block ${error_code}", ("error_code", ec.message()));
|
||||||
|
};
|
||||||
|
|
||||||
|
auto block_header_handler = [&](const libbitcoin::chain::header &block_header) {
|
||||||
|
std::string hash_str = libbitcoin::config::hash256(block_header.hash()).to_string();
|
||||||
|
if (hash_str == GENESIS_TESTNET_HASH || hash_str == GENESIS_REGTEST_HASH) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
|
@ -8,6 +8,14 @@ using namespace graphene::chain;
|
||||||
namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
|
namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
|
||||||
|
|
||||||
const bytes op_num = {0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}; // OP_1 - OP_15
|
const bytes op_num = {0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}; // OP_1 - OP_15
|
||||||
|
enum address_types { MAINNET_SCRIPT = 5,
|
||||||
|
TESTNET_SCRIPT = 196 };
|
||||||
|
|
||||||
|
enum script_op {
|
||||||
|
OP_0 = 0x00,
|
||||||
|
OP_PUSH = 0x20,
|
||||||
|
OP_SIZE_34 = 0x22
|
||||||
|
};
|
||||||
|
|
||||||
class bitcoin_address {
|
class bitcoin_address {
|
||||||
|
|
||||||
|
|
@ -96,9 +104,6 @@ private:
|
||||||
void create_address();
|
void create_address();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum address_types { MAINNET_SCRIPT = 5,
|
|
||||||
TESTNET_SCRIPT = 196 };
|
|
||||||
|
|
||||||
enum { OP_0 = 0x00,
|
enum { OP_0 = 0x00,
|
||||||
OP_EQUAL = 0x87,
|
OP_EQUAL = 0x87,
|
||||||
OP_HASH160 = 0xa9,
|
OP_HASH160 = 0xa9,
|
||||||
|
|
@ -145,7 +150,7 @@ public:
|
||||||
btc_weighted_multisig_address() = default;
|
btc_weighted_multisig_address() = default;
|
||||||
|
|
||||||
btc_weighted_multisig_address(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
|
btc_weighted_multisig_address(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
|
||||||
network network_type = network::regtest);
|
network network_type = network::regtest, payment_type type = payment_type::P2SH_WSH);
|
||||||
|
|
||||||
bytes get_redeem_script() const {
|
bytes get_redeem_script() const {
|
||||||
return redeem_script_;
|
return redeem_script_;
|
||||||
|
|
@ -190,7 +195,7 @@ class btc_one_or_weighted_multisig_address : public bitcoin_address {
|
||||||
public:
|
public:
|
||||||
btc_one_or_weighted_multisig_address() = default;
|
btc_one_or_weighted_multisig_address() = default;
|
||||||
btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
|
btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
|
||||||
network network_type = network::regtest);
|
network network_type = network::regtest, payment_type type = payment_type::P2SH_WSH);
|
||||||
bytes get_redeem_script() const {
|
bytes get_redeem_script() const {
|
||||||
return redeem_script_;
|
return redeem_script_;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#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
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <bitcoin/client/obelisk_client.hpp>
|
||||||
|
#include <bitcoin/client/socket_stream.hpp>
|
||||||
|
#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"
|
||||||
|
#define GENESIS_REGTEST_HASH "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
|
typedef std::function<void(const libbitcoin::chain::block &)>
|
||||||
|
block_update_handler;
|
||||||
|
|
||||||
|
struct list_unspent_replay {
|
||||||
|
std::string hash;
|
||||||
|
uint64_t value;
|
||||||
|
uint32_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
class libbitcoin_client {
|
||||||
|
public:
|
||||||
|
libbitcoin_client(std::string url);
|
||||||
|
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:
|
||||||
|
libbitcoin::client::obelisk_client obelisk_client;
|
||||||
|
libbitcoin::protocol::zmq::identifier id;
|
||||||
|
|
||||||
|
std::string protocol;
|
||||||
|
std::string host;
|
||||||
|
std::string port;
|
||||||
|
std::string url;
|
||||||
|
|
||||||
|
bool is_connected = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <fc/crypto/elliptic.hpp>
|
#include <fc/crypto/elliptic.hpp>
|
||||||
#include <fc/crypto/hex.hpp>
|
#include <fc/crypto/hex.hpp>
|
||||||
#include <graphene/peerplays_sidechain/bitcoin/types.hpp>
|
#include <graphene/peerplays_sidechain/bitcoin/types.hpp>
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ protected:
|
||||||
sidechain_type sidechain;
|
sidechain_type sidechain;
|
||||||
|
|
||||||
bool debug_rpc_calls;
|
bool debug_rpc_calls;
|
||||||
|
bool use_bitcoind_client;
|
||||||
|
|
||||||
std::map<std::string, std::string> private_keys;
|
std::map<std::string, std::string> private_keys;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <graphene/peerplays_sidechain/common/rpc_client.hpp>
|
|
||||||
#include <graphene/peerplays_sidechain/sidechain_net_handler.hpp>
|
#include <graphene/peerplays_sidechain/sidechain_net_handler.hpp>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <zmq_addon.hpp>
|
#include <zmq_addon.hpp>
|
||||||
|
|
||||||
#include <boost/signals2.hpp>
|
#include <boost/signals2.hpp>
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#include <fc/network/http/connection.hpp>
|
#include <fc/network/http/connection.hpp>
|
||||||
|
|
||||||
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_address.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 {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
|
|
@ -23,7 +25,27 @@ public:
|
||||||
uint64_t amount_;
|
uint64_t amount_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class bitcoin_rpc_client : public rpc_client {
|
class btc_txin {
|
||||||
|
public:
|
||||||
|
std::vector<std::string> tx_address;
|
||||||
|
uint64_t tx_amount;
|
||||||
|
uint64_t tx_vout;
|
||||||
|
};
|
||||||
|
|
||||||
|
class btc_tx {
|
||||||
|
public:
|
||||||
|
std::string tx_txid;
|
||||||
|
uint32_t tx_confirmations;
|
||||||
|
std::vector<btc_txin> tx_in_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
class block_data {
|
||||||
|
public:
|
||||||
|
std::string block_hash;
|
||||||
|
libbitcoin::chain::block block;
|
||||||
|
};
|
||||||
|
|
||||||
|
class bitcoin_client_base {
|
||||||
public:
|
public:
|
||||||
enum class multi_type {
|
enum class multi_type {
|
||||||
script,
|
script,
|
||||||
|
|
@ -41,14 +63,47 @@ public:
|
||||||
std::string label;
|
std::string label;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtual uint64_t estimatesmartfee(uint16_t conf_target = 1) = 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 "";
|
||||||
|
};
|
||||||
|
virtual std::string walletlock() {
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
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:
|
public:
|
||||||
bitcoin_rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls);
|
bitcoin_rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls);
|
||||||
|
|
||||||
std::string createwallet(const std::string &wallet_name);
|
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);
|
||||||
std::string getblock(const std::string &block_hash, int32_t verbosity = 2);
|
btc_tx getrawtransaction(const std::string &txid, const bool verbose = false);
|
||||||
std::string getrawtransaction(const std::string &txid, const bool verbose = false);
|
void getnetworkinfo();
|
||||||
std::string getnetworkinfo();
|
|
||||||
std::string getblockchaininfo();
|
std::string getblockchaininfo();
|
||||||
void importmulti(const std::vector<multi_params> &address_or_script_array, const bool rescan = true);
|
void importmulti(const std::vector<multi_params> &address_or_script_array, const bool rescan = true);
|
||||||
std::vector<btc_txout> listunspent(const uint32_t minconf = 1, const uint32_t maxconf = 9999999);
|
std::vector<btc_txout> listunspent(const uint32_t minconf = 1, const uint32_t maxconf = 9999999);
|
||||||
|
|
@ -60,35 +115,84 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string ip;
|
std::string ip;
|
||||||
uint32_t rpc_port;
|
|
||||||
std::string user;
|
std::string user;
|
||||||
std::string password;
|
std::string password;
|
||||||
std::string wallet_name;
|
std::string wallet_name;
|
||||||
std::string wallet_password;
|
std::string wallet_password;
|
||||||
|
uint32_t bitcoin_major_version;
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
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();
|
||||||
|
std::string getblockchaininfo();
|
||||||
|
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);
|
||||||
|
std::string sendrawtransaction(const std::string &tx_hex);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool is_test_net = false;
|
||||||
|
std::unique_ptr<estimate_fee_external> estimate_fee_ext;
|
||||||
|
uint64_t current_internal_fee = DEAFULT_LIBBITCOIN_TRX_FEE;
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
class zmq_listener {
|
class zmq_listener_base {
|
||||||
public:
|
public:
|
||||||
zmq_listener(std::string _ip, uint32_t _zmq);
|
virtual ~zmq_listener_base(){};
|
||||||
virtual ~zmq_listener();
|
zmq_listener_base(std::string _ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port = 0) {
|
||||||
|
ip = _ip;
|
||||||
|
block_zmq_port = _block_zmq_port;
|
||||||
|
trx_zmq_port = _trx_zmq_port;
|
||||||
|
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;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string ip;
|
||||||
|
uint32_t block_zmq_port;
|
||||||
|
uint32_t trx_zmq_port;
|
||||||
|
std::atomic_bool stopped;
|
||||||
|
std::thread block_thr;
|
||||||
|
std::thread trx_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);
|
||||||
|
virtual ~zmq_listener();
|
||||||
void start();
|
void start();
|
||||||
boost::signals2::signal<void(const std::string &)> event_received;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handle_zmq();
|
void handle_zmq();
|
||||||
std::vector<zmq::message_t> receive_multipart();
|
std::vector<zmq::message_t> receive_multipart();
|
||||||
|
|
||||||
std::string ip;
|
|
||||||
uint32_t zmq_port;
|
|
||||||
|
|
||||||
zmq::context_t ctx;
|
zmq::context_t ctx;
|
||||||
zmq::socket_t socket;
|
zmq::socket_t socket;
|
||||||
|
};
|
||||||
|
|
||||||
std::atomic_bool stopped;
|
class zmq_listener_libbitcoin : public zmq_listener_base {
|
||||||
std::thread thr;
|
public:
|
||||||
|
zmq_listener_libbitcoin(std::string _ip, uint32_t _block_zmq_port = 9093, uint32_t _trx_zmq_port = 9094);
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
@ -109,16 +213,19 @@ public:
|
||||||
virtual optional<asset> estimate_withdrawal_transaction_fee() const override;
|
virtual optional<asset> estimate_withdrawal_transaction_fee() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string ip;
|
std::string bitcoin_node_ip;
|
||||||
uint32_t zmq_port;
|
std::string libbitcoin_server_ip;
|
||||||
|
uint32_t libbitcoin_block_zmq_port;
|
||||||
|
uint32_t libbitcoin_trx_zmq_port;
|
||||||
|
uint32_t bitcoin_node_zmq_port;
|
||||||
uint32_t rpc_port;
|
uint32_t rpc_port;
|
||||||
std::string rpc_user;
|
std::string rpc_user;
|
||||||
std::string rpc_password;
|
std::string rpc_password;
|
||||||
std::string wallet_name;
|
std::string wallet_name;
|
||||||
std::string wallet_password;
|
std::string wallet_password;
|
||||||
|
|
||||||
std::unique_ptr<bitcoin_rpc_client> bitcoin_client;
|
std::unique_ptr<bitcoin_client_base> bitcoin_client;
|
||||||
std::unique_ptr<zmq_listener> listener;
|
std::unique_ptr<zmq_listener_base> listener;
|
||||||
|
|
||||||
fc::future<void> on_changed_objects_task;
|
fc::future<void> on_changed_objects_task;
|
||||||
|
|
||||||
|
|
@ -138,9 +245,9 @@ private:
|
||||||
std::string sign_transaction(const sidechain_transaction_object &sto);
|
std::string sign_transaction(const sidechain_transaction_object &sto);
|
||||||
std::string send_transaction(const sidechain_transaction_object &sto);
|
std::string send_transaction(const sidechain_transaction_object &sto);
|
||||||
|
|
||||||
void handle_event(const std::string &event_data);
|
void block_handle_event(const block_data &event_data);
|
||||||
|
void trx_handle_event(const libbitcoin::chain::transaction &event_data);
|
||||||
std::string get_redeemscript_for_userdeposit(const std::string &user_address);
|
std::string get_redeemscript_for_userdeposit(const std::string &user_address);
|
||||||
std::vector<info_for_vin> extract_info_from_block(const std::string &_block);
|
|
||||||
void on_changed_objects(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts);
|
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);
|
void on_changed_objects_cb(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,10 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
|
||||||
cli.add_options()("debug-rpc-calls", bpo::value<bool>()->default_value(false), "Outputs RPC calls to console");
|
cli.add_options()("debug-rpc-calls", bpo::value<bool>()->default_value(false), "Outputs RPC calls to console");
|
||||||
|
|
||||||
cli.add_options()("bitcoin-sidechain-enabled", bpo::value<bool>()->default_value(false), "Bitcoin sidechain handler enabled");
|
cli.add_options()("bitcoin-sidechain-enabled", bpo::value<bool>()->default_value(false), "Bitcoin sidechain handler enabled");
|
||||||
|
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-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-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-port", bpo::value<uint32_t>()->default_value(8332), "RPC port of Bitcoin node");
|
||||||
|
|
@ -192,7 +196,7 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
|
||||||
cli.add_options()("ethereum-node-rpc-user", bpo::value<string>(), "Ethereum RPC user");
|
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-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-wallet-contract-address", bpo::value<string>(), "Ethereum wallet contract address");
|
||||||
cli.add_options()("erc-20-address", bpo::value<vector<string>>()->composing()->multitoken(),
|
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)");
|
"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")),
|
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)");
|
"Tuple of [Ethereum public key, Ethereum private key] (may specify multiple times)");
|
||||||
|
|
@ -249,12 +253,14 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt
|
||||||
}
|
}
|
||||||
|
|
||||||
sidechain_enabled_bitcoin = options.at("bitcoin-sidechain-enabled").as<bool>();
|
sidechain_enabled_bitcoin = options.at("bitcoin-sidechain-enabled").as<bool>();
|
||||||
config_ready_bitcoin = options.count("bitcoin-node-ip") &&
|
|
||||||
options.count("bitcoin-node-zmq-port") && options.count("bitcoin-node-rpc-port") &&
|
config_ready_bitcoin = (((options.count("libbitcoin-server-ip") && options.count("libbitcoin-server-zmq-port")) ||
|
||||||
options.count("bitcoin-node-rpc-user") && options.count("bitcoin-node-rpc-password") &&
|
(options.count("bitcoin-node-ip") && options.count("bitcoin-node-zmq-port") &&
|
||||||
options.count("bitcoin-wallet-name") && options.count("bitcoin-wallet-password") &&
|
options.count("bitcoin-node-rpc-port") && options.count("bitcoin-node-rpc-user") &&
|
||||||
options.count("bitcoin-private-key");
|
options.count("bitcoin-node-rpc-password") && options.count("bitcoin-wallet-name") &&
|
||||||
if (sidechain_enabled_bitcoin && !config_ready_bitcoin) {
|
options.count("bitcoin-wallet-password"))) &&
|
||||||
|
options.count("bitcoin-private-key"));
|
||||||
|
if (!config_ready_bitcoin) {
|
||||||
wlog("Haven't set up Bitcoin sidechain parameters");
|
wlog("Haven't set up Bitcoin sidechain parameters");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,6 @@ bitcoin_rpc_client::bitcoin_rpc_client(std::string _url, std::string _user, std:
|
||||||
rpc_client(_url, _user, _password, _debug_rpc_calls) {
|
rpc_client(_url, _user, _password, _debug_rpc_calls) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string bitcoin_rpc_client::createwallet(const std::string &wallet_name) {
|
|
||||||
const std::string params = std::string("[\"") + wallet_name + std::string("\"]");
|
|
||||||
return send_post_request("createwallet", params, debug_rpc_calls);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t bitcoin_rpc_client::estimatesmartfee(uint16_t conf_target) {
|
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 params = std::string("[") + std::to_string(conf_target) + std::string("]");
|
||||||
const std::string str = send_post_request("estimatesmartfee", params, debug_rpc_calls);
|
const std::string str = send_post_request("estimatesmartfee", params, debug_rpc_calls);
|
||||||
|
|
@ -58,36 +53,130 @@ uint64_t bitcoin_rpc_client::estimatesmartfee(uint16_t conf_target) {
|
||||||
return 20000;
|
return 20000;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string bitcoin_rpc_client::getblock(const std::string &block_hash, int32_t verbosity) {
|
std::vector<info_for_vin> bitcoin_rpc_client::getblock(const block_data &block, int32_t verbosity) {
|
||||||
const std::string params = std::string("[\"") + block_hash + std::string("\",") + std::to_string(verbosity) + std::string("]");
|
std::string params = std::string("[\"") + block.block_hash + std::string("\",") + std::to_string(verbosity) + std::string("]");
|
||||||
return send_post_request("getblock", params, debug_rpc_calls);
|
std::string str = send_post_request("getblock", params, debug_rpc_calls);
|
||||||
|
std::vector<info_for_vin> result;
|
||||||
|
|
||||||
|
if (str.empty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss(str);
|
||||||
|
boost::property_tree::ptree json;
|
||||||
|
boost::property_tree::read_json(ss, json);
|
||||||
|
|
||||||
|
auto json_result = json.get_child_optional("result");
|
||||||
|
|
||||||
|
for (const auto &tx_child : json_result.get().get_child("tx")) {
|
||||||
|
const auto &tx = tx_child.second;
|
||||||
|
|
||||||
|
for (const auto &o : tx.get_child("vout")) {
|
||||||
|
const auto script = o.second.get_child("scriptPubKey");
|
||||||
|
std::vector<std::string> address_list;
|
||||||
|
|
||||||
|
if (script.count("address")) {
|
||||||
|
address_list.emplace_back(script.get<std::string>("address"));
|
||||||
|
} else if (script.count("addresses")) {
|
||||||
|
for (const auto &addr : script.get_child("addresses")) {
|
||||||
|
address_list.emplace_back(addr.second.get_value<std::string>());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &address : address_list) {
|
||||||
|
const auto address_base58 = address;
|
||||||
|
info_for_vin vin;
|
||||||
|
vin.out.hash_tx = tx.get_child("txid").get_value<std::string>();
|
||||||
|
string amount = o.second.get_child("value").get_value<std::string>();
|
||||||
|
amount.erase(std::remove(amount.begin(), amount.end(), '.'), amount.end());
|
||||||
|
vin.out.amount = std::stoll(amount);
|
||||||
|
vin.out.n_vout = o.second.get_child("n").get_value<uint32_t>();
|
||||||
|
vin.address = address_base58;
|
||||||
|
result.push_back(vin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string bitcoin_rpc_client::getnetworkinfo() {
|
void bitcoin_rpc_client::getnetworkinfo() {
|
||||||
static const std::string params = std::string("[]");
|
std::string params = std::string("[]");
|
||||||
return send_post_request("getnetworkinfo", params, debug_rpc_calls);
|
std::string str = send_post_request("getnetworkinfo", params, debug_rpc_calls);
|
||||||
|
|
||||||
|
std::stringstream network_info_ss(str);
|
||||||
|
boost::property_tree::ptree network_info_json;
|
||||||
|
boost::property_tree::read_json(network_info_ss, network_info_json);
|
||||||
|
|
||||||
|
bitcoin_major_version = network_info_json.get<uint32_t>("result.version") / 10000;
|
||||||
|
ilog("Bitcoin major version is: '${version}'", ("version", bitcoin_major_version));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string bitcoin_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) {
|
btc_tx bitcoin_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) {
|
||||||
const std::string params = std::string("[\"") + txid + std::string("\",") + (verbose ? "true" : "false") + std::string("]");
|
std::string params = std::string("[\"") + txid + std::string("\",") + (verbose ? "true" : "false") + std::string("]");
|
||||||
return send_post_request("getrawtransaction", params, debug_rpc_calls);
|
std::string str = send_post_request("getrawtransaction", params, debug_rpc_calls);
|
||||||
|
|
||||||
|
btc_tx tx;
|
||||||
|
|
||||||
|
std::stringstream tx_ss(str);
|
||||||
|
boost::property_tree::ptree tx_json;
|
||||||
|
boost::property_tree::read_json(tx_ss, tx_json);
|
||||||
|
|
||||||
|
if (tx_json.count("error") && tx_json.get_child("error").empty()) {
|
||||||
|
|
||||||
|
std::string tx_txid = tx_json.get<std::string>("result.txid");
|
||||||
|
uint32_t tx_confirmations = tx_json.get<uint32_t>("result.confirmations");
|
||||||
|
|
||||||
|
tx.tx_txid = tx_txid;
|
||||||
|
tx.tx_confirmations = tx_confirmations;
|
||||||
|
|
||||||
|
for (auto &input : tx_json.get_child("result.vout")) {
|
||||||
|
btc_txin tx_in;
|
||||||
|
std::string tx_vout_s = input.second.get<std::string>("n");
|
||||||
|
tx_in.tx_vout = std::stoll(tx_vout_s);
|
||||||
|
if (bitcoin_major_version > 21) {
|
||||||
|
std::string address = input.second.get<std::string>("scriptPubKey.address");
|
||||||
|
tx_in.tx_address.emplace_back(address);
|
||||||
|
} else {
|
||||||
|
for (auto &address : input.second.get_child("scriptPubKey.addresses")) {
|
||||||
|
tx_in.tx_address.emplace_back(address.second.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string tx_amount_s = input.second.get<std::string>("value");
|
||||||
|
tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end());
|
||||||
|
tx_in.tx_amount = std::stoll(tx_amount_s);
|
||||||
|
|
||||||
|
tx.tx_in_list.emplace_back(tx_in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string bitcoin_rpc_client::getblockchaininfo() {
|
std::string bitcoin_rpc_client::getblockchaininfo() {
|
||||||
static const std::string params = std::string("[]");
|
static const std::string params = std::string("[]");
|
||||||
const std::string str = send_post_request("getblockchaininfo", params, debug_rpc_calls);
|
const std::string str = send_post_request("getblockchaininfo", params, debug_rpc_calls);
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
|
||||||
if (str.length() > 0) {
|
if (str.length() > 0) {
|
||||||
|
|
||||||
std::stringstream ss(str);
|
std::stringstream ss(str);
|
||||||
boost::property_tree::ptree json;
|
boost::property_tree::ptree json;
|
||||||
boost::property_tree::read_json(ss, json);
|
boost::property_tree::read_json(ss, json);
|
||||||
|
|
||||||
boost::property_tree::json_parser::write_json(ss, json.get_child("result"));
|
if (json.find("result") != json.not_found()) {
|
||||||
return ss.str();
|
auto json_result = json.get_child("result");
|
||||||
|
if (json_result.count("chain")) {
|
||||||
|
result = json_result.get<std::string>("chain");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bitcoin_rpc_client::importmulti(const std::vector<multi_params> &address_or_script_array, const bool rescan) {
|
void bitcoin_rpc_client::importmulti(const std::vector<multi_params> &address_or_script_array, const bool rescan) {
|
||||||
|
|
@ -106,11 +195,11 @@ void bitcoin_rpc_client::importmulti(const std::vector<multi_params> &address_or
|
||||||
|
|
||||||
//! Note
|
//! Note
|
||||||
/* Creation time of the key expressed in UNIX epoch time,
|
/* Creation time of the key expressed in UNIX epoch time,
|
||||||
or the string "now" to substitute the current synced blockchain time. The timestamp of the oldest
|
or the string "now" to substitute the current synced blockchain time. The timestamp of the oldest
|
||||||
key will determine how far back blockchain rescans need to begin for missing wallet transactions.
|
key will determine how far back blockchain rescans need to begin for missing wallet transactions.
|
||||||
"now" can be specified to bypass scanning, for keys which are known to never have been used, and
|
"now" can be specified to bypass scanning, for keys which are known to never have been used, and
|
||||||
0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key
|
0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key
|
||||||
creation time of all keys being imported by the importmulti call will be scanned.*/
|
creation time of all keys being imported by the importmulti call will be scanned.*/
|
||||||
|
|
||||||
if (¶m != &address_or_script_array.back()) {
|
if (¶m != &address_or_script_array.back()) {
|
||||||
argument_1 += ", ";
|
argument_1 += ", ";
|
||||||
|
|
@ -243,15 +332,178 @@ bool bitcoin_rpc_client::walletpassphrase(const std::string &passphrase, uint32_
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
for (const auto &tx : trx_list) {
|
||||||
|
uint32_t vout_seq = 0;
|
||||||
|
for (const auto &o : tx.outputs()) {
|
||||||
|
std::vector<std::string> address_list;
|
||||||
|
|
||||||
|
libbitcoin::wallet::payment_address::list addresses;
|
||||||
|
if (is_test_net) {
|
||||||
|
addresses = o.addresses(libbitcoin::wallet::payment_address::testnet_p2kh,
|
||||||
|
libbitcoin::wallet::payment_address::testnet_p2sh);
|
||||||
|
} else {
|
||||||
|
addresses = o.addresses();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &payment_address : addresses) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << payment_address;
|
||||||
|
address_list.emplace_back(ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// addres list consists usual of one element
|
||||||
|
for (auto &address : address_list) {
|
||||||
|
const auto address_base58 = address;
|
||||||
|
info_for_vin vin;
|
||||||
|
vin.out.hash_tx = libbitcoin::config::hash256(tx.hash()).to_string();
|
||||||
|
vin.out.amount = std::floor(o.value());
|
||||||
|
vin.out.n_vout = vout_seq;
|
||||||
|
vin.address = address_base58;
|
||||||
|
result.push_back(vin);
|
||||||
|
}
|
||||||
|
vout_seq++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
btc_tx bitcoin_libbitcoin_client::getrawtransaction(const std::string &txid, const bool verbose) {
|
||||||
|
btc_tx tx;
|
||||||
|
|
||||||
|
std::string tx_hash;
|
||||||
|
uint32_t confirmitions;
|
||||||
|
|
||||||
|
libbitcoin::chain::output::list outs = get_transaction(txid, tx_hash, confirmitions);
|
||||||
|
|
||||||
|
if (tx_hash.empty()) {
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.tx_txid = tx_hash;
|
||||||
|
tx.tx_confirmations = confirmitions;
|
||||||
|
|
||||||
|
uint64_t tx_vout_sequence = 0;
|
||||||
|
|
||||||
|
for (auto &out : outs) {
|
||||||
|
btc_txin tx_in;
|
||||||
|
tx_in.tx_vout = tx_vout_sequence++;
|
||||||
|
|
||||||
|
libbitcoin::wallet::payment_address::list addresses;
|
||||||
|
if (is_test_net) {
|
||||||
|
addresses = out.addresses(libbitcoin::wallet::payment_address::testnet_p2kh,
|
||||||
|
libbitcoin::wallet::payment_address::testnet_p2sh);
|
||||||
|
} else {
|
||||||
|
addresses = out.addresses();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &address : addresses) {
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << address;
|
||||||
|
tx_in.tx_address.emplace_back(ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
tx_in.tx_amount = std::floor(out.value());
|
||||||
|
tx.tx_in_list.emplace_back(tx_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitcoin_libbitcoin_client::getnetworkinfo() {
|
||||||
|
// This function is only used for bitcoind client in order of getting
|
||||||
|
// version of bitcoin client. Version is used for extracting addresses or address
|
||||||
|
// which is not important for libbitcoin client
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string bitcoin_libbitcoin_client::getblockchaininfo() {
|
||||||
|
if (get_is_test_net()) {
|
||||||
|
is_test_net = true;
|
||||||
|
return "regtest";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<btc_txout> bitcoin_libbitcoin_client::listunspent_by_address_and_amount(const std::string &address, double transfer_amount, const uint32_t minconf, const uint32_t maxconf) {
|
||||||
|
|
||||||
|
std::vector<btc_txout> result;
|
||||||
|
std::vector<list_unspent_replay> outputs = listunspent(address, transfer_amount);
|
||||||
|
for (auto &output : outputs) {
|
||||||
|
btc_txout txo;
|
||||||
|
txo.txid_ = output.hash;
|
||||||
|
txo.out_num_ = output.index;
|
||||||
|
txo.amount_ = output.value;
|
||||||
|
result.push_back(txo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string bitcoin_libbitcoin_client::sendrawtransaction(const std::string &tx_hex) {
|
||||||
|
std::string res = send_transaction(tx_hex);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
zmq_listener::zmq_listener(std::string _ip, uint32_t _zmq) :
|
zmq_listener::zmq_listener(std::string _ip, uint32_t _zmq_block_port, uint32_t _zmq_trx_port) :
|
||||||
ip(_ip),
|
zmq_listener_base(_ip, _zmq_block_port, _zmq_trx_port),
|
||||||
zmq_port(_zmq),
|
|
||||||
ctx(1),
|
ctx(1),
|
||||||
socket(ctx, ZMQ_SUB),
|
socket(ctx, ZMQ_SUB) {
|
||||||
stopped(false) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void zmq_listener::start() {
|
void zmq_listener::start() {
|
||||||
|
|
@ -265,16 +517,16 @@ void zmq_listener::start() {
|
||||||
// socket.setsockopt( ZMQ_SUBSCRIBE, "hashtx", 6 );
|
// socket.setsockopt( ZMQ_SUBSCRIBE, "hashtx", 6 );
|
||||||
// socket.setsockopt( ZMQ_SUBSCRIBE, "rawblock", 8 );
|
// socket.setsockopt( ZMQ_SUBSCRIBE, "rawblock", 8 );
|
||||||
// socket.setsockopt( ZMQ_SUBSCRIBE, "rawtx", 5 );
|
// socket.setsockopt( ZMQ_SUBSCRIBE, "rawtx", 5 );
|
||||||
socket.connect("tcp://" + ip + ":" + std::to_string(zmq_port));
|
socket.connect("tcp://" + ip + ":" + std::to_string(block_zmq_port));
|
||||||
|
|
||||||
thr = std::thread(&zmq_listener::handle_zmq, this);
|
block_thr = std::thread(&zmq_listener::handle_zmq, this);
|
||||||
|
|
||||||
ilog("zmq_listener thread started");
|
ilog("zmq_listener thread started");
|
||||||
}
|
}
|
||||||
|
|
||||||
zmq_listener::~zmq_listener() {
|
zmq_listener::~zmq_listener() {
|
||||||
stopped = true;
|
stopped = true;
|
||||||
thr.join();
|
block_thr.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<zmq::message_t> zmq_listener::receive_multipart() {
|
std::vector<zmq::message_t> zmq_listener::receive_multipart() {
|
||||||
|
|
@ -302,7 +554,9 @@ void zmq_listener::handle_zmq() {
|
||||||
}
|
}
|
||||||
const auto header = std::string(static_cast<char *>(msg[0].data()), msg[0].size());
|
const auto header = std::string(static_cast<char *>(msg[0].data()), msg[0].size());
|
||||||
const auto block_hash = boost::algorithm::hex(std::string(static_cast<char *>(msg[1].data()), msg[1].size()));
|
const auto block_hash = boost::algorithm::hex(std::string(static_cast<char *>(msg[1].data()), msg[1].size()));
|
||||||
event_received(block_hash);
|
block_data event_data;
|
||||||
|
event_data.block_hash = block_hash;
|
||||||
|
block_event_received(event_data);
|
||||||
}
|
}
|
||||||
} catch (zmq::error_t &e) {
|
} catch (zmq::error_t &e) {
|
||||||
elog("handle_zmq recv_multipart exception ${str}", ("str", e.what()));
|
elog("handle_zmq recv_multipart exception ${str}", ("str", e.what()));
|
||||||
|
|
@ -314,6 +568,92 @@ 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() {
|
||||||
|
stopped.store(true);
|
||||||
|
block_thr.join();
|
||||||
|
trx_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");
|
||||||
|
}
|
||||||
|
|
||||||
|
void zmq_listener_libbitcoin::handle_block() {
|
||||||
|
block_poller.add(block_socket);
|
||||||
|
|
||||||
|
while (!stopped.load()) {
|
||||||
|
const auto identifiers = block_poller.wait(500);
|
||||||
|
|
||||||
|
if (identifiers.contains(block_socket.id())) {
|
||||||
|
libbitcoin::protocol::zmq::message message;
|
||||||
|
|
||||||
|
block_socket.receive(message);
|
||||||
|
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
data.clear();
|
||||||
|
message.dequeue(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
libbitcoin::chain::block block;
|
||||||
|
block.from_data(data, true);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ilog("zmq_listener_libbitcoin block thread finished");
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
|
sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
|
||||||
sidechain_net_handler(_plugin, options) {
|
sidechain_net_handler(_plugin, options) {
|
||||||
sidechain = sidechain_type::bitcoin;
|
sidechain = sidechain_type::bitcoin;
|
||||||
|
|
@ -322,8 +662,16 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain
|
||||||
debug_rpc_calls = options.at("debug-rpc-calls").as<bool>();
|
debug_rpc_calls = options.at("debug-rpc-calls").as<bool>();
|
||||||
}
|
}
|
||||||
|
|
||||||
ip = options.at("bitcoin-node-ip").as<std::string>();
|
if (options.count("use-bitcoind-client")) {
|
||||||
zmq_port = options.at("bitcoin-node-zmq-port").as<uint32_t>();
|
use_bitcoind_client = options.at("use-bitcoind-client").as<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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>();
|
||||||
|
|
||||||
|
bitcoin_node_ip = options.at("bitcoin-node-ip").as<std::string>();
|
||||||
|
bitcoin_node_zmq_port = options.at("bitcoin-node-zmq-port").as<uint32_t>();
|
||||||
rpc_port = options.at("bitcoin-node-rpc-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_user = options.at("bitcoin-node-rpc-user").as<std::string>();
|
||||||
rpc_password = options.at("bitcoin-node-rpc-password").as<std::string>();
|
rpc_password = options.at("bitcoin-node-rpc-password").as<std::string>();
|
||||||
|
|
@ -348,55 +696,44 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string url = ip + ":" + std::to_string(rpc_port);
|
if (use_bitcoind_client) {
|
||||||
if (!wallet_name.empty()) {
|
std::string url = bitcoin_node_ip + ":" + std::to_string(rpc_port);
|
||||||
url = url + "/wallet/" + wallet_name;
|
if (!wallet_name.empty()) {
|
||||||
|
url = url + "/wallet/" + wallet_name;
|
||||||
|
}
|
||||||
|
bitcoin_client = std::unique_ptr<bitcoin_rpc_client>(new bitcoin_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls));
|
||||||
|
if (!wallet_name.empty()) {
|
||||||
|
bitcoin_client->loadwallet(wallet_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
bitcoin_client = std::unique_ptr<bitcoin_rpc_client>(new bitcoin_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls));
|
std::string chain_info = bitcoin_client->getblockchaininfo();
|
||||||
if (!wallet_name.empty()) {
|
|
||||||
bitcoin_client->loadwallet(wallet_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string blockchain_info = bitcoin_client->getblockchaininfo();
|
|
||||||
if (blockchain_info.empty()) {
|
|
||||||
elog("No Bitcoin node running at ${url}", ("url", url));
|
|
||||||
FC_ASSERT(false);
|
|
||||||
}
|
|
||||||
std::stringstream bci_ss(std::string(blockchain_info.begin(), blockchain_info.end()));
|
|
||||||
boost::property_tree::ptree bci_json;
|
|
||||||
boost::property_tree::read_json(bci_ss, bci_json);
|
|
||||||
|
|
||||||
using namespace bitcoin;
|
using namespace bitcoin;
|
||||||
network_type = bitcoin_address::network::mainnet;
|
network_type = bitcoin_address::network::mainnet;
|
||||||
|
|
||||||
if (bci_json.count("chain")) {
|
if (chain_info == "test") {
|
||||||
std::string chain = bci_json.get<std::string>("chain");
|
network_type = bitcoin_address::network::testnet;
|
||||||
if (chain.length() > 0) {
|
} else if (chain_info == "regtest") {
|
||||||
if (chain == "test") {
|
network_type = bitcoin_address::network::regtest;
|
||||||
network_type = bitcoin_address::network::testnet;
|
|
||||||
} else if (chain == "regtest") {
|
|
||||||
network_type = bitcoin_address::network::regtest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string network_info_str = bitcoin_client->getnetworkinfo();
|
bitcoin_client->getnetworkinfo();
|
||||||
if (network_info_str.empty()) {
|
|
||||||
elog("No Bitcoin node running at ${url}", ("url", url));
|
|
||||||
FC_ASSERT(false);
|
|
||||||
}
|
|
||||||
std::stringstream network_info_ss(network_info_str);
|
|
||||||
boost::property_tree::ptree network_info_json;
|
|
||||||
boost::property_tree::read_json(network_info_ss, network_info_json);
|
|
||||||
|
|
||||||
bitcoin_major_version = network_info_json.get<uint32_t>("result.version") / 10000;
|
|
||||||
ilog("Bitcoin major version is: '${version}'", ("version", bitcoin_major_version));
|
|
||||||
|
|
||||||
listener = std::unique_ptr<zmq_listener>(new zmq_listener(ip, zmq_port));
|
|
||||||
listener->start();
|
listener->start();
|
||||||
listener->event_received.connect([this](const std::string &event_data) {
|
listener->block_event_received.connect([this](const block_data &block_event_data) {
|
||||||
std::thread(&sidechain_net_handler_bitcoin::handle_event, this, event_data).detach();
|
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();
|
||||||
});
|
});
|
||||||
|
|
||||||
database.changed_objects.connect([this](const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts) {
|
database.changed_objects.connect([this](const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts) {
|
||||||
|
|
@ -418,7 +755,7 @@ sidechain_net_handler_bitcoin::~sidechain_net_handler_bitcoin() {
|
||||||
|
|
||||||
bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) {
|
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;
|
bool should_approve = false;
|
||||||
|
|
||||||
|
|
@ -450,7 +787,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
|
||||||
son_wallet_id_type swo_id = op_obj_idx_0.get<son_wallet_update_operation>().son_wallet_id;
|
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 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 auto id = (swo_id.instance.value - std::distance(ast.begin(), ast.find(sidechain))) / ast.size();
|
||||||
const son_wallet_id_type op_id{ id };
|
const son_wallet_id_type op_id{id};
|
||||||
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_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(op_id);
|
||||||
if (swo != idx.end()) {
|
if (swo != idx.end()) {
|
||||||
|
|
@ -491,7 +828,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
|
||||||
const object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
|
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 ast = active_sidechain_types(database.head_block_time());
|
||||||
const auto id = (object_id.instance() - std::distance(ast.begin(), ast.find(sidechain))) / ast.size();
|
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 object_id_type obj_id{object_id.space(), object_id.type(), id};
|
||||||
std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
|
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_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
|
||||||
|
|
@ -533,50 +870,35 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
|
||||||
uint64_t swdo_amount = swdo->sidechain_amount.value;
|
uint64_t swdo_amount = swdo->sidechain_amount.value;
|
||||||
uint64_t swdo_vout = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-") + 1));
|
uint64_t swdo_vout = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-") + 1));
|
||||||
|
|
||||||
const std::string tx_str = bitcoin_client->getrawtransaction(swdo_txid, true);
|
btc_tx tx = bitcoin_client->getrawtransaction(swdo_txid, true);
|
||||||
if (tx_str != "") {
|
|
||||||
std::stringstream tx_ss(tx_str);
|
|
||||||
boost::property_tree::ptree tx_json;
|
|
||||||
boost::property_tree::read_json(tx_ss, tx_json);
|
|
||||||
|
|
||||||
if (tx_json.count("error") && tx_json.get_child("error").empty()) {
|
if (!tx.tx_in_list.empty()) {
|
||||||
|
|
||||||
std::string tx_txid = tx_json.get<std::string>("result.txid");
|
std::string tx_txid = tx.tx_txid;
|
||||||
uint32_t tx_confirmations = tx_json.get<uint32_t>("result.confirmations");
|
uint32_t tx_confirmations = tx.tx_confirmations;
|
||||||
std::string tx_address = "";
|
std::string tx_address = "";
|
||||||
uint64_t tx_amount = -1;
|
uint64_t tx_amount = -1;
|
||||||
uint64_t tx_vout = -1;
|
uint64_t tx_vout = -1;
|
||||||
|
|
||||||
for (auto &input : tx_json.get_child("result.vout")) {
|
for (auto &input : tx.tx_in_list) {
|
||||||
std::string tx_vout_s = input.second.get<std::string>("n");
|
tx_vout = input.tx_vout;
|
||||||
tx_vout = std::stoll(tx_vout_s);
|
if (tx_vout == swdo_vout) {
|
||||||
if (tx_vout == swdo_vout) {
|
for (auto &address : input.tx_address) {
|
||||||
if (bitcoin_major_version > 21) {
|
if (address == swdo_address) {
|
||||||
std::string address = input.second.get<std::string>("scriptPubKey.address");
|
tx_address = address;
|
||||||
if (address == swdo_address) {
|
break;
|
||||||
tx_address = address;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (auto &address : input.second.get_child("scriptPubKey.addresses")) {
|
|
||||||
if (address.second.data() == swdo_address) {
|
|
||||||
tx_address = address.second.data();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
std::string tx_amount_s = input.second.get<std::string>("value");
|
|
||||||
tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end());
|
|
||||||
tx_amount = std::stoll(tx_amount_s);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
tx_amount = input.tx_amount;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
process_ok = (swdo_txid == tx_txid) &&
|
|
||||||
(swdo_address == tx_address) &&
|
|
||||||
(swdo_amount == tx_amount) &&
|
|
||||||
(swdo_vout == tx_vout) &&
|
|
||||||
(gpo.parameters.son_bitcoin_min_tx_confirmations() <= tx_confirmations);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process_ok = (swdo_txid == tx_txid) &&
|
||||||
|
(swdo_address == tx_address) &&
|
||||||
|
(swdo_amount == tx_amount) &&
|
||||||
|
(swdo_vout == tx_vout) &&
|
||||||
|
(gpo.parameters.son_bitcoin_min_tx_confirmations() <= tx_confirmations);
|
||||||
}
|
}
|
||||||
|
|
||||||
object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
|
object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
|
||||||
|
|
@ -724,7 +1046,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() {
|
||||||
|
|
||||||
const auto ast = active_sidechain_types(database.head_block_time());
|
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 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 };
|
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)) {
|
if (proposal_exists(chain::operation::tag<chain::son_wallet_update_operation>::value, op_id)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -765,7 +1087,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() {
|
||||||
if (!tx_str.empty()) {
|
if (!tx_str.empty()) {
|
||||||
const auto ast = active_sidechain_types(database.head_block_time());
|
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 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 };
|
const object_id_type prev_op_id{prev_sw->id.space(), prev_sw->id.type(), prev_id};
|
||||||
|
|
||||||
sidechain_transaction_create_operation stc_op;
|
sidechain_transaction_create_operation stc_op;
|
||||||
stc_op.payer = gpo.parameters.son_account();
|
stc_op.payer = gpo.parameters.son_account();
|
||||||
|
|
@ -820,7 +1142,12 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() {
|
||||||
if (sao.expires == time_point_sec::maximum()) {
|
if (sao.expires == time_point_sec::maximum()) {
|
||||||
auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key)));
|
auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key)));
|
||||||
|
|
||||||
btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type);
|
payment_type payment_type_address = payment_type::P2SH_WSH;
|
||||||
|
if (use_bitcoind_client) {
|
||||||
|
payment_type_address = payment_type::P2WSH;
|
||||||
|
}
|
||||||
|
|
||||||
|
btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type, payment_type_address);
|
||||||
std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) +
|
std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) +
|
||||||
"\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }";
|
"\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }";
|
||||||
|
|
||||||
|
|
@ -977,61 +1304,53 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string tx_str = bitcoin_client->getrawtransaction(sto.sidechain_transaction, true);
|
btc_tx tx = bitcoin_client->getrawtransaction(sto.sidechain_transaction, true);
|
||||||
if (tx_str != "") {
|
|
||||||
std::stringstream tx_ss(tx_str);
|
|
||||||
boost::property_tree::ptree tx_json;
|
|
||||||
boost::property_tree::read_json(tx_ss, tx_json);
|
|
||||||
|
|
||||||
if ((tx_json.count("error")) && (!tx_json.get_child("error").empty())) {
|
if (tx.tx_in_list.empty()) {
|
||||||
return false;
|
// This case will result with segmentation fault.
|
||||||
}
|
// FIXME check if that happened before introducing libbitcoin
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const chain::global_property_object &gpo = database.get_global_properties();
|
const chain::global_property_object &gpo = database.get_global_properties();
|
||||||
|
|
||||||
using namespace bitcoin;
|
using namespace bitcoin;
|
||||||
std::vector<std::pair<fc::ecc::public_key, uint16_t>> pubkey_weights;
|
std::vector<std::pair<fc::ecc::public_key, uint16_t>> pubkey_weights;
|
||||||
for (auto si : sto.signers) {
|
for (auto si : sto.signers) {
|
||||||
auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(si.public_key)));
|
auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(si.public_key)));
|
||||||
pubkey_weights.push_back(std::make_pair(pub_key, si.weight));
|
pubkey_weights.push_back(std::make_pair(pub_key, si.weight));
|
||||||
}
|
}
|
||||||
btc_weighted_multisig_address addr(pubkey_weights, network_type);
|
|
||||||
|
|
||||||
std::string tx_txid = tx_json.get<std::string>("result.txid");
|
payment_type payment_type_address = payment_type::P2SH_WSH;
|
||||||
uint32_t tx_confirmations = tx_json.get<uint32_t>("result.confirmations");
|
if (use_bitcoind_client) {
|
||||||
std::string tx_address = addr.get_address();
|
payment_type_address = payment_type::P2WSH;
|
||||||
int64_t tx_amount = -1;
|
}
|
||||||
|
|
||||||
if (tx_confirmations >= gpo.parameters.son_bitcoin_min_tx_confirmations()) {
|
btc_weighted_multisig_address addr(pubkey_weights, network_type, payment_type_address);
|
||||||
if (sto.object_id.is<son_wallet_deposit_id_type>()) {
|
|
||||||
for (auto &input : tx_json.get_child("result.vout")) {
|
std::string tx_txid = tx.tx_txid;
|
||||||
if (bitcoin_major_version > 21) {
|
uint32_t tx_confirmations = tx.tx_confirmations;
|
||||||
std::string address = input.second.get<std::string>("scriptPubKey.address");
|
std::string tx_address = addr.get_address();
|
||||||
if (address == tx_address) {
|
int64_t tx_amount = -1;
|
||||||
std::string tx_amount_s = input.second.get<std::string>("value");
|
|
||||||
tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end());
|
if (tx_confirmations >= gpo.parameters.son_bitcoin_min_tx_confirmations()) {
|
||||||
tx_amount = std::stoll(tx_amount_s);
|
if (sto.object_id.is<son_wallet_deposit_id_type>()) {
|
||||||
}
|
for (auto &input : tx.tx_in_list) {
|
||||||
} else {
|
for (auto &address : input.tx_address) {
|
||||||
for (auto &address : input.second.get_child("scriptPubKey.addresses")) {
|
if (address == tx_address) {
|
||||||
if (address.second.data() == tx_address) {
|
tx_amount = input.tx_amount;
|
||||||
std::string tx_amount_s = input.second.get<std::string>("value");
|
break;
|
||||||
tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end());
|
|
||||||
tx_amount = std::stoll(tx_amount_s);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
settle_amount = asset(tx_amount, database.get_global_properties().parameters.btc_asset());
|
settle_amount = asset(tx_amount, database.get_global_properties().parameters.btc_asset());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sto.object_id.is<son_wallet_withdraw_id_type>()) {
|
if (sto.object_id.is<son_wallet_withdraw_id_type>()) {
|
||||||
auto swwo = database.get<son_wallet_withdraw_object>(sto.object_id);
|
auto swwo = database.get<son_wallet_withdraw_object>(sto.object_id);
|
||||||
settle_amount = asset(swwo.withdraw_amount, database.get_global_properties().parameters.btc_asset());
|
settle_amount = asset(swwo.withdraw_amount, database.get_global_properties().parameters.btc_asset());
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1051,7 +1370,11 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const s
|
||||||
pubkey_weights.push_back(std::make_pair(pub_key, son.weight));
|
pubkey_weights.push_back(std::make_pair(pub_key, son.weight));
|
||||||
}
|
}
|
||||||
|
|
||||||
btc_weighted_multisig_address addr(pubkey_weights, network_type);
|
payment_type payment_type_address = payment_type::P2SH_WSH;
|
||||||
|
if (use_bitcoind_client) {
|
||||||
|
payment_type_address = payment_type::P2WSH;
|
||||||
|
}
|
||||||
|
btc_weighted_multisig_address addr(pubkey_weights, network_type, payment_type_address);
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
|
@ -1287,18 +1610,34 @@ std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_tran
|
||||||
}
|
}
|
||||||
// Add redeemscripts to vins and make tx ready for sending
|
// Add redeemscripts to vins and make tx ready for sending
|
||||||
sign_witness_transaction_finalize(tx, redeem_scripts, false);
|
sign_witness_transaction_finalize(tx, redeem_scripts, false);
|
||||||
|
|
||||||
|
if (!use_bitcoind_client) {
|
||||||
|
// get witness script from redeem script
|
||||||
|
bitcoin::bytes redeem_bytes = parse_hex(redeem_script);
|
||||||
|
fc::sha256 sha = fc::sha256::hash(&redeem_bytes[0], redeem_bytes.size());
|
||||||
|
std::string witness_script(sha.str());
|
||||||
|
witness_script.insert(0, std::string("220020"));
|
||||||
|
for (size_t i = 0; i < tx.vin.size(); i++) {
|
||||||
|
tx.vin[i].scriptSig = parse_hex(witness_script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string final_tx_hex = fc::to_hex(pack(tx));
|
std::string final_tx_hex = fc::to_hex(pack(tx));
|
||||||
return bitcoin_client->sendrawtransaction(final_tx_hex);
|
std::string res = bitcoin_client->sendrawtransaction(final_tx_hex);
|
||||||
|
|
||||||
|
if (res.empty()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx.get_txid().str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) {
|
void sidechain_net_handler_bitcoin::block_handle_event(const block_data &event_data) {
|
||||||
const std::string block = bitcoin_client->getblock(event_data);
|
|
||||||
if (block.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
add_to_son_listener_log("BLOCK : " + event_data);
|
auto vins = bitcoin_client->getblock(event_data);
|
||||||
|
|
||||||
|
add_to_son_listener_log("BLOCK : " + event_data.block_hash);
|
||||||
|
|
||||||
auto vins = extract_info_from_block(block);
|
|
||||||
scoped_lock interlock(event_handler_mutex);
|
scoped_lock interlock(event_handler_mutex);
|
||||||
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();
|
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();
|
||||||
|
|
||||||
|
|
@ -1335,6 +1674,10 @@ void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
std::string sidechain_net_handler_bitcoin::get_redeemscript_for_userdeposit(const std::string &user_address) {
|
||||||
using namespace bitcoin;
|
using namespace bitcoin;
|
||||||
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();
|
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();
|
||||||
|
|
@ -1355,56 +1698,14 @@ std::string sidechain_net_handler_bitcoin::get_redeemscript_for_userdeposit(cons
|
||||||
pubkey_weights.push_back(std::make_pair(pub_key, son.weight));
|
pubkey_weights.push_back(std::make_pair(pub_key, son.weight));
|
||||||
}
|
}
|
||||||
auto user_pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(addr_itr->deposit_public_key)));
|
auto user_pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(addr_itr->deposit_public_key)));
|
||||||
btc_one_or_weighted_multisig_address deposit_addr(user_pub_key, pubkey_weights, network_type);
|
|
||||||
return fc::to_hex(deposit_addr.get_redeem_script());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<info_for_vin> sidechain_net_handler_bitcoin::extract_info_from_block(const std::string &_block) {
|
payment_type payment_type_address = payment_type::P2SH_WSH;
|
||||||
std::stringstream ss(_block);
|
if (use_bitcoind_client) {
|
||||||
boost::property_tree::ptree json;
|
payment_type_address = payment_type::P2WSH;
|
||||||
boost::property_tree::read_json(ss, json);
|
|
||||||
|
|
||||||
auto json_result = json.get_child_optional("result");
|
|
||||||
|
|
||||||
std::vector<info_for_vin> result;
|
|
||||||
|
|
||||||
for (const auto &tx_child : json_result.get().get_child("tx")) {
|
|
||||||
const auto &tx = tx_child.second;
|
|
||||||
|
|
||||||
for (const auto &o : tx.get_child("vout")) {
|
|
||||||
const auto script = o.second.get_child("scriptPubKey");
|
|
||||||
|
|
||||||
if (bitcoin_major_version > 21) {
|
|
||||||
if (!script.count("address"))
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
if (!script.count("addresses"))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sort_out_vin = [&](std::string address) {
|
|
||||||
const auto address_base58 = address;
|
|
||||||
info_for_vin vin;
|
|
||||||
vin.out.hash_tx = tx.get_child("txid").get_value<std::string>();
|
|
||||||
string amount = o.second.get_child("value").get_value<std::string>();
|
|
||||||
amount.erase(std::remove(amount.begin(), amount.end(), '.'), amount.end());
|
|
||||||
vin.out.amount = std::stoll(amount);
|
|
||||||
vin.out.n_vout = o.second.get_child("n").get_value<uint32_t>();
|
|
||||||
vin.address = address_base58;
|
|
||||||
result.push_back(vin);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (bitcoin_major_version > 21) {
|
|
||||||
std::string address = script.get<std::string>("address");
|
|
||||||
sort_out_vin(address);
|
|
||||||
} else {
|
|
||||||
for (const auto &addr : script.get_child("addresses")) // in which cases there can be more addresses?
|
|
||||||
sort_out_vin(addr.second.get_value<std::string>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
btc_one_or_weighted_multisig_address deposit_addr(user_pub_key, pubkey_weights, network_type, payment_type_address);
|
||||||
|
|
||||||
return result;
|
return fc::to_hex(deposit_addr.get_redeem_script());
|
||||||
}
|
}
|
||||||
|
|
||||||
void sidechain_net_handler_bitcoin::on_changed_objects(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts) {
|
void sidechain_net_handler_bitcoin::on_changed_objects(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts) {
|
||||||
|
|
|
||||||
|
|
@ -148,8 +148,8 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha
|
||||||
|
|
||||||
wallet_contract_address = options.at("ethereum-wallet-contract-address").as<std::string>();
|
wallet_contract_address = options.at("ethereum-wallet-contract-address").as<std::string>();
|
||||||
|
|
||||||
if (options.count("erc-20-address")) {
|
if (options.count("ethereum-erc-20-address")) {
|
||||||
const std::vector<std::string> symbol_addresses = options["erc-20-address"].as<std::vector<std::string>>();
|
const std::vector<std::string> symbol_addresses = options["ethereum-erc-20-address"].as<std::vector<std::string>>();
|
||||||
for (const std::string &itr : symbol_addresses) {
|
for (const std::string &itr : symbol_addresses) {
|
||||||
auto itr_pair = graphene::app::dejsonify<std::pair<std::string, std::string>>(itr, 5);
|
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));
|
ilog("ERC-20 symbol: ${symbol}, address: ${address}", ("symbol", itr_pair.first)("address", itr_pair.second));
|
||||||
|
|
@ -236,7 +236,7 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po)
|
||||||
const son_wallet_id_type swo_id = op_obj_idx_0.get<son_wallet_update_operation>().son_wallet_id;
|
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 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 auto id = (swo_id.instance.value - std::distance(ast.begin(), ast.find(sidechain))) / ast.size();
|
||||||
const son_wallet_id_type op_id{ id };
|
const son_wallet_id_type op_id{id};
|
||||||
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_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(op_id);
|
||||||
if (swo != idx.end()) {
|
if (swo != idx.end()) {
|
||||||
|
|
@ -259,7 +259,7 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po)
|
||||||
if (po.proposed_transaction.operations.size() >= 2) {
|
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 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 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 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 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_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
|
||||||
|
|
@ -459,7 +459,7 @@ void sidechain_net_handler_ethereum::process_primary_wallet() {
|
||||||
|
|
||||||
const auto ast = active_sidechain_types(database.head_block_time());
|
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 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 };
|
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)) {
|
if (proposal_exists(chain::operation::tag<chain::son_wallet_update_operation>::value, op_id)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) {
|
||||||
son_wallet_id_type swo_id = op_obj_idx_0.get<son_wallet_update_operation>().son_wallet_id;
|
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 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 auto id = (swo_id.instance.value - std::distance(ast.begin(), ast.find(sidechain))) / ast.size();
|
||||||
const son_wallet_id_type op_id{ id };
|
const son_wallet_id_type op_id{id};
|
||||||
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_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(op_id);
|
||||||
if (swo != idx.end()) {
|
if (swo != idx.end()) {
|
||||||
|
|
@ -234,7 +234,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) {
|
||||||
if (po.proposed_transaction.operations.size() >= 2) {
|
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 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 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 object_id_type obj_id{object_id.space(), object_id.type(), id};
|
||||||
std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
|
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_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
|
||||||
|
|
@ -493,7 +493,7 @@ void sidechain_net_handler_hive::process_primary_wallet() {
|
||||||
|
|
||||||
const auto ast = active_sidechain_types(database.head_block_time());
|
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 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 };
|
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)) {
|
if (proposal_exists(chain::operation::tag<chain::son_wallet_update_operation>::value, op_id)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue