Compare commits
199 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3d967a2d7 | ||
|
|
178756bd34 | ||
|
|
1f70857d64 | ||
|
|
97e85a849d | ||
|
|
dc4cdd6e4b | ||
|
|
1472066af6 | ||
|
|
a641b8e93f | ||
|
|
aa099f960f | ||
|
|
f0654e5ffd | ||
|
|
9fe351300b | ||
|
|
5fd79c3e78 | ||
|
|
b56818b8ae | ||
|
|
bc0fbeb707 | ||
|
|
accd334a86 | ||
|
|
84a66c6722 | ||
|
|
abd446d80b | ||
|
|
93fb57c080 | ||
|
|
a8845ffde9 | ||
|
|
435c1f8e96 | ||
|
|
1123ff6f93 | ||
|
|
c34415b403 | ||
|
|
daca2813ef | ||
|
|
0b37a48b02 | ||
|
|
e3b10cf1ec | ||
|
|
f5c6a6310b | ||
|
|
75ee6fbed3 | ||
|
|
7516126d01 | ||
|
|
f32a51d03b | ||
|
|
c421453621 | ||
|
|
54ff842db1 | ||
|
|
16ba10ffab | ||
|
|
79974280c0 | ||
|
|
5867a8ae27 | ||
|
|
741534c47f | ||
|
|
f3227fb33d | ||
|
|
bfb961c7be | ||
|
|
5e08b793c5 | ||
|
|
7af3d037b5 | ||
|
|
2788281062 | ||
|
|
4e2850f826 | ||
|
|
f477af6771 | ||
|
|
80d168e5b6 | ||
|
|
e44ed0cfe5 | ||
|
|
142cf5b903 | ||
|
|
ebc1529c48 | ||
|
|
19e0911d64 | ||
|
|
70cd09495e | ||
|
|
e9c7021e16 | ||
|
|
9c9aaa03d3 | ||
|
|
038fa37cc6 | ||
|
|
73b2ba635b | ||
|
|
936f13d2a1 | ||
|
|
fc1cdf2629 | ||
|
|
71f0806b25 | ||
|
|
da3a858aa6 | ||
|
|
1883f97be2 | ||
|
|
559769db2b | ||
|
|
0b64f0cfcc | ||
|
|
96d737fbc2 | ||
|
|
d89e5e1f23 | ||
|
|
6f472d3d3b | ||
|
|
cb60cbe5d1 | ||
|
|
576c54a260 | ||
|
|
2f5e12b28e | ||
|
|
68fbd6f40b | ||
|
|
674b38910d | ||
|
|
d264398a6f | ||
|
|
c1d5691ce2 | ||
|
|
ca69a692cc | ||
|
|
bd041bc13f | ||
|
|
6037e89df0 | ||
|
|
bb7c534b10 | ||
|
|
1be6636bbf | ||
|
|
578edc56d8 | ||
|
|
d387e324fe | ||
|
|
1bf5c82101 | ||
|
|
4883dfe38d | ||
|
|
249276b009 | ||
|
|
ab1e08a756 | ||
|
|
440e4fbb43 | ||
|
|
42b3890a7c | ||
|
|
5dff0830fb | ||
|
|
c3eab0a80b | ||
|
|
12c0c66f4b | ||
|
|
b7113c4ff3 | ||
|
|
d76b752c8c | ||
|
|
804376b149 | ||
|
|
1b340345f3 | ||
|
|
022fdeb40a | ||
|
|
f6d22466fd | ||
|
|
811d68ef4d | ||
|
|
a6da2a6413 | ||
|
|
8853a76752 | ||
|
|
f209ab8ee6 | ||
|
|
9620e3c211 | ||
|
|
3ebcd29e10 | ||
|
|
d5b2b7aeda | ||
|
|
759dac5d41 | ||
|
|
a30325660d | ||
|
|
d5d6390030 | ||
|
|
400c3cfb89 | ||
|
|
aa90f715fd | ||
|
|
c3b2a598b4 | ||
|
|
06bc65cc79 | ||
|
|
8e8142235a | ||
|
|
194fa6abfa | ||
|
|
283fbd28f7 | ||
|
|
71c113c190 | ||
|
|
846366139f | ||
|
|
0856e898bb | ||
|
|
4db9f3a15b | ||
|
|
1b1df25023 | ||
|
|
f9314a4c0c | ||
|
|
d4c015d400 | ||
|
|
e6474f5f2a | ||
|
|
f2f4b57ced | ||
|
|
2c95ac0b9d | ||
|
|
9831579bfe | ||
|
|
2d6dec5943 | ||
|
|
46f4770071 | ||
|
|
2accee53e2 | ||
|
|
54a11e7662 | ||
|
|
c1f93f58ee | ||
|
|
2fd6f60112 | ||
|
|
5f97eb7662 | ||
|
|
b4e8b76a30 | ||
|
|
a9267544de | ||
|
|
e287d8a845 | ||
|
|
0f64947f4a | ||
|
|
b895b52b7b | ||
|
|
9c5aab826d | ||
|
|
6a38fb2382 | ||
|
|
0a9a324277 | ||
|
|
5c416e3a5b | ||
|
|
9268c31ac4 | ||
|
|
c4f6f522a4 | ||
|
|
f127495c0e | ||
|
|
9b2c60f76c | ||
|
|
22fc780a91 | ||
|
|
005478e3ef | ||
|
|
5bfd685684 | ||
|
|
662139ca22 | ||
|
|
6844b74e29 | ||
|
|
99ed37e834 | ||
|
|
629a6672fd | ||
|
|
3b5e928094 | ||
|
|
09579fbab1 | ||
|
|
ff462234af | ||
|
|
873dfd788b | ||
|
|
b186a2f0ed | ||
|
|
1a196bfcc2 | ||
|
|
bc7b0e7788 | ||
|
|
a7f5e1f603 | ||
|
|
eb2894c3d3 | ||
|
|
11834c7f53 | ||
|
|
1ae9470dab | ||
|
|
e575334e30 | ||
|
|
8ce0db6ec3 | ||
|
|
02d898d4dc | ||
|
|
9dd0747e5d | ||
|
|
29189b3897 | ||
|
|
2a373a70f7 | ||
|
|
b05c36b4fe | ||
|
|
e2d9741af8 | ||
|
|
1846b1709e | ||
|
|
2c02591e24 | ||
|
|
aa2dea6ddf | ||
|
|
9af213190a | ||
|
|
0b04faec83 | ||
|
|
a7b4d1cef5 | ||
|
|
0fd22a9945 | ||
|
|
3980512543 | ||
|
|
fc324559eb | ||
|
|
f16aa73b3e | ||
|
|
ca5dc441a7 | ||
|
|
2e55b1818a | ||
|
|
a2702cd1f4 | ||
|
|
564af2e19e | ||
|
|
5b4a4d18d8 | ||
|
|
8562a4c655 | ||
|
|
852565dcb1 | ||
|
|
ffbe0cd592 | ||
|
|
27c77ba74b | ||
|
|
cb3302160b | ||
|
|
c79c8987dc | ||
|
|
223d2a528d | ||
|
|
62f8983c5e | ||
|
|
c973131ed2 | ||
|
|
0c01935ff4 | ||
|
|
520505b667 | ||
|
|
000aeaa721 | ||
|
|
c1048e1509 | ||
|
|
3664ee67ca | ||
|
|
bd6f265409 | ||
|
|
0f0cf62b20 | ||
|
|
13c782ccd6 | ||
|
|
659a3c9185 | ||
|
|
b0c7a527fa | ||
|
|
157e6c2fd8 |
147 changed files with 11214 additions and 6953 deletions
|
|
@ -9,6 +9,8 @@ stages:
|
||||||
- build
|
- build
|
||||||
- test
|
- test
|
||||||
- dockerize
|
- dockerize
|
||||||
|
- python-test
|
||||||
|
- deploy
|
||||||
|
|
||||||
build-mainnet:
|
build-mainnet:
|
||||||
stage: build
|
stage: build
|
||||||
|
|
@ -44,12 +46,11 @@ test-mainnet:
|
||||||
|
|
||||||
dockerize-mainnet:
|
dockerize-mainnet:
|
||||||
stage: dockerize
|
stage: dockerize
|
||||||
dependencies:
|
|
||||||
- test-mainnet
|
|
||||||
variables:
|
variables:
|
||||||
IMAGE: $CI_REGISTRY_IMAGE/mainnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
|
IMAGE: $CI_REGISTRY_IMAGE/mainnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
|
||||||
before_script:
|
before_script:
|
||||||
- docker info
|
- docker info
|
||||||
|
- docker builder prune -a -f
|
||||||
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
||||||
script:
|
script:
|
||||||
- docker build --no-cache -t $IMAGE .
|
- docker build --no-cache -t $IMAGE .
|
||||||
|
|
@ -58,8 +59,6 @@ dockerize-mainnet:
|
||||||
- docker rmi $IMAGE
|
- docker rmi $IMAGE
|
||||||
tags:
|
tags:
|
||||||
- builder
|
- builder
|
||||||
when:
|
|
||||||
manual
|
|
||||||
timeout:
|
timeout:
|
||||||
3h
|
3h
|
||||||
|
|
||||||
|
|
@ -80,12 +79,27 @@ build-testnet:
|
||||||
- build/libraries/
|
- build/libraries/
|
||||||
- build/programs/
|
- build/programs/
|
||||||
- build/tests/
|
- build/tests/
|
||||||
|
when: manual
|
||||||
tags:
|
tags:
|
||||||
- builder
|
- builder
|
||||||
when:
|
|
||||||
manual
|
deploy-testnet:
|
||||||
timeout:
|
stage: deploy
|
||||||
3h
|
dependencies:
|
||||||
|
- build-testnet
|
||||||
|
script:
|
||||||
|
- sudo systemctl stop witness
|
||||||
|
- rm $WORK_DIR/peerplays/witness_node || true
|
||||||
|
- cp build/programs/witness_node/witness_node $WORK_DIR/peerplays/
|
||||||
|
- sudo systemctl restart witness
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH == "master"
|
||||||
|
when: always
|
||||||
|
environment:
|
||||||
|
name: devnet
|
||||||
|
url: $DEVNET_URL
|
||||||
|
tags:
|
||||||
|
- devnet
|
||||||
|
|
||||||
test-testnet:
|
test-testnet:
|
||||||
stage: test
|
stage: test
|
||||||
|
|
@ -105,8 +119,6 @@ test-testnet:
|
||||||
|
|
||||||
dockerize-testnet:
|
dockerize-testnet:
|
||||||
stage: dockerize
|
stage: dockerize
|
||||||
dependencies:
|
|
||||||
- test-testnet
|
|
||||||
variables:
|
variables:
|
||||||
IMAGE: $CI_REGISTRY_IMAGE/testnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
|
IMAGE: $CI_REGISTRY_IMAGE/testnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
|
||||||
before_script:
|
before_script:
|
||||||
|
|
@ -123,3 +135,37 @@ dockerize-testnet:
|
||||||
manual
|
manual
|
||||||
timeout:
|
timeout:
|
||||||
3h
|
3h
|
||||||
|
|
||||||
|
test-e2e:
|
||||||
|
stage: python-test
|
||||||
|
variables:
|
||||||
|
IMAGE: $CI_REGISTRY_IMAGE/mainnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
|
||||||
|
before_script:
|
||||||
|
- docker info
|
||||||
|
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
||||||
|
script:
|
||||||
|
- git clone https://gitlab.com/PBSA/tools-libs/peerplays-utils.git
|
||||||
|
- cd peerplays-utils/peerplays-qa-environment
|
||||||
|
- git checkout origin/feature/python-e2e-tests-for-CI
|
||||||
|
- cd e2e-tests/
|
||||||
|
- python3 -m venv venv
|
||||||
|
- source venv/bin/activate
|
||||||
|
- pip3 install -r requirements.txt
|
||||||
|
- docker-compose down --remove-orphans
|
||||||
|
- docker ps -a
|
||||||
|
- docker pull $IMAGE
|
||||||
|
- docker tag $IMAGE peerplays-base:latest
|
||||||
|
- docker image ls -a
|
||||||
|
- docker-compose build
|
||||||
|
- python3 main.py --start all
|
||||||
|
- docker ps -a
|
||||||
|
- python3 -m pytest test_btc_init_state.py test_hive_inital_state.py test_pp_inital_state.py
|
||||||
|
- python3 main.py --stop
|
||||||
|
- deactivate
|
||||||
|
- docker ps -a
|
||||||
|
after_script:
|
||||||
|
- docker rmi $(docker images -a | grep -v 'hive-for-peerplays\|ethereum-for-peerplays\|bitcoin-for-peerplays\|ubuntu-for-peerplays' | awk '{print $3}')
|
||||||
|
tags:
|
||||||
|
- python-tests
|
||||||
|
when:
|
||||||
|
manual
|
||||||
|
|
|
||||||
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -5,5 +5,5 @@
|
||||||
[submodule "libraries/fc"]
|
[submodule "libraries/fc"]
|
||||||
path = libraries/fc
|
path = libraries/fc
|
||||||
url = https://gitlab.com/PBSA/tools-libs/peerplays-fc.git
|
url = https://gitlab.com/PBSA/tools-libs/peerplays-fc.git
|
||||||
branch = latest-fc
|
branch = develop
|
||||||
ignore = dirty
|
ignore = dirty
|
||||||
|
|
|
||||||
126
Dockerfile
126
Dockerfile
|
|
@ -1,5 +1,4 @@
|
||||||
FROM ubuntu:20.04
|
FROM ubuntu:20.04
|
||||||
MAINTAINER Peerplays Blockchain Standards Association
|
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# Ubuntu setup
|
# Ubuntu setup
|
||||||
|
|
@ -11,15 +10,14 @@ RUN \
|
||||||
apt-utils \
|
apt-utils \
|
||||||
autoconf \
|
autoconf \
|
||||||
bash \
|
bash \
|
||||||
|
bison \
|
||||||
build-essential \
|
build-essential \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
cmake \
|
|
||||||
dnsutils \
|
dnsutils \
|
||||||
doxygen \
|
|
||||||
expect \
|
expect \
|
||||||
|
flex \
|
||||||
git \
|
git \
|
||||||
graphviz \
|
graphviz \
|
||||||
libboost1.67-all-dev \
|
|
||||||
libbz2-dev \
|
libbz2-dev \
|
||||||
libcurl4-openssl-dev \
|
libcurl4-openssl-dev \
|
||||||
libncurses-dev \
|
libncurses-dev \
|
||||||
|
|
@ -35,7 +33,6 @@ RUN \
|
||||||
ntp \
|
ntp \
|
||||||
openssh-server \
|
openssh-server \
|
||||||
pkg-config \
|
pkg-config \
|
||||||
perl \
|
|
||||||
python3 \
|
python3 \
|
||||||
python3-jinja2 \
|
python3-jinja2 \
|
||||||
sudo \
|
sudo \
|
||||||
|
|
@ -53,16 +50,105 @@ RUN echo 'peerplays:peerplays' | chpasswd
|
||||||
# SSH
|
# SSH
|
||||||
EXPOSE 22
|
EXPOSE 22
|
||||||
|
|
||||||
|
WORKDIR /home/peerplays/src
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Boost setup
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \
|
||||||
|
tar -xzf boost_1_72_0.tar.gz && \
|
||||||
|
cd boost_1_72_0 && \
|
||||||
|
./bootstrap.sh && \
|
||||||
|
./b2 install && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# cmake setup
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
wget https://github.com/Kitware/CMake/releases/download/v3.24.2/cmake-3.24.2-linux-x86_64.sh && \
|
||||||
|
chmod 755 ./cmake-3.24.2-linux-x86_64.sh && \
|
||||||
|
./cmake-3.24.2-linux-x86_64.sh --prefix=/usr --skip-license && \
|
||||||
|
cmake --version && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# libzmq setup
|
# libzmq setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
RUN \
|
||||||
|
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.tar.gz && \
|
||||||
|
tar -xzvf v4.3.4.tar.gz && \
|
||||||
|
cd libzmq-4.3.4 && \
|
||||||
|
mkdir build && \
|
||||||
|
cd build && \
|
||||||
|
cmake .. && \
|
||||||
|
make -j$(nproc) && \
|
||||||
|
make install && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# cppzmq setup
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip && \
|
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.9.0.tar.gz && \
|
||||||
unzip v4.3.4.zip && \
|
tar -xzvf v4.9.0.tar.gz && \
|
||||||
cd libzmq-4.3.4 && \
|
cd cppzmq-4.9.0 && \
|
||||||
|
mkdir build && \
|
||||||
|
cd build && \
|
||||||
|
cmake .. && \
|
||||||
|
make -j$(nproc) && \
|
||||||
|
make install && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# gsl setup
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
||||||
|
libpcre3-dev
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
wget https://github.com/imatix/gsl/archive/refs/tags/v4.1.4.tar.gz && \
|
||||||
|
tar -xzvf v4.1.4.tar.gz && \
|
||||||
|
cd gsl-4.1.4 && \
|
||||||
|
make -j$(nproc) && \
|
||||||
|
make install && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# libbitcoin-build setup
|
||||||
|
# libbitcoin-explorer setup
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
||||||
|
libsodium-dev
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
git clone --branch version3.8.0 --depth 1 https://gitlab.com/PBSA/peerplays-1.0/libbitcoin-explorer.git && \
|
||||||
|
cd libbitcoin-explorer && \
|
||||||
|
./install.sh && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Doxygen setup
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
sudo apt install -y bison flex && \
|
||||||
|
wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \
|
||||||
|
tar -xvf Release_1_8_17.tar.gz && \
|
||||||
|
cd doxygen-Release_1_8_17 && \
|
||||||
mkdir build && \
|
mkdir build && \
|
||||||
cd build && \
|
cd build && \
|
||||||
cmake .. && \
|
cmake .. && \
|
||||||
|
|
@ -70,18 +156,14 @@ RUN \
|
||||||
ldconfig
|
ldconfig
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# cppzmq setup
|
# Perl setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip && \
|
wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \
|
||||||
unzip v4.8.1.zip && \
|
tar -xvf v5.30.0.tar.gz && \
|
||||||
cd cppzmq-4.8.1 && \
|
cd perl5-5.30.0 && \
|
||||||
mkdir build && \
|
./Configure -des && \
|
||||||
cd build && \
|
|
||||||
cmake .. && \
|
|
||||||
make -j$(nproc) install && \
|
make -j$(nproc) install && \
|
||||||
ldconfig
|
ldconfig
|
||||||
|
|
||||||
|
|
@ -89,8 +171,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 && \
|
||||||
|
|
@ -106,6 +186,8 @@ ADD . peerplays
|
||||||
# Configure Peerplays
|
# Configure Peerplays
|
||||||
RUN \
|
RUN \
|
||||||
cd peerplays && \
|
cd peerplays && \
|
||||||
|
git submodule update --init --recursive && \
|
||||||
|
git log --oneline -n 5 && \
|
||||||
mkdir build && \
|
mkdir build && \
|
||||||
cd build && \
|
cd build && \
|
||||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||||
|
|
@ -119,8 +201,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
|
||||||
|
|
|
||||||
124
Dockerfile.18.04
124
Dockerfile.18.04
|
|
@ -1,5 +1,4 @@
|
||||||
FROM ubuntu:18.04
|
FROM ubuntu:18.04
|
||||||
MAINTAINER Peerplays Blockchain Standards Association
|
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# Ubuntu setup
|
# Ubuntu setup
|
||||||
|
|
@ -11,11 +10,12 @@ RUN \
|
||||||
apt-utils \
|
apt-utils \
|
||||||
autoconf \
|
autoconf \
|
||||||
bash \
|
bash \
|
||||||
|
bison \
|
||||||
build-essential \
|
build-essential \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
dnsutils \
|
dnsutils \
|
||||||
doxygen \
|
|
||||||
expect \
|
expect \
|
||||||
|
flex \
|
||||||
git \
|
git \
|
||||||
graphviz \
|
graphviz \
|
||||||
libbz2-dev \
|
libbz2-dev \
|
||||||
|
|
@ -33,7 +33,6 @@ RUN \
|
||||||
ntp \
|
ntp \
|
||||||
openssh-server \
|
openssh-server \
|
||||||
pkg-config \
|
pkg-config \
|
||||||
perl \
|
|
||||||
python3 \
|
python3 \
|
||||||
python3-jinja2 \
|
python3-jinja2 \
|
||||||
sudo \
|
sudo \
|
||||||
|
|
@ -51,41 +50,105 @@ 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 -c 'http://sourceforge.net/projects/boost/files/boost/1.67.0/boost_1_67_0.tar.bz2/download' -O boost_1_67_0.tar.bz2 && \
|
wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \
|
||||||
tar xjf boost_1_67_0.tar.bz2 && \
|
tar -xzf boost_1_72_0.tar.gz && \
|
||||||
cd boost_1_67_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 \
|
||||||
|
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.tar.gz && \
|
||||||
|
tar -xzvf v4.3.4.tar.gz && \
|
||||||
|
cd libzmq-4.3.4 && \
|
||||||
|
mkdir build && \
|
||||||
|
cd build && \
|
||||||
|
cmake .. && \
|
||||||
|
make -j$(nproc) && \
|
||||||
|
make install && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# cppzmq setup
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip && \
|
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.9.0.tar.gz && \
|
||||||
unzip v4.3.4.zip && \
|
tar -xzvf v4.9.0.tar.gz && \
|
||||||
cd libzmq-4.3.4 && \
|
cd cppzmq-4.9.0 && \
|
||||||
|
mkdir build && \
|
||||||
|
cd build && \
|
||||||
|
cmake .. && \
|
||||||
|
make -j$(nproc) && \
|
||||||
|
make install && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# gsl setup
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
||||||
|
libpcre3-dev
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
wget https://github.com/imatix/gsl/archive/refs/tags/v4.1.4.tar.gz && \
|
||||||
|
tar -xzvf v4.1.4.tar.gz && \
|
||||||
|
cd gsl-4.1.4 && \
|
||||||
|
make -j$(nproc) && \
|
||||||
|
make install && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# libbitcoin-build setup
|
||||||
|
# libbitcoin-explorer setup
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
||||||
|
libsodium-dev
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
git clone --branch version3.8.0 --depth 1 https://gitlab.com/PBSA/peerplays-1.0/libbitcoin-explorer.git && \
|
||||||
|
cd libbitcoin-explorer && \
|
||||||
|
./install.sh && \
|
||||||
|
ldconfig && \
|
||||||
|
rm -rf /home/peerplays/src/*
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Doxygen setup
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
sudo apt install -y bison flex && \
|
||||||
|
wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \
|
||||||
|
tar -xvf Release_1_8_17.tar.gz && \
|
||||||
|
cd doxygen-Release_1_8_17 && \
|
||||||
mkdir build && \
|
mkdir build && \
|
||||||
cd build && \
|
cd build && \
|
||||||
cmake .. && \
|
cmake .. && \
|
||||||
|
|
@ -93,18 +156,14 @@ RUN \
|
||||||
ldconfig
|
ldconfig
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# cppzmq setup
|
# Perl setup
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
|
||||||
WORKDIR /home/peerplays/
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip && \
|
wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \
|
||||||
unzip v4.8.1.zip && \
|
tar -xvf v5.30.0.tar.gz && \
|
||||||
cd cppzmq-4.8.1 && \
|
cd perl5-5.30.0 && \
|
||||||
mkdir build && \
|
./Configure -des && \
|
||||||
cd build && \
|
|
||||||
cmake .. && \
|
|
||||||
make -j$(nproc) install && \
|
make -j$(nproc) install && \
|
||||||
ldconfig
|
ldconfig
|
||||||
|
|
||||||
|
|
@ -112,8 +171,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 && \
|
||||||
|
|
@ -129,6 +186,9 @@ ADD . peerplays
|
||||||
# Configure Peerplays
|
# Configure Peerplays
|
||||||
RUN \
|
RUN \
|
||||||
cd peerplays && \
|
cd peerplays && \
|
||||||
|
git submodule update --init --recursive && \
|
||||||
|
git symbolic-ref --short HEAD && \
|
||||||
|
git log --oneline -n 5 && \
|
||||||
mkdir build && \
|
mkdir build && \
|
||||||
cd build && \
|
cd build && \
|
||||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||||
|
|
@ -142,8 +202,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
|
||||||
|
|
|
||||||
150
README.md
150
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 'http://sourceforge.net/projects/boost/files/boost/1.67.0/boost_1_67_0.tar.bz2/download' -O boost_1_67_0.tar.bz2
|
|
||||||
tar xjf boost_1_67_0.tar.bz2
|
|
||||||
cd boost_1_67_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,48 @@ 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 --branch version3.8.0 --depth 1 https://gitlab.com/PBSA/peerplays-1.0/libbitcoin-explorer.git
|
||||||
|
cd libbitcoin-explorer
|
||||||
|
sudo ./install.sh
|
||||||
|
sudo ldconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
Doxygen setup:
|
||||||
|
```
|
||||||
|
wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz
|
||||||
|
tar -xvf Release_1_8_17.tar.gz
|
||||||
|
cd doxygen-Release_1_8_17
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j$(nproc)
|
||||||
|
sudo make install
|
||||||
|
sudo ldconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
Perl setup:
|
||||||
|
```
|
||||||
|
wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz
|
||||||
|
tar -xvf v5.30.0.tar.gz
|
||||||
|
cd perl5-5.30.0
|
||||||
|
./Configure -des
|
||||||
|
make -j$(nproc)
|
||||||
|
sudo make install
|
||||||
|
sudo ldconfig
|
||||||
|
```
|
||||||
|
|
||||||
Building Peerplays
|
Building Peerplays
|
||||||
```
|
```
|
||||||
git clone https://gitlab.com/PBSA/peerplays.git
|
git clone https://gitlab.com/PBSA/peerplays.git
|
||||||
|
|
@ -146,7 +129,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.
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ add_subdirectory( egenesis )
|
||||||
add_subdirectory( fc )
|
add_subdirectory( fc )
|
||||||
add_subdirectory( net )
|
add_subdirectory( net )
|
||||||
add_subdirectory( plugins )
|
add_subdirectory( plugins )
|
||||||
|
add_subdirectory( sha3 )
|
||||||
add_subdirectory( time )
|
add_subdirectory( time )
|
||||||
add_subdirectory( utilities )
|
add_subdirectory( utilities )
|
||||||
add_subdirectory( wallet )
|
add_subdirectory( wallet )
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ template class fc::api<graphene::app::block_api>;
|
||||||
template class fc::api<graphene::app::network_broadcast_api>;
|
template class fc::api<graphene::app::network_broadcast_api>;
|
||||||
template class fc::api<graphene::app::network_node_api>;
|
template class fc::api<graphene::app::network_node_api>;
|
||||||
template class fc::api<graphene::app::history_api>;
|
template class fc::api<graphene::app::history_api>;
|
||||||
template class fc::api<graphene::app::crypto_api>;
|
|
||||||
template class fc::api<graphene::app::asset_api>;
|
template class fc::api<graphene::app::asset_api>;
|
||||||
template class fc::api<graphene::debug_witness::debug_api>;
|
template class fc::api<graphene::debug_witness::debug_api>;
|
||||||
template class fc::api<graphene::app::login_api>;
|
template class fc::api<graphene::app::login_api>;
|
||||||
|
|
@ -90,8 +89,6 @@ void login_api::enable_api(const std::string &api_name) {
|
||||||
_history_api = std::make_shared<history_api>(_app);
|
_history_api = std::make_shared<history_api>(_app);
|
||||||
} else if (api_name == "network_node_api") {
|
} else if (api_name == "network_node_api") {
|
||||||
_network_node_api = std::make_shared<network_node_api>(std::ref(_app));
|
_network_node_api = std::make_shared<network_node_api>(std::ref(_app));
|
||||||
} else if (api_name == "crypto_api") {
|
|
||||||
_crypto_api = std::make_shared<crypto_api>();
|
|
||||||
} else if (api_name == "asset_api") {
|
} else if (api_name == "asset_api") {
|
||||||
_asset_api = std::make_shared<asset_api>(_app);
|
_asset_api = std::make_shared<asset_api>(_app);
|
||||||
} else if (api_name == "debug_api") {
|
} else if (api_name == "debug_api") {
|
||||||
|
|
@ -213,8 +210,8 @@ network_node_api::network_node_api(application &a) :
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove expired transactions from pending_transactions
|
* Remove expired transactions from pending_transactions
|
||||||
*/
|
*/
|
||||||
for (const auto &transaction : _pending_transactions) {
|
for (const auto &transaction : _pending_transactions) {
|
||||||
if (transaction.second.expiration < block.timestamp) {
|
if (transaction.second.expiration < block.timestamp) {
|
||||||
auto transaction_it = _pending_transactions.find(transaction.second.id());
|
auto transaction_it = _pending_transactions.find(transaction.second.id());
|
||||||
|
|
@ -289,11 +286,6 @@ fc::api<history_api> login_api::history() const {
|
||||||
return *_history_api;
|
return *_history_api;
|
||||||
}
|
}
|
||||||
|
|
||||||
fc::api<crypto_api> login_api::crypto() const {
|
|
||||||
FC_ASSERT(_crypto_api);
|
|
||||||
return *_crypto_api;
|
|
||||||
}
|
|
||||||
|
|
||||||
fc::api<asset_api> login_api::asset() const {
|
fc::api<asset_api> login_api::asset() const {
|
||||||
FC_ASSERT(_asset_api);
|
FC_ASSERT(_asset_api);
|
||||||
return *_asset_api;
|
return *_asset_api;
|
||||||
|
|
@ -522,55 +514,6 @@ vector<bucket_object> history_api::get_market_history(std::string asset_a, std::
|
||||||
FC_CAPTURE_AND_RETHROW((asset_a)(asset_b)(bucket_seconds)(start)(end))
|
FC_CAPTURE_AND_RETHROW((asset_a)(asset_b)(bucket_seconds)(start)(end))
|
||||||
}
|
}
|
||||||
|
|
||||||
crypto_api::crypto_api(){};
|
|
||||||
|
|
||||||
commitment_type crypto_api::blind(const blind_factor_type &blind, uint64_t value) {
|
|
||||||
return fc::ecc::blind(blind, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
blind_factor_type crypto_api::blind_sum(const std::vector<blind_factor_type> &blinds_in, uint32_t non_neg) {
|
|
||||||
return fc::ecc::blind_sum(blinds_in, non_neg);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool crypto_api::verify_sum(const std::vector<commitment_type> &commits_in, const std::vector<commitment_type> &neg_commits_in, int64_t excess) {
|
|
||||||
return fc::ecc::verify_sum(commits_in, neg_commits_in, excess);
|
|
||||||
}
|
|
||||||
|
|
||||||
verify_range_result crypto_api::verify_range(const commitment_type &commit, const std::vector<char> &proof) {
|
|
||||||
verify_range_result result;
|
|
||||||
result.success = fc::ecc::verify_range(result.min_val, result.max_val, commit, proof);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<char> crypto_api::range_proof_sign(uint64_t min_value,
|
|
||||||
const commitment_type &commit,
|
|
||||||
const blind_factor_type &commit_blind,
|
|
||||||
const blind_factor_type &nonce,
|
|
||||||
int8_t base10_exp,
|
|
||||||
uint8_t min_bits,
|
|
||||||
uint64_t actual_value) {
|
|
||||||
return fc::ecc::range_proof_sign(min_value, commit, commit_blind, nonce, base10_exp, min_bits, actual_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
verify_range_proof_rewind_result crypto_api::verify_range_proof_rewind(const blind_factor_type &nonce,
|
|
||||||
const commitment_type &commit,
|
|
||||||
const std::vector<char> &proof) {
|
|
||||||
verify_range_proof_rewind_result result;
|
|
||||||
result.success = fc::ecc::verify_range_proof_rewind(result.blind_out,
|
|
||||||
result.value_out,
|
|
||||||
result.message_out,
|
|
||||||
nonce,
|
|
||||||
result.min_val,
|
|
||||||
result.max_val,
|
|
||||||
const_cast<commitment_type &>(commit),
|
|
||||||
proof);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
range_proof_info crypto_api::range_get_info(const std::vector<char> &proof) {
|
|
||||||
return fc::ecc::range_get_info(proof);
|
|
||||||
}
|
|
||||||
|
|
||||||
// asset_api
|
// asset_api
|
||||||
asset_api::asset_api(graphene::app::application &app) :
|
asset_api::asset_api(graphene::app::application &app) :
|
||||||
_app(app),
|
_app(app),
|
||||||
|
|
|
||||||
|
|
@ -362,7 +362,6 @@ public:
|
||||||
wild_access.allowed_apis.push_back("database_api");
|
wild_access.allowed_apis.push_back("database_api");
|
||||||
wild_access.allowed_apis.push_back("network_broadcast_api");
|
wild_access.allowed_apis.push_back("network_broadcast_api");
|
||||||
wild_access.allowed_apis.push_back("history_api");
|
wild_access.allowed_apis.push_back("history_api");
|
||||||
wild_access.allowed_apis.push_back("crypto_api");
|
|
||||||
wild_access.allowed_apis.push_back("bookie_api");
|
wild_access.allowed_apis.push_back("bookie_api");
|
||||||
wild_access.allowed_apis.push_back("affiliate_stats_api");
|
wild_access.allowed_apis.push_back("affiliate_stats_api");
|
||||||
wild_access.allowed_apis.push_back("sidechain_api");
|
wild_access.allowed_apis.push_back("sidechain_api");
|
||||||
|
|
@ -392,8 +391,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If delegate has the item, the network has no need to fetch it.
|
* If delegate has the item, the network has no need to fetch it.
|
||||||
*/
|
*/
|
||||||
virtual bool has_item(const net::item_id &id) override {
|
virtual bool has_item(const net::item_id &id) override {
|
||||||
try {
|
try {
|
||||||
if (id.item_type == graphene::net::block_message_type)
|
if (id.item_type == graphene::net::block_message_type)
|
||||||
|
|
@ -405,13 +404,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief allows the application to validate an item prior to broadcasting to peers.
|
* @brief allows the application to validate an item prior to broadcasting to peers.
|
||||||
*
|
*
|
||||||
* @param sync_mode true if the message was fetched through the sync process, false during normal operation
|
* @param sync_mode true if the message was fetched through the sync process, false during normal operation
|
||||||
* @returns true if this message caused the blockchain to switch forks, false if it did not
|
* @returns true if this message caused the blockchain to switch forks, false if it did not
|
||||||
*
|
*
|
||||||
* @throws exception if error validating the item, otherwise the item is safe to broadcast on.
|
* @throws exception if error validating the item, otherwise the item is safe to broadcast on.
|
||||||
*/
|
*/
|
||||||
virtual bool handle_block(const graphene::net::block_message &blk_msg, bool sync_mode,
|
virtual bool handle_block(const graphene::net::block_message &blk_msg, bool sync_mode,
|
||||||
std::vector<fc::uint160_t> &contained_transaction_message_ids) override {
|
std::vector<fc::uint160_t> &contained_transaction_message_ids) override {
|
||||||
|
|
||||||
|
|
@ -499,14 +498,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assuming all data elements are ordered in some way, this method should
|
* Assuming all data elements are ordered in some way, this method should
|
||||||
* return up to limit ids that occur *after* the last ID in synopsis that
|
* return up to limit ids that occur *after* the last ID in synopsis that
|
||||||
* we recognize.
|
* we recognize.
|
||||||
*
|
*
|
||||||
* On return, remaining_item_count will be set to the number of items
|
* On return, remaining_item_count will be set to the number of items
|
||||||
* in our blockchain after the last item returned in the result,
|
* in our blockchain after the last item returned in the result,
|
||||||
* or 0 if the result contains the last item in the blockchain
|
* or 0 if the result contains the last item in the blockchain
|
||||||
*/
|
*/
|
||||||
virtual std::vector<item_hash_t> get_block_ids(const std::vector<item_hash_t> &blockchain_synopsis,
|
virtual std::vector<item_hash_t> get_block_ids(const std::vector<item_hash_t> &blockchain_synopsis,
|
||||||
uint32_t &remaining_item_count,
|
uint32_t &remaining_item_count,
|
||||||
uint32_t limit) override {
|
uint32_t limit) override {
|
||||||
|
|
@ -553,8 +552,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the hash of the requested data, fetch the body.
|
* Given the hash of the requested data, fetch the body.
|
||||||
*/
|
*/
|
||||||
virtual message get_item(const item_id &id) override {
|
virtual message get_item(const item_id &id) override {
|
||||||
try {
|
try {
|
||||||
// ilog("Request for item ${id}", ("id", id));
|
// ilog("Request for item ${id}", ("id", id));
|
||||||
|
|
@ -577,63 +576,63 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a synopsis of the blockchain used for syncing. This consists of a list of
|
* Returns a synopsis of the blockchain used for syncing. This consists of a list of
|
||||||
* block hashes at intervals exponentially increasing towards the genesis block.
|
* block hashes at intervals exponentially increasing towards the genesis block.
|
||||||
* When syncing to a peer, the peer uses this data to determine if we're on the same
|
* When syncing to a peer, the peer uses this data to determine if we're on the same
|
||||||
* fork as they are, and if not, what blocks they need to send us to get us on their
|
* fork as they are, and if not, what blocks they need to send us to get us on their
|
||||||
* fork.
|
* fork.
|
||||||
*
|
*
|
||||||
* In the over-simplified case, this is a straighforward synopsis of our current
|
* In the over-simplified case, this is a straighforward synopsis of our current
|
||||||
* preferred blockchain; when we first connect up to a peer, this is what we will be sending.
|
* preferred blockchain; when we first connect up to a peer, this is what we will be sending.
|
||||||
* It looks like this:
|
* It looks like this:
|
||||||
* If the blockchain is empty, it will return the empty list.
|
* If the blockchain is empty, it will return the empty list.
|
||||||
* If the blockchain has one block, it will return a list containing just that block.
|
* If the blockchain has one block, it will return a list containing just that block.
|
||||||
* If it contains more than one block:
|
* If it contains more than one block:
|
||||||
* the first element in the list will be the hash of the highest numbered block that
|
* the first element in the list will be the hash of the highest numbered block that
|
||||||
* we cannot undo
|
* we cannot undo
|
||||||
* the second element will be the hash of an item at the half way point in the undoable
|
* the second element will be the hash of an item at the half way point in the undoable
|
||||||
* segment of the blockchain
|
* segment of the blockchain
|
||||||
* the third will be ~3/4 of the way through the undoable segment of the block chain
|
* the third will be ~3/4 of the way through the undoable segment of the block chain
|
||||||
* the fourth will be at ~7/8...
|
* the fourth will be at ~7/8...
|
||||||
* &c.
|
* &c.
|
||||||
* the last item in the list will be the hash of the most recent block on our preferred chain
|
* the last item in the list will be the hash of the most recent block on our preferred chain
|
||||||
* so if the blockchain had 26 blocks labeled a - z, the synopsis would be:
|
* so if the blockchain had 26 blocks labeled a - z, the synopsis would be:
|
||||||
* a n u x z
|
* a n u x z
|
||||||
* the idea being that by sending a small (<30) number of block ids, we can summarize a huge
|
* the idea being that by sending a small (<30) number of block ids, we can summarize a huge
|
||||||
* blockchain. The block ids are more dense near the end of the chain where because we are
|
* blockchain. The block ids are more dense near the end of the chain where because we are
|
||||||
* more likely to be almost in sync when we first connect, and forks are likely to be short.
|
* more likely to be almost in sync when we first connect, and forks are likely to be short.
|
||||||
* If the peer we're syncing with in our example is on a fork that started at block 'v',
|
* If the peer we're syncing with in our example is on a fork that started at block 'v',
|
||||||
* then they will reply to our synopsis with a list of all blocks starting from block 'u',
|
* then they will reply to our synopsis with a list of all blocks starting from block 'u',
|
||||||
* the last block they know that we had in common.
|
* the last block they know that we had in common.
|
||||||
*
|
*
|
||||||
* In the real code, there are several complications.
|
* In the real code, there are several complications.
|
||||||
*
|
*
|
||||||
* First, as an optimization, we don't usually send a synopsis of the entire blockchain, we
|
* First, as an optimization, we don't usually send a synopsis of the entire blockchain, we
|
||||||
* send a synopsis of only the segment of the blockchain that we have undo data for. If their
|
* send a synopsis of only the segment of the blockchain that we have undo data for. If their
|
||||||
* fork doesn't build off of something in our undo history, we would be unable to switch, so there's
|
* fork doesn't build off of something in our undo history, we would be unable to switch, so there's
|
||||||
* no reason to fetch the blocks.
|
* no reason to fetch the blocks.
|
||||||
*
|
*
|
||||||
* Second, when a peer replies to our initial synopsis and gives us a list of the blocks they think
|
* Second, when a peer replies to our initial synopsis and gives us a list of the blocks they think
|
||||||
* we are missing, they only send a chunk of a few thousand blocks at once. After we get those
|
* we are missing, they only send a chunk of a few thousand blocks at once. After we get those
|
||||||
* block ids, we need to request more blocks by sending another synopsis (we can't just say "send me
|
* block ids, we need to request more blocks by sending another synopsis (we can't just say "send me
|
||||||
* the next 2000 ids" because they may have switched forks themselves and they don't track what
|
* the next 2000 ids" because they may have switched forks themselves and they don't track what
|
||||||
* they've sent us). For faster performance, we want to get a fairly long list of block ids first,
|
* they've sent us). For faster performance, we want to get a fairly long list of block ids first,
|
||||||
* then start downloading the blocks.
|
* then start downloading the blocks.
|
||||||
* The peer doesn't handle these follow-up block id requests any different from the initial request;
|
* The peer doesn't handle these follow-up block id requests any different from the initial request;
|
||||||
* it treats the synopsis we send as our blockchain and bases its response entirely off that. So to
|
* it treats the synopsis we send as our blockchain and bases its response entirely off that. So to
|
||||||
* get the response we want (the next chunk of block ids following the last one they sent us, or,
|
* get the response we want (the next chunk of block ids following the last one they sent us, or,
|
||||||
* failing that, the shortest fork off of the last list of block ids they sent), we need to construct
|
* failing that, the shortest fork off of the last list of block ids they sent), we need to construct
|
||||||
* a synopsis as if our blockchain was made up of:
|
* a synopsis as if our blockchain was made up of:
|
||||||
* 1. the blocks in our block chain up to the fork point (if there is a fork) or the head block (if no fork)
|
* 1. the blocks in our block chain up to the fork point (if there is a fork) or the head block (if no fork)
|
||||||
* 2. the blocks we've already pushed from their fork (if there's a fork)
|
* 2. the blocks we've already pushed from their fork (if there's a fork)
|
||||||
* 3. the block ids they've previously sent us
|
* 3. the block ids they've previously sent us
|
||||||
* Segment 3 is handled in the p2p code, it just tells us the number of blocks it has (in
|
* Segment 3 is handled in the p2p code, it just tells us the number of blocks it has (in
|
||||||
* number_of_blocks_after_reference_point) so we can leave space in the synopsis for them.
|
* number_of_blocks_after_reference_point) so we can leave space in the synopsis for them.
|
||||||
* We're responsible for constructing the synopsis of Segments 1 and 2 from our active blockchain and
|
* We're responsible for constructing the synopsis of Segments 1 and 2 from our active blockchain and
|
||||||
* fork database. The reference_point parameter is the last block from that peer that has been
|
* fork database. The reference_point parameter is the last block from that peer that has been
|
||||||
* successfully pushed to the blockchain, so that tells us whether the peer is on a fork or on
|
* successfully pushed to the blockchain, so that tells us whether the peer is on a fork or on
|
||||||
* the main chain.
|
* the main chain.
|
||||||
*/
|
*/
|
||||||
virtual std::vector<item_hash_t> get_blockchain_synopsis(const item_hash_t &reference_point,
|
virtual std::vector<item_hash_t> get_blockchain_synopsis(const item_hash_t &reference_point,
|
||||||
uint32_t number_of_blocks_after_reference_point) override {
|
uint32_t number_of_blocks_after_reference_point) override {
|
||||||
try {
|
try {
|
||||||
|
|
@ -734,26 +733,26 @@ public:
|
||||||
low_block_num += (true_high_block_num - low_block_num + 2) / 2;
|
low_block_num += (true_high_block_num - low_block_num + 2) / 2;
|
||||||
} while (low_block_num <= high_block_num);
|
} while (low_block_num <= high_block_num);
|
||||||
|
|
||||||
//idump((synopsis));
|
// idump((synopsis));
|
||||||
return synopsis;
|
return synopsis;
|
||||||
}
|
}
|
||||||
FC_CAPTURE_AND_RETHROW()
|
FC_CAPTURE_AND_RETHROW()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this after the call to handle_message succeeds.
|
* Call this after the call to handle_message succeeds.
|
||||||
*
|
*
|
||||||
* @param item_type the type of the item we're synchronizing, will be the same as item passed to the sync_from() call
|
* @param item_type the type of the item we're synchronizing, will be the same as item passed to the sync_from() call
|
||||||
* @param item_count the number of items known to the node that haven't been sent to handle_item() yet.
|
* @param item_count the number of items known to the node that haven't been sent to handle_item() yet.
|
||||||
* After `item_count` more calls to handle_item(), the node will be in sync
|
* After `item_count` more calls to handle_item(), the node will be in sync
|
||||||
*/
|
*/
|
||||||
virtual void sync_status(uint32_t item_type, uint32_t item_count) override {
|
virtual void sync_status(uint32_t item_type, uint32_t item_count) override {
|
||||||
// any status reports to GUI go here
|
// any status reports to GUI go here
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call any time the number of connected peers changes.
|
* Call any time the number of connected peers changes.
|
||||||
*/
|
*/
|
||||||
virtual void connection_count_changed(uint32_t c) override {
|
virtual void connection_count_changed(uint32_t c) override {
|
||||||
// any status reports to GUI go here
|
// any status reports to GUI go here
|
||||||
}
|
}
|
||||||
|
|
@ -765,10 +764,14 @@ public:
|
||||||
FC_CAPTURE_AND_RETHROW((block_id))
|
FC_CAPTURE_AND_RETHROW((block_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual fc::time_point_sec get_last_known_hardfork_time() override {
|
||||||
|
return _chain_db->_hardfork_times[_chain_db->_hardfork_times.size() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the time a block was produced (if block_id = 0, returns genesis time).
|
* Returns the time a block was produced (if block_id = 0, returns genesis time).
|
||||||
* If we don't know about the block, returns time_point_sec::min()
|
* If we don't know about the block, returns time_point_sec::min()
|
||||||
*/
|
*/
|
||||||
virtual fc::time_point_sec get_block_time(const item_hash_t &block_id) override {
|
virtual fc::time_point_sec get_block_time(const item_hash_t &block_id) override {
|
||||||
try {
|
try {
|
||||||
auto opt_block = _chain_db->fetch_block_by_id(block_id);
|
auto opt_block = _chain_db->fetch_block_by_id(block_id);
|
||||||
|
|
@ -914,7 +917,8 @@ void application::initialize(const fc::path &data_dir, const boost::program_opti
|
||||||
wanted.insert("accounts_list");
|
wanted.insert("accounts_list");
|
||||||
wanted.insert("affiliate_stats");
|
wanted.insert("affiliate_stats");
|
||||||
}
|
}
|
||||||
wanted.insert("witness");
|
if (!wanted.count("delayed_node") && !wanted.count("debug_witness") && !wanted.count("witness")) // explicitly requested delayed_node or debug_witness functionality suppresses witness functions
|
||||||
|
wanted.insert("witness");
|
||||||
wanted.insert("bookie");
|
wanted.insert("bookie");
|
||||||
|
|
||||||
int es_ah_conflict_counter = 0;
|
int es_ah_conflict_counter = 0;
|
||||||
|
|
@ -946,7 +950,7 @@ void application::startup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<abstract_plugin> application::get_plugin(const string &name) const {
|
std::shared_ptr<abstract_plugin> application::get_plugin(const string &name) const {
|
||||||
return my->_active_plugins[name];
|
return is_plugin_enabled(name) ? my->_active_plugins[name] : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool application::is_plugin_enabled(const string &name) const {
|
bool application::is_plugin_enabled(const string &name) const {
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,17 @@ std::string object_id_to_string(object_id_type id) {
|
||||||
return object_id;
|
return object_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signed_block_with_info::signed_block_with_info(){};
|
||||||
|
|
||||||
|
signed_block_with_info::signed_block_with_info(const signed_block &block) :
|
||||||
|
signed_block(block) {
|
||||||
|
block_id = id();
|
||||||
|
signing_key = signee();
|
||||||
|
transaction_ids.reserve(transactions.size());
|
||||||
|
for (const processed_transaction &tx : transactions)
|
||||||
|
transaction_ids.push_back(tx.id());
|
||||||
|
}
|
||||||
|
|
||||||
class database_api_impl : public std::enable_shared_from_this<database_api_impl> {
|
class database_api_impl : public std::enable_shared_from_this<database_api_impl> {
|
||||||
public:
|
public:
|
||||||
database_api_impl(graphene::chain::database &db);
|
database_api_impl(graphene::chain::database &db);
|
||||||
|
|
@ -89,6 +100,7 @@ public:
|
||||||
optional<block_header> get_block_header(uint32_t block_num) const;
|
optional<block_header> get_block_header(uint32_t block_num) const;
|
||||||
map<uint32_t, optional<block_header>> get_block_header_batch(const vector<uint32_t> block_nums) const;
|
map<uint32_t, optional<block_header>> get_block_header_batch(const vector<uint32_t> block_nums) const;
|
||||||
optional<signed_block> get_block(uint32_t block_num) const;
|
optional<signed_block> get_block(uint32_t block_num) const;
|
||||||
|
optional<signed_block_with_info> get_block2(uint32_t block_num) const;
|
||||||
vector<optional<signed_block>> get_blocks(uint32_t block_num_from, uint32_t block_num_to) const;
|
vector<optional<signed_block>> get_blocks(uint32_t block_num_from, uint32_t block_num_to) const;
|
||||||
processed_transaction get_transaction(uint32_t block_num, uint32_t trx_in_block) const;
|
processed_transaction get_transaction(uint32_t block_num, uint32_t trx_in_block) const;
|
||||||
|
|
||||||
|
|
@ -184,6 +196,10 @@ public:
|
||||||
fc::optional<son_object> get_son_by_account(const std::string account_id_or_name) const;
|
fc::optional<son_object> get_son_by_account(const std::string account_id_or_name) const;
|
||||||
map<string, son_id_type> lookup_son_accounts(const string &lower_bound_name, uint32_t limit) const;
|
map<string, son_id_type> lookup_son_accounts(const string &lower_bound_name, uint32_t limit) const;
|
||||||
uint64_t get_son_count() const;
|
uint64_t get_son_count() const;
|
||||||
|
flat_map<sidechain_type, vector<son_sidechain_info>> get_active_sons();
|
||||||
|
vector<son_sidechain_info> get_active_sons_by_sidechain(sidechain_type sidechain);
|
||||||
|
map<sidechain_type, map<son_id_type, string>> get_son_network_status();
|
||||||
|
map<son_id_type, string> get_son_network_status_by_sidechain(sidechain_type sidechain);
|
||||||
|
|
||||||
// SON wallets
|
// SON wallets
|
||||||
optional<son_wallet_object> get_active_son_wallet();
|
optional<son_wallet_object> get_active_son_wallet();
|
||||||
|
|
@ -237,9 +253,6 @@ public:
|
||||||
// Proposed transactions
|
// Proposed transactions
|
||||||
vector<proposal_object> get_proposed_transactions(const std::string account_id_or_name) const;
|
vector<proposal_object> get_proposed_transactions(const std::string account_id_or_name) const;
|
||||||
|
|
||||||
// Blinded balances
|
|
||||||
vector<blinded_balance_object> get_blinded_balances(const flat_set<commitment_type> &commitments) const;
|
|
||||||
|
|
||||||
// Tournaments
|
// Tournaments
|
||||||
vector<tournament_object> get_tournaments_in_state(tournament_state state, uint32_t limit) const;
|
vector<tournament_object> get_tournaments_in_state(tournament_state state, uint32_t limit) const;
|
||||||
vector<tournament_object> get_tournaments(tournament_id_type stop, unsigned limit, tournament_id_type start);
|
vector<tournament_object> get_tournaments(tournament_id_type stop, unsigned limit, tournament_id_type start);
|
||||||
|
|
@ -268,8 +281,9 @@ public:
|
||||||
uint64_t nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const;
|
uint64_t nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const;
|
||||||
nft_object nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const;
|
nft_object nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const;
|
||||||
nft_object nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const;
|
nft_object nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const;
|
||||||
vector<nft_object> nft_get_all_tokens() const;
|
vector<nft_object> nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const;
|
||||||
vector<nft_object> nft_get_tokens_by_owner(const account_id_type owner) const;
|
vector<nft_object> nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const;
|
||||||
|
vector<nft_metadata_object> nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const;
|
||||||
|
|
||||||
// Marketplace
|
// Marketplace
|
||||||
vector<offer_object> list_offers(const offer_id_type lower_id, uint32_t limit) const;
|
vector<offer_object> list_offers(const offer_id_type lower_id, uint32_t limit) const;
|
||||||
|
|
@ -290,6 +304,7 @@ public:
|
||||||
uint32_t api_limit_get_limit_orders_by_account = 101;
|
uint32_t api_limit_get_limit_orders_by_account = 101;
|
||||||
uint32_t api_limit_get_order_book = 50;
|
uint32_t api_limit_get_order_book = 50;
|
||||||
uint32_t api_limit_all_offers_count = 100;
|
uint32_t api_limit_all_offers_count = 100;
|
||||||
|
uint32_t api_limit_nft_tokens = 100;
|
||||||
uint32_t api_limit_lookup_accounts = 1000;
|
uint32_t api_limit_lookup_accounts = 1000;
|
||||||
uint32_t api_limit_lookup_witness_accounts = 1000;
|
uint32_t api_limit_lookup_witness_accounts = 1000;
|
||||||
uint32_t api_limit_lookup_committee_member_accounts = 1000;
|
uint32_t api_limit_lookup_committee_member_accounts = 1000;
|
||||||
|
|
@ -298,7 +313,7 @@ public:
|
||||||
uint32_t api_limit_get_trade_history = 100;
|
uint32_t api_limit_get_trade_history = 100;
|
||||||
uint32_t api_limit_get_trade_history_by_sequence = 100;
|
uint32_t api_limit_get_trade_history_by_sequence = 100;
|
||||||
|
|
||||||
//private:
|
// private:
|
||||||
const account_object *get_account_from_string(const std::string &name_or_id,
|
const account_object *get_account_from_string(const std::string &name_or_id,
|
||||||
bool throw_if_not_found = true) const;
|
bool throw_if_not_found = true) const;
|
||||||
const asset_object *get_asset_from_string(const std::string &symbol_or_id,
|
const asset_object *get_asset_from_string(const std::string &symbol_or_id,
|
||||||
|
|
@ -455,7 +470,7 @@ void database_api::set_subscribe_callback(std::function<void(const variant &)> c
|
||||||
}
|
}
|
||||||
|
|
||||||
void database_api_impl::set_subscribe_callback(std::function<void(const variant &)> cb, bool notify_remove_create) {
|
void database_api_impl::set_subscribe_callback(std::function<void(const variant &)> cb, bool notify_remove_create) {
|
||||||
//edump((clear_filter));
|
// edump((clear_filter));
|
||||||
_subscribe_callback = cb;
|
_subscribe_callback = cb;
|
||||||
_notify_remove_create = notify_remove_create;
|
_notify_remove_create = notify_remove_create;
|
||||||
_subscribed_accounts.clear();
|
_subscribed_accounts.clear();
|
||||||
|
|
@ -529,6 +544,17 @@ optional<signed_block> database_api_impl::get_block(uint32_t block_num) const {
|
||||||
return _db.fetch_block_by_number(block_num);
|
return _db.fetch_block_by_number(block_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optional<signed_block_with_info> database_api::get_block2(uint32_t block_num) const {
|
||||||
|
return my->get_block2(block_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<signed_block_with_info> database_api_impl::get_block2(uint32_t block_num) const {
|
||||||
|
auto result = _db.fetch_block_by_number(block_num);
|
||||||
|
if (result)
|
||||||
|
return signed_block_with_info(*result);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
vector<optional<signed_block>> database_api::get_blocks(uint32_t block_num_from, uint32_t block_num_to) const {
|
vector<optional<signed_block>> database_api::get_blocks(uint32_t block_num_from, uint32_t block_num_to) const {
|
||||||
return my->get_blocks(block_num_from, block_num_to);
|
return my->get_blocks(block_num_from, block_num_to);
|
||||||
}
|
}
|
||||||
|
|
@ -1851,6 +1877,80 @@ uint64_t database_api_impl::get_son_count() const {
|
||||||
return _db.get_index_type<son_index>().indices().size();
|
return _db.get_index_type<son_index>().indices().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flat_map<sidechain_type, vector<son_sidechain_info>> database_api::get_active_sons() {
|
||||||
|
return my->get_active_sons();
|
||||||
|
}
|
||||||
|
|
||||||
|
flat_map<sidechain_type, vector<son_sidechain_info>> database_api_impl::get_active_sons() {
|
||||||
|
return get_global_properties().active_sons;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<son_sidechain_info> database_api::get_active_sons_by_sidechain(sidechain_type sidechain) {
|
||||||
|
return my->get_active_sons_by_sidechain(sidechain);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<son_sidechain_info> database_api_impl::get_active_sons_by_sidechain(sidechain_type sidechain) {
|
||||||
|
const global_property_object &gpo = get_global_properties();
|
||||||
|
|
||||||
|
vector<son_sidechain_info> result;
|
||||||
|
|
||||||
|
if (gpo.active_sons.find(sidechain) != gpo.active_sons.end()) {
|
||||||
|
result = gpo.active_sons.at(sidechain);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
map<sidechain_type, map<son_id_type, string>> database_api::get_son_network_status() {
|
||||||
|
return my->get_son_network_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
map<sidechain_type, map<son_id_type, string>> database_api_impl::get_son_network_status() {
|
||||||
|
map<sidechain_type, map<son_id_type, string>> result;
|
||||||
|
|
||||||
|
for (auto active_sidechain_type : active_sidechain_types(_db.head_block_time())) {
|
||||||
|
result[active_sidechain_type] = get_son_network_status_by_sidechain(active_sidechain_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
map<son_id_type, string> database_api::get_son_network_status_by_sidechain(sidechain_type sidechain) {
|
||||||
|
return my->get_son_network_status_by_sidechain(sidechain);
|
||||||
|
}
|
||||||
|
|
||||||
|
map<son_id_type, string> database_api_impl::get_son_network_status_by_sidechain(sidechain_type sidechain) {
|
||||||
|
const global_property_object &gpo = get_global_properties();
|
||||||
|
|
||||||
|
map<son_id_type, string> result;
|
||||||
|
|
||||||
|
if (gpo.active_sons.find(sidechain) != gpo.active_sons.end()) {
|
||||||
|
for (const auto si : gpo.active_sons.at(sidechain)) {
|
||||||
|
const auto son_obj = si.son_id(_db);
|
||||||
|
const auto sso = son_obj.statistics(_db);
|
||||||
|
string status;
|
||||||
|
|
||||||
|
if (sso.last_active_timestamp.find(sidechain) != sso.last_active_timestamp.end()) {
|
||||||
|
if (time_point_sec(sso.last_active_timestamp.at(sidechain) + fc::seconds(gpo.parameters.son_heartbeat_frequency())) > _db.head_block_time()) {
|
||||||
|
status = "OK, regular SON heartbeat";
|
||||||
|
} else {
|
||||||
|
if (time_point_sec(sso.last_active_timestamp.at(sidechain) + fc::seconds(gpo.parameters.son_down_time())) > _db.head_block_time()) {
|
||||||
|
status = "OK, irregular SON heartbeat, but not triggering SON down proposal";
|
||||||
|
} else {
|
||||||
|
status = "NOT OK, irregular SON heartbeat, triggering SON down proposal";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = "No heartbeats sent";
|
||||||
|
}
|
||||||
|
|
||||||
|
result[si.son_id] = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// //
|
// //
|
||||||
// SON Wallets //
|
// SON Wallets //
|
||||||
|
|
@ -2086,7 +2186,9 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
|
||||||
const auto &committee_idx = _db.get_index_type<committee_member_index>().indices().get<by_vote_id>();
|
const auto &committee_idx = _db.get_index_type<committee_member_index>().indices().get<by_vote_id>();
|
||||||
const auto &for_worker_idx = _db.get_index_type<worker_index>().indices().get<by_vote_for>();
|
const auto &for_worker_idx = _db.get_index_type<worker_index>().indices().get<by_vote_for>();
|
||||||
const auto &against_worker_idx = _db.get_index_type<worker_index>().indices().get<by_vote_against>();
|
const auto &against_worker_idx = _db.get_index_type<worker_index>().indices().get<by_vote_against>();
|
||||||
const auto &son_idx = _db.get_index_type<son_index>().indices().get<by_vote_id>();
|
const auto &son_bictoin_idx = _db.get_index_type<son_index>().indices().get<by_vote_id_bitcoin>();
|
||||||
|
const auto &son_hive_idx = _db.get_index_type<son_index>().indices().get<by_vote_id_hive>();
|
||||||
|
const auto &son_ethereum_idx = _db.get_index_type<son_index>().indices().get<by_vote_id_ethereum>();
|
||||||
|
|
||||||
vector<variant> result;
|
vector<variant> result;
|
||||||
result.reserve(votes.size());
|
result.reserve(votes.size());
|
||||||
|
|
@ -2095,7 +2197,7 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
|
||||||
case vote_id_type::committee: {
|
case vote_id_type::committee: {
|
||||||
auto itr = committee_idx.find(id);
|
auto itr = committee_idx.find(id);
|
||||||
if (itr != committee_idx.end())
|
if (itr != committee_idx.end())
|
||||||
result.emplace_back(variant(*itr, 1));
|
result.emplace_back(variant(*itr, 2)); // Depth of committee_member_object is 1, add 1 to be safe
|
||||||
else
|
else
|
||||||
result.emplace_back(variant());
|
result.emplace_back(variant());
|
||||||
break;
|
break;
|
||||||
|
|
@ -2103,7 +2205,7 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
|
||||||
case vote_id_type::witness: {
|
case vote_id_type::witness: {
|
||||||
auto itr = witness_idx.find(id);
|
auto itr = witness_idx.find(id);
|
||||||
if (itr != witness_idx.end())
|
if (itr != witness_idx.end())
|
||||||
result.emplace_back(variant(*itr, 1));
|
result.emplace_back(variant(*itr, 2)); // Depth of witness_object is 1, add 1 here to be safe
|
||||||
else
|
else
|
||||||
result.emplace_back(variant());
|
result.emplace_back(variant());
|
||||||
break;
|
break;
|
||||||
|
|
@ -2111,26 +2213,45 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
|
||||||
case vote_id_type::worker: {
|
case vote_id_type::worker: {
|
||||||
auto itr = for_worker_idx.find(id);
|
auto itr = for_worker_idx.find(id);
|
||||||
if (itr != for_worker_idx.end()) {
|
if (itr != for_worker_idx.end()) {
|
||||||
result.emplace_back(variant(*itr, 1));
|
result.emplace_back(variant(*itr, 4)); // Depth of worker_object is 3, add 1 here to be safe.
|
||||||
|
// If we want to extract the balance object inside,
|
||||||
|
// need to increase this value
|
||||||
} else {
|
} else {
|
||||||
auto itr = against_worker_idx.find(id);
|
auto itr = against_worker_idx.find(id);
|
||||||
if (itr != against_worker_idx.end()) {
|
if (itr != against_worker_idx.end()) {
|
||||||
result.emplace_back(variant(*itr, 1));
|
result.emplace_back(variant(*itr, 4)); // Depth of worker_object is 3, add 1 here to be safe.
|
||||||
|
// If we want to extract the balance object inside,
|
||||||
|
// need to increase this value
|
||||||
} else {
|
} else {
|
||||||
result.emplace_back(variant());
|
result.emplace_back(variant());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case vote_id_type::son: {
|
case vote_id_type::son_bitcoin: {
|
||||||
auto itr = son_idx.find(id);
|
auto itr = son_bictoin_idx.find(id);
|
||||||
if (itr != son_idx.end())
|
if (itr != son_bictoin_idx.end())
|
||||||
|
result.emplace_back(variant(*itr, 5));
|
||||||
|
else
|
||||||
|
result.emplace_back(variant());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case vote_id_type::son_hive: {
|
||||||
|
auto itr = son_hive_idx.find(id);
|
||||||
|
if (itr != son_hive_idx.end())
|
||||||
|
result.emplace_back(variant(*itr, 5));
|
||||||
|
else
|
||||||
|
result.emplace_back(variant());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case vote_id_type::son_ethereum: {
|
||||||
|
auto itr = son_ethereum_idx.find(id);
|
||||||
|
if (itr != son_ethereum_idx.end())
|
||||||
result.emplace_back(variant(*itr, 5));
|
result.emplace_back(variant(*itr, 5));
|
||||||
else
|
else
|
||||||
result.emplace_back(variant());
|
result.emplace_back(variant());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case vote_id_type::VOTE_TYPE_COUNT:
|
case vote_id_type::VOTE_TYPE_COUNT:
|
||||||
break; // supress unused enum value warnings
|
break; // supress unused enum value warnings
|
||||||
default:
|
default:
|
||||||
|
|
@ -2155,12 +2276,24 @@ vector<vote_id_type> database_api_impl::get_votes_ids(const string &account_name
|
||||||
votes_info database_api_impl::get_votes(const string &account_name_or_id) const {
|
votes_info database_api_impl::get_votes(const string &account_name_or_id) const {
|
||||||
votes_info result;
|
votes_info result;
|
||||||
|
|
||||||
const auto &votes_ids = get_votes_ids(account_name_or_id);
|
const auto votes_ids = get_votes_ids(account_name_or_id);
|
||||||
const auto &committee_ids = get_votes_objects<committee_member_index, by_vote_id>(votes_ids);
|
const auto committee_ids = get_votes_objects<committee_member_index, by_vote_id>(votes_ids);
|
||||||
const auto &witness_ids = get_votes_objects<witness_index, by_vote_id>(votes_ids);
|
const auto witness_ids = get_votes_objects<witness_index, by_vote_id>(votes_ids);
|
||||||
const auto &for_worker_ids = get_votes_objects<worker_index, by_vote_for>(votes_ids);
|
const auto for_worker_ids = get_votes_objects<worker_index, by_vote_for>(votes_ids);
|
||||||
const auto &against_worker_ids = get_votes_objects<worker_index, by_vote_against>(votes_ids);
|
const auto against_worker_ids = get_votes_objects<worker_index, by_vote_against>(votes_ids);
|
||||||
const auto &son_ids = get_votes_objects<son_index, by_vote_id>(votes_ids, 5);
|
const auto son_ids = [this, &votes_ids]() {
|
||||||
|
flat_map<sidechain_type, vector<variant>> son_ids;
|
||||||
|
const auto son_bitcoin_ids = get_votes_objects<son_index, by_vote_id_bitcoin>(votes_ids, 5);
|
||||||
|
if (!son_bitcoin_ids.empty())
|
||||||
|
son_ids[sidechain_type::bitcoin] = std::move(son_bitcoin_ids);
|
||||||
|
const auto son_hive_ids = get_votes_objects<son_index, by_vote_id_hive>(votes_ids, 5);
|
||||||
|
if (!son_hive_ids.empty())
|
||||||
|
son_ids[sidechain_type::hive] = std::move(son_hive_ids);
|
||||||
|
const auto son_ethereum_ids = get_votes_objects<son_index, by_vote_id_ethereum>(votes_ids, 5);
|
||||||
|
if (!son_ethereum_ids.empty())
|
||||||
|
son_ids[sidechain_type::ethereum] = std::move(son_ethereum_ids);
|
||||||
|
return son_ids;
|
||||||
|
}();
|
||||||
|
|
||||||
//! Fill votes info
|
//! Fill votes info
|
||||||
if (!committee_ids.empty()) {
|
if (!committee_ids.empty()) {
|
||||||
|
|
@ -2204,11 +2337,17 @@ votes_info database_api_impl::get_votes(const string &account_name_or_id) const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!son_ids.empty()) {
|
if (!son_ids.empty()) {
|
||||||
vector<votes_info_object> votes_for_sons;
|
flat_map<sidechain_type, vector<votes_info_object>> votes_for_sons;
|
||||||
votes_for_sons.reserve(son_ids.size());
|
for (const auto &son_sidechain_ids : son_ids) {
|
||||||
for (const auto &son : son_ids) {
|
const auto &sidechain = son_sidechain_ids.first;
|
||||||
const auto &son_obj = son.as<son_object>(6);
|
const auto &sidechain_ids = son_sidechain_ids.second;
|
||||||
votes_for_sons.emplace_back(votes_info_object{son_obj.vote_id, son_obj.id});
|
votes_for_sons[sidechain].reserve(sidechain_ids.size());
|
||||||
|
for (const auto &son : sidechain_ids) {
|
||||||
|
const auto &son_obj = son.as<son_object>(6);
|
||||||
|
if (son_obj.get_sidechain_vote_id(sidechain).valid()) {
|
||||||
|
votes_for_sons[sidechain].emplace_back(votes_info_object{*son_obj.get_sidechain_vote_id(sidechain), son_obj.id});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result.votes_for_sons = std::move(votes_for_sons);
|
result.votes_for_sons = std::move(votes_for_sons);
|
||||||
}
|
}
|
||||||
|
|
@ -2382,12 +2521,16 @@ voters_info database_api_impl::get_voters(const string &account_name_or_id) cons
|
||||||
|
|
||||||
//! Info for son voters
|
//! Info for son voters
|
||||||
if (son_object) {
|
if (son_object) {
|
||||||
const auto &son_voters = get_voters_by_id(son_object->vote_id);
|
flat_map<sidechain_type, voters_info_object> voters_for_son;
|
||||||
voters_info_object voters_for_son;
|
for (const auto &vote_id : son_object->sidechain_vote_ids) {
|
||||||
voters_for_son.vote_id = son_object->vote_id;
|
const auto &son_voters = get_voters_by_id(vote_id.second);
|
||||||
voters_for_son.voters.reserve(son_voters.size());
|
voters_info_object voters_for_sidechain_son;
|
||||||
for (const auto &voter : son_voters) {
|
voters_for_sidechain_son.vote_id = vote_id.second;
|
||||||
voters_for_son.voters.emplace_back(voter.get_id());
|
voters_for_sidechain_son.voters.reserve(son_voters.size());
|
||||||
|
for (const auto &voter : son_voters) {
|
||||||
|
voters_for_sidechain_son.voters.emplace_back(voter.get_id());
|
||||||
|
}
|
||||||
|
voters_for_son[vote_id.first] = std::move(voters_for_sidechain_son);
|
||||||
}
|
}
|
||||||
result.voters_for_son = std::move(voters_for_son);
|
result.voters_for_son = std::move(voters_for_son);
|
||||||
}
|
}
|
||||||
|
|
@ -2650,29 +2793,6 @@ vector<proposal_object> database_api_impl::get_proposed_transactions(const std::
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// //
|
|
||||||
// Blinded balances //
|
|
||||||
// //
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
vector<blinded_balance_object> database_api::get_blinded_balances(const flat_set<commitment_type> &commitments) const {
|
|
||||||
return my->get_blinded_balances(commitments);
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<blinded_balance_object> database_api_impl::get_blinded_balances(const flat_set<commitment_type> &commitments) const {
|
|
||||||
vector<blinded_balance_object> result;
|
|
||||||
result.reserve(commitments.size());
|
|
||||||
const auto &bal_idx = _db.get_index_type<blinded_balance_index>();
|
|
||||||
const auto &by_commitment_idx = bal_idx.indices().get<by_commitment>();
|
|
||||||
for (const auto &c : commitments) {
|
|
||||||
auto itr = by_commitment_idx.find(c);
|
|
||||||
if (itr != by_commitment_idx.end())
|
|
||||||
result.push_back(*itr);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// //
|
// //
|
||||||
// Tournament methods //
|
// Tournament methods //
|
||||||
|
|
@ -2787,7 +2907,7 @@ graphene::app::gpos_info database_api::get_gpos_info(const account_id_type accou
|
||||||
}
|
}
|
||||||
|
|
||||||
graphene::app::gpos_info database_api_impl::get_gpos_info(const account_id_type account) const {
|
graphene::app::gpos_info database_api_impl::get_gpos_info(const account_id_type account) const {
|
||||||
FC_ASSERT(_db.head_block_time() > HARDFORK_GPOS_TIME); //Can be deleted after GPOS hardfork time
|
FC_ASSERT(_db.head_block_time() > HARDFORK_GPOS_TIME); // Can be deleted after GPOS hardfork time
|
||||||
gpos_info result;
|
gpos_info result;
|
||||||
|
|
||||||
result.vesting_factor = _db.calculate_vesting_factor(account(_db));
|
result.vesting_factor = _db.calculate_vesting_factor(account(_db));
|
||||||
|
|
@ -2975,8 +3095,8 @@ uint64_t database_api::nft_get_total_supply(const nft_metadata_id_type nft_metad
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t database_api_impl::nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const {
|
uint64_t database_api_impl::nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const {
|
||||||
const auto &idx_nft_md = _db.get_index_type<nft_metadata_index>().indices().get<by_id>();
|
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_metadata>();
|
||||||
return idx_nft_md.size();
|
return idx_nft.count(nft_metadata_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
nft_object database_api::nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const {
|
nft_object database_api::nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const {
|
||||||
|
|
@ -3013,30 +3133,61 @@ nft_object database_api_impl::nft_token_of_owner_by_index(const nft_metadata_id_
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<nft_object> database_api::nft_get_all_tokens() const {
|
vector<nft_object> database_api::nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const {
|
||||||
return my->nft_get_all_tokens();
|
return my->nft_get_all_tokens(lower_id, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<nft_object> database_api_impl::nft_get_all_tokens() const {
|
vector<nft_object> database_api_impl::nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const {
|
||||||
|
FC_ASSERT(limit <= api_limit_nft_tokens,
|
||||||
|
"Number of queried nft tokens can not be greater than ${configured_limit}",
|
||||||
|
("configured_limit", api_limit_nft_tokens));
|
||||||
|
|
||||||
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_id>();
|
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_id>();
|
||||||
vector<nft_object> result;
|
vector<nft_object> result;
|
||||||
for (auto itr = idx_nft.begin(); itr != idx_nft.end(); ++itr) {
|
result.reserve(limit);
|
||||||
result.push_back(*itr);
|
auto itr = idx_nft.lower_bound(lower_id);
|
||||||
}
|
while (limit-- && itr != idx_nft.end())
|
||||||
|
result.emplace_back(*itr++);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<nft_object> database_api::nft_get_tokens_by_owner(const account_id_type owner) const {
|
vector<nft_object> database_api::nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const {
|
||||||
return my->nft_get_tokens_by_owner(owner);
|
return my->nft_get_tokens_by_owner(owner, lower_id, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<nft_object> database_api_impl::nft_get_tokens_by_owner(const account_id_type owner) const {
|
vector<nft_object> database_api_impl::nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const {
|
||||||
|
FC_ASSERT(limit <= api_limit_nft_tokens,
|
||||||
|
"Number of queried nft tokens can not be greater than ${configured_limit}",
|
||||||
|
("configured_limit", api_limit_nft_tokens));
|
||||||
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_owner>();
|
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_owner>();
|
||||||
auto idx_nft_range = idx_nft.equal_range(owner);
|
auto idx_nft_range = idx_nft.equal_range(owner);
|
||||||
vector<nft_object> result;
|
vector<nft_object> result;
|
||||||
for (auto itr = idx_nft_range.first; itr != idx_nft_range.second; ++itr) {
|
result.reserve(limit);
|
||||||
result.push_back(*itr);
|
auto itr = std::find_if(idx_nft_range.first, idx_nft_range.second, [&lower_id](const nft_object &obj) {
|
||||||
}
|
return !(obj.id.instance() < lower_id.instance);
|
||||||
|
});
|
||||||
|
while (limit-- && itr != idx_nft_range.second)
|
||||||
|
result.emplace_back(*itr++);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<nft_metadata_object> database_api::nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const {
|
||||||
|
return my->nft_get_metadata_by_owner(owner, lower_id, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<nft_metadata_object> database_api_impl::nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const {
|
||||||
|
FC_ASSERT(limit <= api_limit_nft_tokens,
|
||||||
|
"Number of queried nft metadata objects can not be greater than ${configured_limit}",
|
||||||
|
("configured_limit", api_limit_nft_tokens));
|
||||||
|
const auto &idx_nft = _db.get_index_type<nft_metadata_index>().indices().get<by_owner>();
|
||||||
|
auto idx_nft_range = idx_nft.equal_range(owner);
|
||||||
|
vector<nft_metadata_object> result;
|
||||||
|
result.reserve(limit);
|
||||||
|
auto itr = std::find_if(idx_nft_range.first, idx_nft_range.second, [&lower_id](const nft_metadata_object &obj) {
|
||||||
|
return !(obj.id.instance() < lower_id.instance);
|
||||||
|
});
|
||||||
|
while (limit-- && itr != idx_nft_range.second)
|
||||||
|
result.emplace_back(*itr++);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3403,9 +3554,9 @@ void database_api_impl::handle_object_changed(bool force_notify, bool full_objec
|
||||||
/// pushing the future back / popping the prior future if it is complete.
|
/// pushing the future back / popping the prior future if it is complete.
|
||||||
/// if a connection hangs then this could get backed up and result in
|
/// if a connection hangs then this could get backed up and result in
|
||||||
/// a failure to exit cleanly.
|
/// a failure to exit cleanly.
|
||||||
//fc::async([capture_this,this,updates,market_broadcast_queue](){
|
// fc::async([capture_this,this,updates,market_broadcast_queue](){
|
||||||
//if( _subscribe_callback )
|
// if( _subscribe_callback )
|
||||||
// _subscribe_callback( updates );
|
// _subscribe_callback( updates );
|
||||||
|
|
||||||
for (auto id : ids) {
|
for (auto id : ids) {
|
||||||
if (id.is<call_order_object>()) {
|
if (id.is<call_order_object>()) {
|
||||||
|
|
|
||||||
|
|
@ -85,10 +85,10 @@ struct asset_holders {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The history_api class implements the RPC API for account history
|
* @brief The history_api class implements the RPC API for account history
|
||||||
*
|
*
|
||||||
* This API contains methods to access account histories
|
* This API contains methods to access account histories
|
||||||
*/
|
*/
|
||||||
class history_api {
|
class history_api {
|
||||||
public:
|
public:
|
||||||
history_api(application &app) :
|
history_api(application &app) :
|
||||||
|
|
@ -97,27 +97,27 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get operations relevant to the specificed account
|
* @brief Get operations relevant to the specificed account
|
||||||
* @param account_id_or_name The account ID or name whose history should be queried
|
* @param account_id_or_name The account ID or name whose history should be queried
|
||||||
* @param stop ID of the earliest operation to retrieve
|
* @param stop ID of the earliest operation to retrieve
|
||||||
* @param limit Maximum number of operations to retrieve (must not exceed 100)
|
* @param limit Maximum number of operations to retrieve (must not exceed 100)
|
||||||
* @param start ID of the most recent operation to retrieve
|
* @param start ID of the most recent operation to retrieve
|
||||||
* @return A list of operations performed by account, ordered from most recent to oldest.
|
* @return A list of operations performed by account, ordered from most recent to oldest.
|
||||||
*/
|
*/
|
||||||
vector<operation_history_object> get_account_history(const std::string account_id_or_name,
|
vector<operation_history_object> get_account_history(const std::string account_id_or_name,
|
||||||
operation_history_id_type stop = operation_history_id_type(),
|
operation_history_id_type stop = operation_history_id_type(),
|
||||||
unsigned limit = 100,
|
unsigned limit = 100,
|
||||||
operation_history_id_type start = operation_history_id_type()) const;
|
operation_history_id_type start = operation_history_id_type()) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get only asked operations relevant to the specified account
|
* @brief Get only asked operations relevant to the specified account
|
||||||
* @param account_id_or_name The account ID or name whose history should be queried
|
* @param account_id_or_name The account ID or name whose history should be queried
|
||||||
* @param operation_id The ID of the operation we want to get operations in the account( 0 = transfer , 1 = limit order create, ...)
|
* @param operation_id The ID of the operation we want to get operations in the account( 0 = transfer , 1 = limit order create, ...)
|
||||||
* @param stop ID of the earliest operation to retrieve
|
* @param stop ID of the earliest operation to retrieve
|
||||||
* @param limit Maximum number of operations to retrieve (must not exceed 100)
|
* @param limit Maximum number of operations to retrieve (must not exceed 100)
|
||||||
* @param start ID of the most recent operation to retrieve
|
* @param start ID of the most recent operation to retrieve
|
||||||
* @return A list of operations performed by account, ordered from most recent to oldest.
|
* @return A list of operations performed by account, ordered from most recent to oldest.
|
||||||
*/
|
*/
|
||||||
vector<operation_history_object> get_account_history_operations(const std::string account_id_or_name,
|
vector<operation_history_object> get_account_history_operations(const std::string account_id_or_name,
|
||||||
int operation_id,
|
int operation_id,
|
||||||
operation_history_id_type start = operation_history_id_type(),
|
operation_history_id_type start = operation_history_id_type(),
|
||||||
|
|
@ -125,17 +125,17 @@ public:
|
||||||
unsigned limit = 100) const;
|
unsigned limit = 100) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @breif Get operations relevant to the specified account referenced
|
* @breif Get operations relevant to the specified account referenced
|
||||||
* by an event numbering specific to the account. The current number of operations
|
* by an event numbering specific to the account. The current number of operations
|
||||||
* for the account can be found in the account statistics (or use 0 for start).
|
* for the account can be found in the account statistics (or use 0 for start).
|
||||||
* @param account_id_or_name The account ID or name whose history should be queried
|
* @param account_id_or_name The account ID or name whose history should be queried
|
||||||
* @param stop Sequence number of earliest operation. 0 is default and will
|
* @param stop Sequence number of earliest operation. 0 is default and will
|
||||||
* query 'limit' number of operations.
|
* query 'limit' number of operations.
|
||||||
* @param limit Maximum number of operations to retrieve (must not exceed 100)
|
* @param limit Maximum number of operations to retrieve (must not exceed 100)
|
||||||
* @param start Sequence number of the most recent operation to retrieve.
|
* @param start Sequence number of the most recent operation to retrieve.
|
||||||
* 0 is default, which will start querying from the most recent operation.
|
* 0 is default, which will start querying from the most recent operation.
|
||||||
* @return A list of operations performed by account, ordered from most recent to oldest.
|
* @return A list of operations performed by account, ordered from most recent to oldest.
|
||||||
*/
|
*/
|
||||||
vector<operation_history_object> get_relative_account_history(const std::string account_id_or_name,
|
vector<operation_history_object> get_relative_account_history(const std::string account_id_or_name,
|
||||||
uint32_t stop = 0,
|
uint32_t stop = 0,
|
||||||
unsigned limit = 100,
|
unsigned limit = 100,
|
||||||
|
|
@ -156,8 +156,8 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Block api
|
* @brief Block api
|
||||||
*/
|
*/
|
||||||
class block_api {
|
class block_api {
|
||||||
public:
|
public:
|
||||||
block_api(graphene::chain::database &db);
|
block_api(graphene::chain::database &db);
|
||||||
|
|
@ -170,8 +170,8 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The network_broadcast_api class allows broadcasting of transactions.
|
* @brief The network_broadcast_api class allows broadcasting of transactions.
|
||||||
*/
|
*/
|
||||||
class network_broadcast_api : public std::enable_shared_from_this<network_broadcast_api> {
|
class network_broadcast_api : public std::enable_shared_from_this<network_broadcast_api> {
|
||||||
public:
|
public:
|
||||||
network_broadcast_api(application &a);
|
network_broadcast_api(application &a);
|
||||||
|
|
@ -186,36 +186,36 @@ public:
|
||||||
typedef std::function<void(variant /*transaction_confirmation*/)> confirmation_callback;
|
typedef std::function<void(variant /*transaction_confirmation*/)> confirmation_callback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Broadcast a transaction to the network
|
* @brief Broadcast a transaction to the network
|
||||||
* @param trx The transaction to broadcast
|
* @param trx The transaction to broadcast
|
||||||
*
|
*
|
||||||
* The transaction will be checked for validity in the local database prior to broadcasting. If it fails to
|
* The transaction will be checked for validity in the local database prior to broadcasting. If it fails to
|
||||||
* apply locally, an error will be thrown and the transaction will not be broadcast.
|
* apply locally, an error will be thrown and the transaction will not be broadcast.
|
||||||
*/
|
*/
|
||||||
void broadcast_transaction(const signed_transaction &trx);
|
void broadcast_transaction(const signed_transaction &trx);
|
||||||
|
|
||||||
/** this version of broadcast transaction registers a callback method that will be called when the transaction is
|
/** this version of broadcast transaction registers a callback method that will be called when the transaction is
|
||||||
* included into a block. The callback method includes the transaction id, block number, and transaction number in the
|
* included into a block. The callback method includes the transaction id, block number, and transaction number in the
|
||||||
* block.
|
* block.
|
||||||
*/
|
*/
|
||||||
void broadcast_transaction_with_callback(confirmation_callback cb, const signed_transaction &trx);
|
void broadcast_transaction_with_callback(confirmation_callback cb, const signed_transaction &trx);
|
||||||
|
|
||||||
/** this version of broadcast transaction registers a callback method that will be called when the transaction is
|
/** this version of broadcast transaction registers a callback method that will be called when the transaction is
|
||||||
* included into a block. The callback method includes the transaction id, block number, and transaction number in the
|
* included into a block. The callback method includes the transaction id, block number, and transaction number in the
|
||||||
* block.
|
* block.
|
||||||
*/
|
*/
|
||||||
fc::variant broadcast_transaction_synchronous(const signed_transaction &trx);
|
fc::variant broadcast_transaction_synchronous(const signed_transaction &trx);
|
||||||
|
|
||||||
void broadcast_block(const signed_block &block);
|
void broadcast_block(const signed_block &block);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Not reflected, thus not accessible to API clients.
|
* @brief Not reflected, thus not accessible to API clients.
|
||||||
*
|
*
|
||||||
* This function is registered to receive the applied_block
|
* This function is registered to receive the applied_block
|
||||||
* signal from the chain database when a block is received.
|
* signal from the chain database when a block is received.
|
||||||
* It then dispatches callbacks to clients who have requested
|
* It then dispatches callbacks to clients who have requested
|
||||||
* to be notified when a particular txid is included in a block.
|
* to be notified when a particular txid is included in a block.
|
||||||
*/
|
*/
|
||||||
void on_applied_block(const signed_block &b);
|
void on_applied_block(const signed_block &b);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -225,60 +225,60 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The network_node_api class allows maintenance of p2p connections.
|
* @brief The network_node_api class allows maintenance of p2p connections.
|
||||||
*/
|
*/
|
||||||
class network_node_api {
|
class network_node_api {
|
||||||
public:
|
public:
|
||||||
network_node_api(application &a);
|
network_node_api(application &a);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return general network information, such as p2p port
|
* @brief Return general network information, such as p2p port
|
||||||
*/
|
*/
|
||||||
fc::variant_object get_info() const;
|
fc::variant_object get_info() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief add_node Connect to a new peer
|
* @brief add_node Connect to a new peer
|
||||||
* @param ep The IP/Port of the peer to connect to
|
* @param ep The IP/Port of the peer to connect to
|
||||||
*/
|
*/
|
||||||
void add_node(const fc::ip::endpoint &ep);
|
void add_node(const fc::ip::endpoint &ep);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get status of all current connections to peers
|
* @brief Get status of all current connections to peers
|
||||||
*/
|
*/
|
||||||
std::vector<net::peer_status> get_connected_peers() const;
|
std::vector<net::peer_status> get_connected_peers() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get advanced node parameters, such as desired and max
|
* @brief Get advanced node parameters, such as desired and max
|
||||||
* number of connections
|
* number of connections
|
||||||
*/
|
*/
|
||||||
fc::variant_object get_advanced_node_parameters() const;
|
fc::variant_object get_advanced_node_parameters() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set advanced node parameters, such as desired and max
|
* @brief Set advanced node parameters, such as desired and max
|
||||||
* number of connections
|
* number of connections
|
||||||
* @param params a JSON object containing the name/value pairs for the parameters to set
|
* @param params a JSON object containing the name/value pairs for the parameters to set
|
||||||
*/
|
*/
|
||||||
void set_advanced_node_parameters(const fc::variant_object ¶ms);
|
void set_advanced_node_parameters(const fc::variant_object ¶ms);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return list of potential peers
|
* @brief Return list of potential peers
|
||||||
*/
|
*/
|
||||||
std::vector<net::potential_peer_record> get_potential_peers() const;
|
std::vector<net::potential_peer_record> get_potential_peers() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return list of pending transactions.
|
* @brief Return list of pending transactions.
|
||||||
*/
|
*/
|
||||||
map<transaction_id_type, signed_transaction> list_pending_transactions() const;
|
map<transaction_id_type, signed_transaction> list_pending_transactions() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Subscribes caller for notifications about pending transactions.
|
* @brief Subscribes caller for notifications about pending transactions.
|
||||||
* @param callback a functional object which will be called when new transaction is created.
|
* @param callback a functional object which will be called when new transaction is created.
|
||||||
*/
|
*/
|
||||||
void subscribe_to_pending_transactions(std::function<void(const variant &)> callback);
|
void subscribe_to_pending_transactions(std::function<void(const variant &)> callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unsubscribes caller from notifications about pending transactions.
|
* @brief Unsubscribes caller from notifications about pending transactions.
|
||||||
*/
|
*/
|
||||||
void unsubscribe_from_pending_transactions();
|
void unsubscribe_from_pending_transactions();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -289,61 +289,34 @@ private:
|
||||||
std::function<void(const variant &)> _on_pending_transaction;
|
std::function<void(const variant &)> _on_pending_transaction;
|
||||||
};
|
};
|
||||||
|
|
||||||
class crypto_api {
|
|
||||||
public:
|
|
||||||
crypto_api();
|
|
||||||
|
|
||||||
fc::ecc::commitment_type blind(const fc::ecc::blind_factor_type &blind, uint64_t value);
|
|
||||||
|
|
||||||
fc::ecc::blind_factor_type blind_sum(const std::vector<blind_factor_type> &blinds_in, uint32_t non_neg);
|
|
||||||
|
|
||||||
bool verify_sum(const std::vector<commitment_type> &commits_in, const std::vector<commitment_type> &neg_commits_in, int64_t excess);
|
|
||||||
|
|
||||||
verify_range_result verify_range(const fc::ecc::commitment_type &commit, const std::vector<char> &proof);
|
|
||||||
|
|
||||||
std::vector<char> range_proof_sign(uint64_t min_value,
|
|
||||||
const commitment_type &commit,
|
|
||||||
const blind_factor_type &commit_blind,
|
|
||||||
const blind_factor_type &nonce,
|
|
||||||
int8_t base10_exp,
|
|
||||||
uint8_t min_bits,
|
|
||||||
uint64_t actual_value);
|
|
||||||
|
|
||||||
verify_range_proof_rewind_result verify_range_proof_rewind(const blind_factor_type &nonce,
|
|
||||||
const fc::ecc::commitment_type &commit,
|
|
||||||
const std::vector<char> &proof);
|
|
||||||
|
|
||||||
range_proof_info range_get_info(const std::vector<char> &proof);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
*/
|
*/
|
||||||
class asset_api {
|
class asset_api {
|
||||||
public:
|
public:
|
||||||
asset_api(graphene::app::application &app);
|
asset_api(graphene::app::application &app);
|
||||||
~asset_api();
|
~asset_api();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get asset holders for a specific asset
|
* @brief Get asset holders for a specific asset
|
||||||
* @param asset The specific asset id or symbol
|
* @param asset The specific asset id or symbol
|
||||||
* @param start The start index
|
* @param start The start index
|
||||||
* @param limit Maximum limit must not exceed 100
|
* @param limit Maximum limit must not exceed 100
|
||||||
* @return A list of asset holders for the specified asset
|
* @return A list of asset holders for the specified asset
|
||||||
*/
|
*/
|
||||||
vector<account_asset_balance> get_asset_holders(std::string asset, uint32_t start, uint32_t limit) const;
|
vector<account_asset_balance> get_asset_holders(std::string asset, uint32_t start, uint32_t limit) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get asset holders count for a specific asset
|
* @brief Get asset holders count for a specific asset
|
||||||
* @param asset The specific asset id or symbol
|
* @param asset The specific asset id or symbol
|
||||||
* @return Holders count for the specified asset
|
* @return Holders count for the specified asset
|
||||||
*/
|
*/
|
||||||
int get_asset_holders_count(std::string asset) const;
|
int get_asset_holders_count(std::string asset) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get all asset holders
|
* @brief Get all asset holders
|
||||||
* @return A list of all asset holders
|
* @return A list of all asset holders
|
||||||
*/
|
*/
|
||||||
vector<asset_holders> get_all_asset_holders() const;
|
vector<asset_holders> get_all_asset_holders() const;
|
||||||
|
|
||||||
uint32_t api_limit_get_asset_holders = 100;
|
uint32_t api_limit_get_asset_holders = 100;
|
||||||
|
|
@ -359,30 +332,29 @@ extern template class fc::api<graphene::app::block_api>;
|
||||||
extern template class fc::api<graphene::app::network_broadcast_api>;
|
extern template class fc::api<graphene::app::network_broadcast_api>;
|
||||||
extern template class fc::api<graphene::app::network_node_api>;
|
extern template class fc::api<graphene::app::network_node_api>;
|
||||||
extern template class fc::api<graphene::app::history_api>;
|
extern template class fc::api<graphene::app::history_api>;
|
||||||
extern template class fc::api<graphene::app::crypto_api>;
|
|
||||||
extern template class fc::api<graphene::app::asset_api>;
|
extern template class fc::api<graphene::app::asset_api>;
|
||||||
extern template class fc::api<graphene::debug_witness::debug_api>;
|
extern template class fc::api<graphene::debug_witness::debug_api>;
|
||||||
|
|
||||||
namespace graphene { namespace app {
|
namespace graphene { namespace app {
|
||||||
/**
|
/**
|
||||||
* @brief The login_api class implements the bottom layer of the RPC API
|
* @brief The login_api class implements the bottom layer of the RPC API
|
||||||
*
|
*
|
||||||
* All other APIs must be requested from this API.
|
* All other APIs must be requested from this API.
|
||||||
*/
|
*/
|
||||||
class login_api {
|
class login_api {
|
||||||
public:
|
public:
|
||||||
login_api(application &a);
|
login_api(application &a);
|
||||||
~login_api();
|
~login_api();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Authenticate to the RPC server
|
* @brief Authenticate to the RPC server
|
||||||
* @param user Username to login with
|
* @param user Username to login with
|
||||||
* @param password Password to login with
|
* @param password Password to login with
|
||||||
* @return True if logged in successfully; false otherwise
|
* @return True if logged in successfully; false otherwise
|
||||||
*
|
*
|
||||||
* @note This must be called prior to requesting other APIs. Other APIs may not be accessible until the client
|
* @note This must be called prior to requesting other APIs. Other APIs may not be accessible until the client
|
||||||
* has sucessfully authenticated.
|
* has sucessfully authenticated.
|
||||||
*/
|
*/
|
||||||
bool login(const string &user, const string &password);
|
bool login(const string &user, const string &password);
|
||||||
/// @brief Retrieve the network block API
|
/// @brief Retrieve the network block API
|
||||||
fc::api<block_api> block() const;
|
fc::api<block_api> block() const;
|
||||||
|
|
@ -394,8 +366,6 @@ public:
|
||||||
fc::api<history_api> history() const;
|
fc::api<history_api> history() const;
|
||||||
/// @brief Retrieve the network node API
|
/// @brief Retrieve the network node API
|
||||||
fc::api<network_node_api> network_node() const;
|
fc::api<network_node_api> network_node() const;
|
||||||
/// @brief Retrieve the cryptography API
|
|
||||||
fc::api<crypto_api> crypto() const;
|
|
||||||
/// @brief Retrieve the asset API
|
/// @brief Retrieve the asset API
|
||||||
fc::api<asset_api> asset() const;
|
fc::api<asset_api> asset() const;
|
||||||
/// @brief Retrieve the debug API (if available)
|
/// @brief Retrieve the debug API (if available)
|
||||||
|
|
@ -417,7 +387,6 @@ private:
|
||||||
optional<fc::api<network_broadcast_api>> _network_broadcast_api;
|
optional<fc::api<network_broadcast_api>> _network_broadcast_api;
|
||||||
optional<fc::api<network_node_api>> _network_node_api;
|
optional<fc::api<network_node_api>> _network_node_api;
|
||||||
optional<fc::api<history_api>> _history_api;
|
optional<fc::api<history_api>> _history_api;
|
||||||
optional<fc::api<crypto_api>> _crypto_api;
|
|
||||||
optional<fc::api<asset_api>> _asset_api;
|
optional<fc::api<asset_api>> _asset_api;
|
||||||
optional<fc::api<graphene::debug_witness::debug_api>> _debug_api;
|
optional<fc::api<graphene::debug_witness::debug_api>> _debug_api;
|
||||||
optional<fc::api<graphene::bookie::bookie_api>> _bookie_api;
|
optional<fc::api<graphene::bookie::bookie_api>> _bookie_api;
|
||||||
|
|
@ -475,15 +444,6 @@ FC_API(graphene::app::network_node_api,
|
||||||
(subscribe_to_pending_transactions)
|
(subscribe_to_pending_transactions)
|
||||||
(unsubscribe_from_pending_transactions))
|
(unsubscribe_from_pending_transactions))
|
||||||
|
|
||||||
FC_API(graphene::app::crypto_api,
|
|
||||||
(blind)
|
|
||||||
(blind_sum)
|
|
||||||
(verify_sum)
|
|
||||||
(verify_range)
|
|
||||||
(range_proof_sign)
|
|
||||||
(verify_range_proof_rewind)
|
|
||||||
(range_get_info))
|
|
||||||
|
|
||||||
FC_API(graphene::app::asset_api,
|
FC_API(graphene::app::asset_api,
|
||||||
(get_asset_holders)
|
(get_asset_holders)
|
||||||
(get_asset_holders_count)
|
(get_asset_holders_count)
|
||||||
|
|
@ -496,7 +456,6 @@ FC_API(graphene::app::login_api,
|
||||||
(database)
|
(database)
|
||||||
(history)
|
(history)
|
||||||
(network_node)
|
(network_node)
|
||||||
(crypto)
|
|
||||||
(asset)
|
(asset)
|
||||||
(debug)
|
(debug)
|
||||||
(bookie)
|
(bookie)
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,15 @@ using namespace std;
|
||||||
|
|
||||||
class database_api_impl;
|
class database_api_impl;
|
||||||
|
|
||||||
|
struct signed_block_with_info : public signed_block {
|
||||||
|
signed_block_with_info();
|
||||||
|
signed_block_with_info(const signed_block &block);
|
||||||
|
signed_block_with_info(const signed_block_with_info &block) = default;
|
||||||
|
block_id_type block_id;
|
||||||
|
public_key_type signing_key;
|
||||||
|
vector<transaction_id_type> transaction_ids;
|
||||||
|
};
|
||||||
|
|
||||||
struct order {
|
struct order {
|
||||||
double price;
|
double price;
|
||||||
double quote;
|
double quote;
|
||||||
|
|
@ -189,10 +198,10 @@ public:
|
||||||
optional<block_header> get_block_header(uint32_t block_num) const;
|
optional<block_header> get_block_header(uint32_t block_num) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve multiple block header by block numbers
|
* @brief Retrieve multiple block header by block numbers
|
||||||
* @param block_num vector containing heights of the block whose header should be returned
|
* @param block_num vector containing heights of the block whose header should be returned
|
||||||
* @return array of headers of the referenced blocks, or null if no matching block was found
|
* @return array of headers of the referenced blocks, or null if no matching block was found
|
||||||
*/
|
*/
|
||||||
map<uint32_t, optional<block_header>> get_block_header_batch(const vector<uint32_t> block_nums) const;
|
map<uint32_t, optional<block_header>> get_block_header_batch(const vector<uint32_t> block_nums) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -202,6 +211,13 @@ public:
|
||||||
*/
|
*/
|
||||||
optional<signed_block> get_block(uint32_t block_num) const;
|
optional<signed_block> get_block(uint32_t block_num) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieve a full, signed block, with some extra info
|
||||||
|
* @param block_num Height of the block to be returned
|
||||||
|
* @return the referenced block, or null if no matching block was found
|
||||||
|
*/
|
||||||
|
optional<signed_block_with_info> get_block2(uint32_t block_num) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve a list of signed blocks
|
* @brief Retrieve a list of signed blocks
|
||||||
* @param block_num_from start
|
* @param block_num_from start
|
||||||
|
|
@ -263,12 +279,12 @@ public:
|
||||||
vector<vector<account_id_type>> get_key_references(vector<public_key_type> key) const;
|
vector<vector<account_id_type>> get_key_references(vector<public_key_type> key) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether a textual representation of a public key
|
* Determine whether a textual representation of a public key
|
||||||
* (in Base-58 format) is *currently* linked
|
* (in Base-58 format) is *currently* linked
|
||||||
* to any *registered* (i.e. non-stealth) account on the blockchain
|
* to any *registered* (i.e. non-stealth) account on the blockchain
|
||||||
* @param public_key Public key
|
* @param public_key Public key
|
||||||
* @return Whether a public key is known
|
* @return Whether a public key is known
|
||||||
*/
|
*/
|
||||||
bool is_public_key_registered(string public_key) const;
|
bool is_public_key_registered(string public_key) const;
|
||||||
|
|
||||||
//////////////
|
//////////////
|
||||||
|
|
@ -675,6 +691,32 @@ public:
|
||||||
*/
|
*/
|
||||||
uint64_t get_son_count() const;
|
uint64_t get_son_count() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get list of active sons
|
||||||
|
* @return List of active SONs
|
||||||
|
*/
|
||||||
|
flat_map<sidechain_type, vector<son_sidechain_info>> get_active_sons();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get list of active sons
|
||||||
|
* @param sidechain Sidechain type [bitcoin|ethereum|hive]
|
||||||
|
* @return List of active SONs
|
||||||
|
*/
|
||||||
|
vector<son_sidechain_info> get_active_sons_by_sidechain(sidechain_type sidechain);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get SON network status
|
||||||
|
* @return SON network status description for a given sidechain type
|
||||||
|
*/
|
||||||
|
map<sidechain_type, map<son_id_type, string>> get_son_network_status();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get SON network status
|
||||||
|
* @param sidechain Sidechain type [bitcoin|ethereum|hive]
|
||||||
|
* @return SON network status description for a given sidechain type
|
||||||
|
*/
|
||||||
|
map<son_id_type, string> get_son_network_status_by_sidechain(sidechain_type sidechain);
|
||||||
|
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
// SON Wallets //
|
// SON Wallets //
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
|
|
@ -877,15 +919,6 @@ public:
|
||||||
*/
|
*/
|
||||||
vector<proposal_object> get_proposed_transactions(const std::string account_id_or_name) const;
|
vector<proposal_object> get_proposed_transactions(const std::string account_id_or_name) const;
|
||||||
|
|
||||||
//////////////////////
|
|
||||||
// Blinded balances //
|
|
||||||
//////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the set of blinded balance objects by commitment ID
|
|
||||||
*/
|
|
||||||
vector<blinded_balance_object> get_blinded_balances(const flat_set<commitment_type> &commitments) const;
|
|
||||||
|
|
||||||
/////////////////
|
/////////////////
|
||||||
// Tournaments //
|
// Tournaments //
|
||||||
/////////////////
|
/////////////////
|
||||||
|
|
@ -1010,14 +1043,25 @@ public:
|
||||||
* @brief Returns list of all available NTF's
|
* @brief Returns list of all available NTF's
|
||||||
* @return List of all available NFT's
|
* @return List of all available NFT's
|
||||||
*/
|
*/
|
||||||
vector<nft_object> nft_get_all_tokens() const;
|
vector<nft_object> nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns NFT's owned by owner
|
* @brief Returns NFT's owned by owner
|
||||||
* @param owner NFT owner
|
* @param owner NFT owner
|
||||||
|
* @param lower_id ID of the first NFT to return
|
||||||
|
* @param limit Maximum number of results to return
|
||||||
* @return List of NFT owned by owner
|
* @return List of NFT owned by owner
|
||||||
*/
|
*/
|
||||||
vector<nft_object> nft_get_tokens_by_owner(const account_id_type owner) const;
|
vector<nft_object> nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns NFT metadata owned by owner
|
||||||
|
* @param owner NFT owner
|
||||||
|
* @param lower_id ID of the first NFT metadata to return
|
||||||
|
* @param limit Maximum number of results to return
|
||||||
|
* @return List of NFT owned by owner
|
||||||
|
*/
|
||||||
|
vector<nft_metadata_object> nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const;
|
||||||
|
|
||||||
//////////////////
|
//////////////////
|
||||||
// MARKET PLACE //
|
// MARKET PLACE //
|
||||||
|
|
@ -1047,6 +1091,8 @@ extern template class fc::api<graphene::app::database_api>;
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
|
FC_REFLECT_DERIVED(graphene::app::signed_block_with_info, (graphene::chain::signed_block), (block_id)(signing_key)(transaction_ids));
|
||||||
|
|
||||||
FC_REFLECT(graphene::app::order, (price)(quote)(base));
|
FC_REFLECT(graphene::app::order, (price)(quote)(base));
|
||||||
FC_REFLECT(graphene::app::order_book, (base)(quote)(bids)(asks));
|
FC_REFLECT(graphene::app::order_book, (base)(quote)(bids)(asks));
|
||||||
FC_REFLECT(graphene::app::market_ticker, (base)(quote)(latest)(lowest_ask)(highest_bid)(percent_change)(base_volume)(quote_volume));
|
FC_REFLECT(graphene::app::market_ticker, (base)(quote)(latest)(lowest_ask)(highest_bid)(percent_change)(base_volume)(quote_volume));
|
||||||
|
|
@ -1069,6 +1115,7 @@ FC_API(graphene::app::database_api,
|
||||||
(get_block_header)
|
(get_block_header)
|
||||||
(get_block_header_batch)
|
(get_block_header_batch)
|
||||||
(get_block)
|
(get_block)
|
||||||
|
(get_block2)
|
||||||
(get_blocks)
|
(get_blocks)
|
||||||
(get_transaction)
|
(get_transaction)
|
||||||
(get_recent_transaction_by_id)
|
(get_recent_transaction_by_id)
|
||||||
|
|
@ -1158,6 +1205,10 @@ FC_API(graphene::app::database_api,
|
||||||
(get_son_by_account)
|
(get_son_by_account)
|
||||||
(lookup_son_accounts)
|
(lookup_son_accounts)
|
||||||
(get_son_count)
|
(get_son_count)
|
||||||
|
(get_active_sons)
|
||||||
|
(get_active_sons_by_sidechain)
|
||||||
|
(get_son_network_status)
|
||||||
|
(get_son_network_status_by_sidechain)
|
||||||
|
|
||||||
// SON wallets
|
// SON wallets
|
||||||
(get_active_son_wallet)
|
(get_active_son_wallet)
|
||||||
|
|
@ -1198,9 +1249,6 @@ FC_API(graphene::app::database_api,
|
||||||
// Proposed transactions
|
// Proposed transactions
|
||||||
(get_proposed_transactions)
|
(get_proposed_transactions)
|
||||||
|
|
||||||
// Blinded balances
|
|
||||||
(get_blinded_balances)
|
|
||||||
|
|
||||||
// Tournaments
|
// Tournaments
|
||||||
(get_tournaments_in_state)
|
(get_tournaments_in_state)
|
||||||
(get_tournaments_by_state)
|
(get_tournaments_by_state)
|
||||||
|
|
@ -1231,6 +1279,7 @@ FC_API(graphene::app::database_api,
|
||||||
(nft_token_of_owner_by_index)
|
(nft_token_of_owner_by_index)
|
||||||
(nft_get_all_tokens)
|
(nft_get_all_tokens)
|
||||||
(nft_get_tokens_by_owner)
|
(nft_get_tokens_by_owner)
|
||||||
|
(nft_get_metadata_by_owner)
|
||||||
|
|
||||||
// Marketplace
|
// Marketplace
|
||||||
(list_offers)
|
(list_offers)
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,54 @@ void verify_authority_accounts( const database& db, const authority& a )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void verify_account_votes( const database& db, const account_options& options )
|
// Overwrites the num_son values from the origin to the destination for those sidechains which are found in the origin.
|
||||||
|
// Keeps the values of num_son for the sidechains which are found in the destination, but not in the origin.
|
||||||
|
// Returns false if an error is detected.
|
||||||
|
bool merge_num_sons( flat_map<sidechain_type, uint16_t>& destination,
|
||||||
|
const flat_map<sidechain_type, uint16_t>& origin,
|
||||||
|
fc::optional<time_point_sec> head_block_time = {})
|
||||||
|
{
|
||||||
|
const auto active_sidechains = head_block_time.valid() ? active_sidechain_types(*head_block_time) : all_sidechain_types;
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
for (const auto &ns : origin)
|
||||||
|
{
|
||||||
|
destination[ns.first] = ns.second;
|
||||||
|
if (active_sidechains.find(ns.first) == active_sidechains.end())
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
flat_map<sidechain_type, uint16_t> count_SON_votes_per_sidechain( const flat_set<vote_id_type>& votes )
|
||||||
|
{
|
||||||
|
flat_map<sidechain_type, uint16_t> SON_votes_per_sidechain = account_options::ext::empty_num_son();
|
||||||
|
|
||||||
|
for (const auto &vote : votes)
|
||||||
|
{
|
||||||
|
switch (vote.type())
|
||||||
|
{
|
||||||
|
case vote_id_type::son_bitcoin:
|
||||||
|
SON_votes_per_sidechain[sidechain_type::bitcoin]++;
|
||||||
|
break;
|
||||||
|
case vote_id_type::son_hive:
|
||||||
|
SON_votes_per_sidechain[sidechain_type::hive]++;
|
||||||
|
break;
|
||||||
|
case vote_id_type::son_ethereum:
|
||||||
|
SON_votes_per_sidechain[sidechain_type::ethereum]++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SON_votes_per_sidechain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void verify_account_votes( const database& db, const account_options& options, fc::optional<account_object> account = {} )
|
||||||
{
|
{
|
||||||
// ensure account's votes satisfy requirements
|
// ensure account's votes satisfy requirements
|
||||||
// NB only the part of vote checking that requires chain state is here,
|
// NB only the part of vote checking that requires chain state is here,
|
||||||
|
|
@ -62,10 +109,47 @@ void verify_account_votes( const database& db, const account_options& options )
|
||||||
const auto& gpo = db.get_global_properties();
|
const auto& gpo = db.get_global_properties();
|
||||||
const auto& chain_params = gpo.parameters;
|
const auto& chain_params = gpo.parameters;
|
||||||
|
|
||||||
|
FC_ASSERT( db.find_object(options.voting_account), "Invalid proxy account specified." );
|
||||||
|
|
||||||
FC_ASSERT( options.num_witness <= chain_params.maximum_witness_count,
|
FC_ASSERT( options.num_witness <= chain_params.maximum_witness_count,
|
||||||
"Voted for more witnesses than currently allowed (${c})", ("c", chain_params.maximum_witness_count) );
|
"Voted for more witnesses than currently allowed (${c})", ("c", chain_params.maximum_witness_count) );
|
||||||
FC_ASSERT( options.num_committee <= chain_params.maximum_committee_count,
|
FC_ASSERT( options.num_committee <= chain_params.maximum_committee_count,
|
||||||
"Voted for more committee members than currently allowed (${c})", ("c", chain_params.maximum_committee_count) );
|
"Voted for more committee members than currently allowed (${c})", ("c", chain_params.maximum_committee_count) );
|
||||||
|
FC_ASSERT( chain_params.extensions.value.maximum_son_count.valid() , "Invalid maximum son count" );
|
||||||
|
|
||||||
|
flat_map<sidechain_type, uint16_t> merged_num_sons = account_options::ext::empty_num_son();
|
||||||
|
|
||||||
|
// Merge with existing account if exists
|
||||||
|
if ( account.valid() && account->options.extensions.value.num_son.valid())
|
||||||
|
{
|
||||||
|
merge_num_sons( merged_num_sons, *account->options.extensions.value.num_son, db.head_block_time() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply update operation on top
|
||||||
|
if ( options.extensions.value.num_son.valid() )
|
||||||
|
{
|
||||||
|
merge_num_sons( merged_num_sons, *options.extensions.value.num_son, db.head_block_time() );
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto& num_sons : merged_num_sons)
|
||||||
|
{
|
||||||
|
FC_ASSERT( num_sons.second <= *chain_params.extensions.value.maximum_son_count,
|
||||||
|
"Voted for more sons than currently allowed (${c})", ("c", *chain_params.extensions.value.maximum_son_count) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the votes for SONs and confirm that the account did not vote for less SONs than num_son
|
||||||
|
flat_map<sidechain_type, uint16_t> SON_votes_per_sidechain = count_SON_votes_per_sidechain(options.votes);
|
||||||
|
|
||||||
|
for (const auto& number_of_votes : SON_votes_per_sidechain)
|
||||||
|
{
|
||||||
|
// Number of votes of account_options are also checked in account_options::do_evaluate,
|
||||||
|
// but there we are checking the value before merging num_sons, so the values should be checked again
|
||||||
|
const auto sidechain = number_of_votes.first;
|
||||||
|
FC_ASSERT( number_of_votes.second >= merged_num_sons[sidechain],
|
||||||
|
"Voted for less sons than specified in num_son (votes ${v} < num_son ${ns}) for sidechain ${s}",
|
||||||
|
("v", number_of_votes.second) ("ns", merged_num_sons[sidechain]) ("s", sidechain) );
|
||||||
|
}
|
||||||
|
|
||||||
FC_ASSERT( db.find_object(options.voting_account), "Invalid proxy account specified." );
|
FC_ASSERT( db.find_object(options.voting_account), "Invalid proxy account specified." );
|
||||||
|
|
||||||
uint32_t max_vote_id = gpo.next_available_vote_id;
|
uint32_t max_vote_id = gpo.next_available_vote_id;
|
||||||
|
|
@ -179,6 +263,13 @@ object_id_type account_create_evaluator::do_apply( const account_create_operatio
|
||||||
obj.owner = o.owner;
|
obj.owner = o.owner;
|
||||||
obj.active = o.active;
|
obj.active = o.active;
|
||||||
obj.options = o.options;
|
obj.options = o.options;
|
||||||
|
|
||||||
|
obj.options.extensions.value.num_son = account_options::ext::empty_num_son();
|
||||||
|
if ( o.options.extensions.value.num_son.valid() )
|
||||||
|
{
|
||||||
|
merge_num_sons( *obj.options.extensions.value.num_son, *o.options.extensions.value.num_son );
|
||||||
|
}
|
||||||
|
|
||||||
obj.statistics = d.create<account_statistics_object>([&obj](account_statistics_object& s){
|
obj.statistics = d.create<account_statistics_object>([&obj](account_statistics_object& s){
|
||||||
s.owner = obj.id;
|
s.owner = obj.id;
|
||||||
s.name = obj.name;
|
s.name = obj.name;
|
||||||
|
|
@ -278,7 +369,7 @@ void_result account_update_evaluator::do_evaluate( const account_update_operatio
|
||||||
acnt = &o.account(d);
|
acnt = &o.account(d);
|
||||||
|
|
||||||
if( o.new_options.valid() )
|
if( o.new_options.valid() )
|
||||||
verify_account_votes( d, *o.new_options );
|
verify_account_votes( d, *o.new_options, *acnt );
|
||||||
|
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||||
|
|
@ -317,7 +408,31 @@ void_result account_update_evaluator::do_apply( const account_update_operation&
|
||||||
a.active = *o.active;
|
a.active = *o.active;
|
||||||
a.top_n_control_flags = 0;
|
a.top_n_control_flags = 0;
|
||||||
}
|
}
|
||||||
if( o.new_options ) a.options = *o.new_options;
|
|
||||||
|
// New num_son structure initialized to 0
|
||||||
|
flat_map<sidechain_type, uint16_t> new_num_son = account_options::ext::empty_num_son();
|
||||||
|
|
||||||
|
// If num_son of existing object is valid, we should merge the existing data
|
||||||
|
if ( a.options.extensions.value.num_son.valid() )
|
||||||
|
{
|
||||||
|
merge_num_sons( new_num_son, *a.options.extensions.value.num_son );
|
||||||
|
}
|
||||||
|
|
||||||
|
// If num_son of the operation are valid, they should merge the existing data
|
||||||
|
if ( o.new_options )
|
||||||
|
{
|
||||||
|
const auto new_options = *o.new_options;
|
||||||
|
|
||||||
|
if ( new_options.extensions.value.num_son.valid() )
|
||||||
|
{
|
||||||
|
merge_num_sons( new_num_son, *new_options.extensions.value.num_son );
|
||||||
|
}
|
||||||
|
|
||||||
|
a.options = *o.new_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.options.extensions.value.num_son = new_num_son;
|
||||||
|
|
||||||
if( o.extensions.value.owner_special_authority.valid() )
|
if( o.extensions.value.owner_special_authority.valid() )
|
||||||
{
|
{
|
||||||
a.owner_special_authority = *(o.extensions.value.owner_special_authority);
|
a.owner_special_authority = *(o.extensions.value.owner_special_authority);
|
||||||
|
|
|
||||||
|
|
@ -33,149 +33,163 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
void_result transfer_to_blind_evaluator::do_evaluate( const transfer_to_blind_operation& o )
|
void_result transfer_to_blind_evaluator::do_evaluate( const transfer_to_blind_operation& o )
|
||||||
{ try {
|
{ try {
|
||||||
const auto& d = db();
|
const auto& d = db();
|
||||||
|
if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME )
|
||||||
|
{
|
||||||
|
const auto& atype = o.amount.asset_id(d);
|
||||||
|
FC_ASSERT( atype.allow_confidential() );
|
||||||
|
FC_ASSERT( !atype.is_transfer_restricted() );
|
||||||
|
FC_ASSERT( !(atype.options.flags & white_list) );
|
||||||
|
|
||||||
const auto& atype = o.amount.asset_id(db());
|
for( const auto& out : o.outputs )
|
||||||
FC_ASSERT( atype.allow_confidential() );
|
{
|
||||||
FC_ASSERT( !atype.is_transfer_restricted() );
|
for( const auto& a : out.owner.account_auths )
|
||||||
FC_ASSERT( !(atype.options.flags & white_list) );
|
a.first(d); // verify all accounts exist and are valid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for( const auto& out : o.outputs )
|
return void_result();
|
||||||
{
|
|
||||||
for( const auto& a : out.owner.account_auths )
|
|
||||||
a.first(d); // verify all accounts exist and are valid
|
|
||||||
}
|
|
||||||
return void_result();
|
|
||||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||||
|
|
||||||
|
|
||||||
void_result transfer_to_blind_evaluator::do_apply( const transfer_to_blind_operation& o )
|
void_result transfer_to_blind_evaluator::do_apply( const transfer_to_blind_operation& o )
|
||||||
{ try {
|
{ try {
|
||||||
db().adjust_balance( o.from, -o.amount );
|
if( db().head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
|
||||||
|
db().adjust_balance(o.from, -o.amount);
|
||||||
|
|
||||||
const auto& add = o.amount.asset_id(db()).dynamic_asset_data_id(db()); // verify fee is a legit asset
|
const auto &add = o.amount.asset_id(db()).dynamic_asset_data_id(db()); // verify fee is a legit asset
|
||||||
db().modify( add, [&]( asset_dynamic_data_object& obj ){
|
db().modify(add, [&](asset_dynamic_data_object &obj) {
|
||||||
obj.confidential_supply += o.amount.amount;
|
obj.confidential_supply += o.amount.amount;
|
||||||
FC_ASSERT( obj.confidential_supply >= 0 );
|
FC_ASSERT(obj.confidential_supply >= 0);
|
||||||
});
|
});
|
||||||
for( const auto& out : o.outputs )
|
for (const auto &out : o.outputs) {
|
||||||
{
|
db().create<blinded_balance_object>([&](blinded_balance_object &obj) {
|
||||||
db().create<blinded_balance_object>( [&]( blinded_balance_object& obj ){
|
obj.asset_id = o.amount.asset_id;
|
||||||
obj.asset_id = o.amount.asset_id;
|
obj.owner = out.owner;
|
||||||
obj.owner = out.owner;
|
obj.commitment = out.commitment;
|
||||||
obj.commitment = out.commitment;
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||||
|
|
||||||
void transfer_to_blind_evaluator::pay_fee()
|
void transfer_to_blind_evaluator::pay_fee()
|
||||||
{
|
{
|
||||||
if( db().head_block_time() >= HARDFORK_563_TIME )
|
const auto& d = db();
|
||||||
pay_fba_fee( fba_accumulator_id_transfer_to_blind );
|
if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
|
||||||
else
|
if (d.head_block_time() >= HARDFORK_563_TIME)
|
||||||
generic_evaluator::pay_fee();
|
pay_fba_fee(fba_accumulator_id_transfer_to_blind);
|
||||||
|
else
|
||||||
|
generic_evaluator::pay_fee();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void_result transfer_from_blind_evaluator::do_evaluate( const transfer_from_blind_operation& o )
|
void_result transfer_from_blind_evaluator::do_evaluate( const transfer_from_blind_operation& o )
|
||||||
{ try {
|
{ try {
|
||||||
const auto& d = db();
|
const auto& d = db();
|
||||||
o.fee.asset_id(d); // verify fee is a legit asset
|
if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
|
||||||
const auto& bbi = d.get_index_type<blinded_balance_index>();
|
o.fee.asset_id(d); // verify fee is a legit asset
|
||||||
const auto& cidx = bbi.indices().get<by_commitment>();
|
const auto &bbi = d.get_index_type<blinded_balance_index>();
|
||||||
for( const auto& in : o.inputs )
|
const auto &cidx = bbi.indices().get<by_commitment>();
|
||||||
{
|
for (const auto &in : o.inputs) {
|
||||||
auto itr = cidx.find( in.commitment );
|
auto itr = cidx.find(in.commitment);
|
||||||
FC_ASSERT( itr != cidx.end() );
|
FC_ASSERT(itr != cidx.end());
|
||||||
FC_ASSERT( itr->asset_id == o.fee.asset_id );
|
FC_ASSERT(itr->asset_id == o.fee.asset_id);
|
||||||
FC_ASSERT( itr->owner == in.owner );
|
FC_ASSERT(itr->owner == in.owner);
|
||||||
}
|
}
|
||||||
return void_result();
|
}
|
||||||
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||||
|
|
||||||
void_result transfer_from_blind_evaluator::do_apply( const transfer_from_blind_operation& o )
|
void_result transfer_from_blind_evaluator::do_apply( const transfer_from_blind_operation& o )
|
||||||
{ try {
|
{ try {
|
||||||
db().adjust_balance( o.fee_payer(), o.fee );
|
if( db().head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
|
||||||
db().adjust_balance( o.to, o.amount );
|
db().adjust_balance(o.fee_payer(), o.fee);
|
||||||
const auto& bbi = db().get_index_type<blinded_balance_index>();
|
db().adjust_balance(o.to, o.amount);
|
||||||
const auto& cidx = bbi.indices().get<by_commitment>();
|
const auto &bbi = db().get_index_type<blinded_balance_index>();
|
||||||
for( const auto& in : o.inputs )
|
const auto &cidx = bbi.indices().get<by_commitment>();
|
||||||
{
|
for (const auto &in : o.inputs) {
|
||||||
auto itr = cidx.find( in.commitment );
|
auto itr = cidx.find(in.commitment);
|
||||||
FC_ASSERT( itr != cidx.end() );
|
FC_ASSERT(itr != cidx.end());
|
||||||
db().remove( *itr );
|
db().remove(*itr);
|
||||||
}
|
}
|
||||||
const auto& add = o.amount.asset_id(db()).dynamic_asset_data_id(db()); // verify fee is a legit asset
|
const auto &add = o.amount.asset_id(db()).dynamic_asset_data_id(db()); // verify fee is a legit asset
|
||||||
db().modify( add, [&]( asset_dynamic_data_object& obj ){
|
db().modify(add, [&](asset_dynamic_data_object &obj) {
|
||||||
obj.confidential_supply -= o.amount.amount + o.fee.amount;
|
obj.confidential_supply -= o.amount.amount + o.fee.amount;
|
||||||
FC_ASSERT( obj.confidential_supply >= 0 );
|
FC_ASSERT(obj.confidential_supply >= 0);
|
||||||
});
|
});
|
||||||
return void_result();
|
}
|
||||||
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||||
|
|
||||||
void transfer_from_blind_evaluator::pay_fee()
|
void transfer_from_blind_evaluator::pay_fee()
|
||||||
{
|
{
|
||||||
if( db().head_block_time() >= HARDFORK_563_TIME )
|
const auto& d = db();
|
||||||
pay_fba_fee( fba_accumulator_id_transfer_from_blind );
|
if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
|
||||||
else
|
if (d.head_block_time() >= HARDFORK_563_TIME)
|
||||||
generic_evaluator::pay_fee();
|
pay_fba_fee(fba_accumulator_id_transfer_from_blind);
|
||||||
|
else
|
||||||
|
generic_evaluator::pay_fee();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void_result blind_transfer_evaluator::do_evaluate( const blind_transfer_operation& o )
|
void_result blind_transfer_evaluator::do_evaluate( const blind_transfer_operation& o )
|
||||||
{ try {
|
{ try {
|
||||||
const auto& d = db();
|
const auto& d = db();
|
||||||
o.fee.asset_id(db()); // verify fee is a legit asset
|
if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
|
||||||
const auto& bbi = db().get_index_type<blinded_balance_index>();
|
o.fee.asset_id(d); // verify fee is a legit asset
|
||||||
const auto& cidx = bbi.indices().get<by_commitment>();
|
const auto &bbi = d.get_index_type<blinded_balance_index>();
|
||||||
for( const auto& out : o.outputs )
|
const auto &cidx = bbi.indices().get<by_commitment>();
|
||||||
{
|
for (const auto &out : o.outputs) {
|
||||||
for( const auto& a : out.owner.account_auths )
|
for (const auto &a : out.owner.account_auths)
|
||||||
a.first(d); // verify all accounts exist and are valid
|
a.first(d); // verify all accounts exist and are valid
|
||||||
}
|
}
|
||||||
for( const auto& in : o.inputs )
|
for (const auto &in : o.inputs) {
|
||||||
{
|
auto itr = cidx.find(in.commitment);
|
||||||
auto itr = cidx.find( in.commitment );
|
GRAPHENE_ASSERT(itr != cidx.end(), blind_transfer_unknown_commitment, "", ("commitment", in.commitment));
|
||||||
GRAPHENE_ASSERT( itr != cidx.end(), blind_transfer_unknown_commitment, "", ("commitment",in.commitment) );
|
FC_ASSERT(itr->asset_id == o.fee.asset_id);
|
||||||
FC_ASSERT( itr->asset_id == o.fee.asset_id );
|
FC_ASSERT(itr->owner == in.owner);
|
||||||
FC_ASSERT( itr->owner == in.owner );
|
}
|
||||||
}
|
}
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||||
|
|
||||||
void_result blind_transfer_evaluator::do_apply( const blind_transfer_operation& o )
|
void_result blind_transfer_evaluator::do_apply( const blind_transfer_operation& o )
|
||||||
{ try {
|
{ try {
|
||||||
db().adjust_balance( o.fee_payer(), o.fee ); // deposit the fee to the temp account
|
if( db().head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
|
||||||
const auto& bbi = db().get_index_type<blinded_balance_index>();
|
db().adjust_balance(o.fee_payer(), o.fee); // deposit the fee to the temp account
|
||||||
const auto& cidx = bbi.indices().get<by_commitment>();
|
const auto &bbi = db().get_index_type<blinded_balance_index>();
|
||||||
for( const auto& in : o.inputs )
|
const auto &cidx = bbi.indices().get<by_commitment>();
|
||||||
{
|
for (const auto &in : o.inputs) {
|
||||||
auto itr = cidx.find( in.commitment );
|
auto itr = cidx.find(in.commitment);
|
||||||
GRAPHENE_ASSERT( itr != cidx.end(), blind_transfer_unknown_commitment, "", ("commitment",in.commitment) );
|
GRAPHENE_ASSERT(itr != cidx.end(), blind_transfer_unknown_commitment, "", ("commitment", in.commitment));
|
||||||
db().remove( *itr );
|
db().remove(*itr);
|
||||||
}
|
}
|
||||||
for( const auto& out : o.outputs )
|
for (const auto &out : o.outputs) {
|
||||||
{
|
db().create<blinded_balance_object>([&](blinded_balance_object &obj) {
|
||||||
db().create<blinded_balance_object>( [&]( blinded_balance_object& obj ){
|
obj.asset_id = o.fee.asset_id;
|
||||||
obj.asset_id = o.fee.asset_id;
|
obj.owner = out.owner;
|
||||||
obj.owner = out.owner;
|
obj.commitment = out.commitment;
|
||||||
obj.commitment = out.commitment;
|
});
|
||||||
});
|
}
|
||||||
}
|
const auto &add = o.fee.asset_id(db()).dynamic_asset_data_id(db());
|
||||||
const auto& add = o.fee.asset_id(db()).dynamic_asset_data_id(db());
|
db().modify(add, [&](asset_dynamic_data_object &obj) {
|
||||||
db().modify( add, [&]( asset_dynamic_data_object& obj ){
|
obj.confidential_supply -= o.fee.amount;
|
||||||
obj.confidential_supply -= o.fee.amount;
|
FC_ASSERT(obj.confidential_supply >= 0);
|
||||||
FC_ASSERT( obj.confidential_supply >= 0 );
|
});
|
||||||
});
|
}
|
||||||
|
return void_result();
|
||||||
return void_result();
|
|
||||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||||
|
|
||||||
void blind_transfer_evaluator::pay_fee()
|
void blind_transfer_evaluator::pay_fee()
|
||||||
{
|
{
|
||||||
if( db().head_block_time() >= HARDFORK_563_TIME )
|
const auto& d = db();
|
||||||
pay_fba_fee( fba_accumulator_id_blind_transfer );
|
if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
|
||||||
else
|
if (d.head_block_time() >= HARDFORK_563_TIME)
|
||||||
generic_evaluator::pay_fee();
|
pay_fba_fee(fba_accumulator_id_blind_transfer);
|
||||||
|
else
|
||||||
|
generic_evaluator::pay_fee();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,10 @@
|
||||||
#include <graphene/chain/exceptions.hpp>
|
#include <graphene/chain/exceptions.hpp>
|
||||||
#include <graphene/chain/evaluator.hpp>
|
#include <graphene/chain/evaluator.hpp>
|
||||||
#include <graphene/chain/witness_schedule_object.hpp>
|
#include <graphene/chain/witness_schedule_object.hpp>
|
||||||
|
#include <graphene/db/object_database.hpp>
|
||||||
#include <fc/crypto/digest.hpp>
|
#include <fc/crypto/digest.hpp>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
|
@ -160,10 +162,13 @@ void database::check_transaction_for_duplicated_operations(const signed_transact
|
||||||
existed_operations_digests.insert( proposed_operations_digests.begin(), proposed_operations_digests.end() );
|
existed_operations_digests.insert( proposed_operations_digests.begin(), proposed_operations_digests.end() );
|
||||||
});
|
});
|
||||||
|
|
||||||
for (auto& pending_transaction: _pending_tx)
|
|
||||||
{
|
{
|
||||||
auto proposed_operations_digests = gather_proposed_operations_digests(pending_transaction);
|
const std::lock_guard<std::mutex> pending_tx_lock{_pending_tx_mutex};
|
||||||
existed_operations_digests.insert(proposed_operations_digests.begin(), proposed_operations_digests.end());
|
for (auto &pending_transaction : _pending_tx)
|
||||||
|
{
|
||||||
|
auto proposed_operations_digests = gather_proposed_operations_digests(pending_transaction);
|
||||||
|
existed_operations_digests.insert(proposed_operations_digests.begin(), proposed_operations_digests.end());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto proposed_operations_digests = gather_proposed_operations_digests(trx);
|
auto proposed_operations_digests = gather_proposed_operations_digests(trx);
|
||||||
|
|
@ -185,7 +190,12 @@ bool database::push_block(const signed_block& new_block, uint32_t skip)
|
||||||
bool result;
|
bool result;
|
||||||
detail::with_skip_flags( *this, skip, [&]()
|
detail::with_skip_flags( *this, skip, [&]()
|
||||||
{
|
{
|
||||||
detail::without_pending_transactions( *this, std::move(_pending_tx),
|
std::vector<processed_transaction> pending_tx = [this] {
|
||||||
|
const std::lock_guard<std::mutex> pending_tx_lock{_pending_tx_mutex};
|
||||||
|
return std::move(_pending_tx);
|
||||||
|
}();
|
||||||
|
|
||||||
|
detail::without_pending_transactions( *this, std::move(pending_tx),
|
||||||
[&]()
|
[&]()
|
||||||
{
|
{
|
||||||
result = _push_block(new_block);
|
result = _push_block(new_block);
|
||||||
|
|
@ -196,6 +206,9 @@ bool database::push_block(const signed_block& new_block, uint32_t skip)
|
||||||
|
|
||||||
bool database::_push_block(const signed_block& new_block)
|
bool database::_push_block(const signed_block& new_block)
|
||||||
{ try {
|
{ try {
|
||||||
|
boost::filesystem::space_info si = boost::filesystem::space(get_data_dir());
|
||||||
|
FC_ASSERT((si.available) > 104857600, "Rejecting block due to low disk space"); // 104857600 bytes = 100 MB
|
||||||
|
|
||||||
uint32_t skip = get_node_properties().skip_flags;
|
uint32_t skip = get_node_properties().skip_flags;
|
||||||
const auto now = fc::time_point::now().sec_since_epoch();
|
const auto now = fc::time_point::now().sec_since_epoch();
|
||||||
|
|
||||||
|
|
@ -382,17 +395,26 @@ processed_transaction database::_push_transaction( const signed_transaction& trx
|
||||||
{
|
{
|
||||||
// If this is the first transaction pushed after applying a block, start a new undo session.
|
// If this is the first transaction pushed after applying a block, start a new undo session.
|
||||||
// This allows us to quickly rewind to the clean state of the head block, in case a new block arrives.
|
// This allows us to quickly rewind to the clean state of the head block, in case a new block arrives.
|
||||||
if( !_pending_tx_session.valid() )
|
{
|
||||||
_pending_tx_session = _undo_db.start_undo_session();
|
const std::lock_guard<std::mutex> pending_tx_session_lock{_pending_tx_session_mutex};
|
||||||
|
if (!_pending_tx_session.valid()) {
|
||||||
|
const std::lock_guard<std::mutex> undo_db_lock{_undo_db_mutex};
|
||||||
|
_pending_tx_session = _undo_db.start_undo_session();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create a temporary undo session as a child of _pending_tx_session.
|
// Create a temporary undo session as a child of _pending_tx_session.
|
||||||
// The temporary session will be discarded by the destructor if
|
// The temporary session will be discarded by the destructor if
|
||||||
// _apply_transaction fails. If we make it to merge(), we
|
// _apply_transaction fails. If we make it to merge(), we
|
||||||
// apply the changes.
|
// apply the changes.
|
||||||
|
|
||||||
|
const std::lock_guard<std::mutex> undo_db_lock{_undo_db_mutex};
|
||||||
auto temp_session = _undo_db.start_undo_session();
|
auto temp_session = _undo_db.start_undo_session();
|
||||||
auto processed_trx = _apply_transaction( trx );
|
auto processed_trx = _apply_transaction(trx);
|
||||||
_pending_tx.push_back(processed_trx);
|
{
|
||||||
|
const std::lock_guard<std::mutex> pending_tx_lock{_pending_tx_mutex};
|
||||||
|
_pending_tx.push_back(processed_trx);
|
||||||
|
}
|
||||||
|
|
||||||
// notify_changed_objects();
|
// notify_changed_objects();
|
||||||
// The transaction applied successfully. Merge its changes into the pending block session.
|
// The transaction applied successfully. Merge its changes into the pending block session.
|
||||||
|
|
@ -405,6 +427,7 @@ processed_transaction database::_push_transaction( const signed_transaction& trx
|
||||||
|
|
||||||
processed_transaction database::validate_transaction( const signed_transaction& trx )
|
processed_transaction database::validate_transaction( const signed_transaction& trx )
|
||||||
{
|
{
|
||||||
|
const std::lock_guard<std::mutex> undo_db_lock{_undo_db_mutex};
|
||||||
auto session = _undo_db.start_undo_session();
|
auto session = _undo_db.start_undo_session();
|
||||||
return _apply_transaction( trx );
|
return _apply_transaction( trx );
|
||||||
}
|
}
|
||||||
|
|
@ -504,47 +527,52 @@ signed_block database::_generate_block(
|
||||||
// the value of the "when" variable is known, which means we need to
|
// the value of the "when" variable is known, which means we need to
|
||||||
// re-apply pending transactions in this method.
|
// re-apply pending transactions in this method.
|
||||||
//
|
//
|
||||||
_pending_tx_session.reset();
|
{
|
||||||
_pending_tx_session = _undo_db.start_undo_session();
|
const std::lock_guard<std::mutex> pending_tx_session_lock{_pending_tx_session_mutex};
|
||||||
|
_pending_tx_session.reset();
|
||||||
|
_pending_tx_session = _undo_db.start_undo_session();
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t postponed_tx_count = 0;
|
uint64_t postponed_tx_count = 0;
|
||||||
// pop pending state (reset to head block state)
|
// pop pending state (reset to head block state)
|
||||||
for( const processed_transaction& tx : _pending_tx )
|
|
||||||
{
|
{
|
||||||
size_t new_total_size = total_block_size + fc::raw::pack_size( tx );
|
const std::lock_guard<std::mutex> pending_tx_lock{_pending_tx_mutex};
|
||||||
|
for (const processed_transaction &tx : _pending_tx) {
|
||||||
|
size_t new_total_size = total_block_size + fc::raw::pack_size(tx);
|
||||||
|
|
||||||
// postpone transaction if it would make block too big
|
// postpone transaction if it would make block too big
|
||||||
if( new_total_size >= maximum_block_size )
|
if (new_total_size >= maximum_block_size) {
|
||||||
{
|
postponed_tx_count++;
|
||||||
postponed_tx_count++;
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
auto temp_session = _undo_db.start_undo_session();
|
||||||
auto temp_session = _undo_db.start_undo_session();
|
processed_transaction ptx = _apply_transaction(tx);
|
||||||
processed_transaction ptx = _apply_transaction( tx );
|
temp_session.merge();
|
||||||
temp_session.merge();
|
|
||||||
|
|
||||||
// We have to recompute pack_size(ptx) because it may be different
|
// We have to recompute pack_size(ptx) because it may be different
|
||||||
// than pack_size(tx) (i.e. if one or more results increased
|
// than pack_size(tx) (i.e. if one or more results increased
|
||||||
// their size)
|
// their size)
|
||||||
total_block_size += fc::raw::pack_size( ptx );
|
total_block_size += fc::raw::pack_size(ptx);
|
||||||
pending_block.transactions.push_back( ptx );
|
pending_block.transactions.push_back(ptx);
|
||||||
}
|
} catch (const fc::exception &e) {
|
||||||
catch ( const fc::exception& e )
|
// Do nothing, transaction will not be re-applied
|
||||||
{
|
wlog("Transaction was not processed while generating block due to ${e}", ("e", e));
|
||||||
// Do nothing, transaction will not be re-applied
|
wlog("The transaction was ${t}", ("t", tx));
|
||||||
wlog( "Transaction was not processed while generating block due to ${e}", ("e", e) );
|
}
|
||||||
wlog( "The transaction was ${t}", ("t", tx) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( postponed_tx_count > 0 )
|
if( postponed_tx_count > 0 )
|
||||||
{
|
{
|
||||||
wlog( "Postponed ${n} transactions due to block size limit", ("n", postponed_tx_count) );
|
wlog( "Postponed ${n} transactions due to block size limit", ("n", postponed_tx_count) );
|
||||||
}
|
}
|
||||||
|
|
||||||
_pending_tx_session.reset();
|
{
|
||||||
|
const std::lock_guard<std::mutex> pending_tx_session_lock{_pending_tx_session_mutex};
|
||||||
|
_pending_tx_session.reset();
|
||||||
|
}
|
||||||
|
|
||||||
// We have temporarily broken the invariant that
|
// We have temporarily broken the invariant that
|
||||||
// _pending_tx_session is the result of applying _pending_tx, as
|
// _pending_tx_session is the result of applying _pending_tx, as
|
||||||
|
|
@ -592,7 +620,11 @@ signed_block database::_generate_block(
|
||||||
*/
|
*/
|
||||||
void database::pop_block()
|
void database::pop_block()
|
||||||
{ try {
|
{ try {
|
||||||
_pending_tx_session.reset();
|
{
|
||||||
|
const std::lock_guard<std::mutex> pending_tx_session_lock{_pending_tx_session_mutex};
|
||||||
|
_pending_tx_session.reset();
|
||||||
|
}
|
||||||
|
|
||||||
auto head_id = head_block_id();
|
auto head_id = head_block_id();
|
||||||
optional<signed_block> head_block = fetch_block_by_id( head_id );
|
optional<signed_block> head_block = fetch_block_by_id( head_id );
|
||||||
GRAPHENE_ASSERT( head_block.valid(), pop_empty_chain, "there are no blocks to pop" );
|
GRAPHENE_ASSERT( head_block.valid(), pop_empty_chain, "there are no blocks to pop" );
|
||||||
|
|
@ -606,6 +638,8 @@ void database::pop_block()
|
||||||
|
|
||||||
void database::clear_pending()
|
void database::clear_pending()
|
||||||
{ try {
|
{ try {
|
||||||
|
const std::lock_guard<std::mutex> pending_tx_lock{_pending_tx_mutex};
|
||||||
|
const std::lock_guard<std::mutex> pending_tx_session_lock{_pending_tx_session_mutex};
|
||||||
assert( (_pending_tx.size() == 0) || _pending_tx_session.valid() );
|
assert( (_pending_tx.size() == 0) || _pending_tx_session.valid() );
|
||||||
_pending_tx.clear();
|
_pending_tx.clear();
|
||||||
_pending_tx_session.reset();
|
_pending_tx_session.reset();
|
||||||
|
|
@ -705,8 +739,11 @@ void database::_apply_block( const signed_block& next_block )
|
||||||
|
|
||||||
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM) {
|
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM) {
|
||||||
update_witness_schedule(next_block);
|
update_witness_schedule(next_block);
|
||||||
if(global_props.active_sons.size() > 0) {
|
|
||||||
update_son_schedule(next_block);
|
for(const auto& active_sons : global_props.active_sons) {
|
||||||
|
if(!active_sons.second.empty()) {
|
||||||
|
update_son_schedule(active_sons.first, next_block);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -721,7 +758,7 @@ void database::_apply_block( const signed_block& next_block )
|
||||||
|
|
||||||
check_ending_lotteries();
|
check_ending_lotteries();
|
||||||
check_ending_nft_lotteries();
|
check_ending_nft_lotteries();
|
||||||
|
|
||||||
create_block_summary(next_block);
|
create_block_summary(next_block);
|
||||||
place_delayed_bets(); // must happen after update_global_dynamic_data() updates the time
|
place_delayed_bets(); // must happen after update_global_dynamic_data() updates the time
|
||||||
clear_expired_transactions();
|
clear_expired_transactions();
|
||||||
|
|
@ -739,11 +776,15 @@ void database::_apply_block( const signed_block& next_block )
|
||||||
// TODO: figure out if we could collapse this function into
|
// TODO: figure out if we could collapse this function into
|
||||||
// update_global_dynamic_data() as perhaps these methods only need
|
// update_global_dynamic_data() as perhaps these methods only need
|
||||||
// to be called for header validation?
|
// to be called for header validation?
|
||||||
|
|
||||||
update_maintenance_flag( maint_needed );
|
update_maintenance_flag( maint_needed );
|
||||||
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM) {
|
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM) {
|
||||||
update_witness_schedule();
|
update_witness_schedule();
|
||||||
if(global_props.active_sons.size() > 0) {
|
|
||||||
update_son_schedule();
|
for(const auto& active_sidechain_type : active_sidechain_types(dynamic_global_props.time)) {
|
||||||
|
if(global_props.active_sons.at(active_sidechain_type).size() > 0) {
|
||||||
|
update_son_schedule(active_sidechain_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -222,17 +222,32 @@ std::set<son_id_type> database::get_sons_to_be_deregistered()
|
||||||
|
|
||||||
for( auto& son : son_idx )
|
for( auto& son : son_idx )
|
||||||
{
|
{
|
||||||
if(son.status == son_status::in_maintenance)
|
bool need_to_be_deregistered = true;
|
||||||
|
for(const auto& status : son.statuses)
|
||||||
{
|
{
|
||||||
auto stats = son.statistics(*this);
|
const auto& sidechain = status.first;
|
||||||
// TODO : We need to add a function that returns if we can deregister SON
|
if(status.second != son_status::in_maintenance)
|
||||||
// i.e. with introduction of PW code, we have to make a decision if the SON
|
need_to_be_deregistered = false;
|
||||||
// is needed for release of funds from the PW
|
|
||||||
if(head_block_time() - stats.last_down_timestamp >= fc::seconds(get_global_properties().parameters.son_deregister_time()))
|
if(need_to_be_deregistered)
|
||||||
{
|
{
|
||||||
ret.insert(son.id);
|
auto stats = son.statistics(*this);
|
||||||
|
|
||||||
|
// TODO : We need to add a function that returns if we can deregister SON
|
||||||
|
// i.e. with introduction of PW code, we have to make a decision if the SON
|
||||||
|
// is needed for release of funds from the PW
|
||||||
|
if(stats.last_active_timestamp.contains(sidechain)) {
|
||||||
|
if (head_block_time() - stats.last_active_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time())) {
|
||||||
|
need_to_be_deregistered = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(need_to_be_deregistered)
|
||||||
|
{
|
||||||
|
ret.insert(son.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -289,28 +304,50 @@ bool database::is_son_dereg_valid( son_id_type son_id )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (son->status == son_status::in_maintenance &&
|
bool status_son_dereg_valid = true;
|
||||||
(head_block_time() - son->statistics(*this).last_down_timestamp >= fc::seconds(get_global_properties().parameters.son_deregister_time())));
|
for (const auto &active_sidechain_type : active_sidechain_types(head_block_time())) {
|
||||||
|
if(son->statuses.at(active_sidechain_type) != son_status::in_maintenance)
|
||||||
|
status_son_dereg_valid = false;
|
||||||
|
|
||||||
|
if(status_son_dereg_valid)
|
||||||
|
{
|
||||||
|
if(son->statistics(*this).last_active_timestamp.contains(active_sidechain_type)) {
|
||||||
|
if (head_block_time() - son->statistics(*this).last_active_timestamp.at(active_sidechain_type) < fc::seconds(get_global_properties().parameters.son_deregister_time())) {
|
||||||
|
status_son_dereg_valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status_son_dereg_valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool database::is_son_active( son_id_type son_id )
|
bool database::is_son_active( sidechain_type type, son_id_type son_id )
|
||||||
{
|
{
|
||||||
const auto& son_idx = get_index_type<son_index>().indices().get< by_id >();
|
const auto& son_idx = get_index_type<son_index>().indices().get< by_id >();
|
||||||
auto son = son_idx.find( son_id );
|
auto son = son_idx.find( son_id );
|
||||||
if(son == son_idx.end())
|
if(son == son_idx.end()) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const global_property_object& gpo = get_global_properties();
|
const global_property_object& gpo = get_global_properties();
|
||||||
|
if(!gpo.active_sons.contains(type)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& gpo_as = gpo.active_sons.at(type);
|
||||||
vector<son_id_type> active_son_ids;
|
vector<son_id_type> active_son_ids;
|
||||||
active_son_ids.reserve(gpo.active_sons.size());
|
active_son_ids.reserve(gpo_as.size());
|
||||||
std::transform(gpo.active_sons.begin(), gpo.active_sons.end(),
|
std::transform(gpo_as.cbegin(), gpo_as.cend(),
|
||||||
std::inserter(active_son_ids, active_son_ids.end()),
|
std::inserter(active_son_ids, active_son_ids.end()),
|
||||||
[](const son_info& swi) {
|
[](const son_sidechain_info& swi) {
|
||||||
return swi.son_id;
|
return swi.son_id;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(active_son_ids.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto it_son = std::find(active_son_ids.begin(), active_son_ids.end(), son_id);
|
auto it_son = std::find(active_son_ids.begin(), active_son_ids.end(), son_id);
|
||||||
return (it_son != active_son_ids.end());
|
return (it_son != active_son_ids.end());
|
||||||
}
|
}
|
||||||
|
|
@ -349,23 +386,14 @@ vector<uint64_t> database::get_random_numbers(uint64_t minimum, uint64_t maximum
|
||||||
|
|
||||||
bool database::is_asset_creation_allowed(const string &symbol)
|
bool database::is_asset_creation_allowed(const string &symbol)
|
||||||
{
|
{
|
||||||
time_point_sec now = head_block_time();
|
|
||||||
std::unordered_set<std::string> post_son_hf_symbols = {"ETH", "USDT", "BNB", "ADA", "DOGE", "XRP", "USDC", "DOT", "UNI", "BUSD", "BCH", "LTC", "SOL", "LINK", "MATIC", "THETA",
|
|
||||||
"WBTC", "XLM", "ICP", "DAI", "VET", "ETC", "TRX", "FIL", "XMR", "EGR", "EOS", "SHIB", "AAVE", "CRO", "ALGO", "AMP", "BTCB",
|
|
||||||
"BSV", "KLAY", "CAKE", "FTT", "LEO", "XTZ", "TFUEL", "MIOTA", "LUNA", "NEO", "ATOM", "MKR", "FEI", "WBNB", "UST", "AVAX",
|
|
||||||
"STEEM", "HIVE", "HBD", "SBD", "BTS"};
|
|
||||||
if (symbol == "BTC")
|
if (symbol == "BTC")
|
||||||
{
|
{
|
||||||
if (now < HARDFORK_SON_TIME)
|
if (head_block_time() < HARDFORK_SON_TIME)
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (post_son_hf_symbols.find(symbol) != post_son_hf_symbols.end())
|
|
||||||
{
|
|
||||||
if (now >= HARDFORK_SON_TIME)
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} }
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -329,10 +329,54 @@ void database::initialize_evaluators()
|
||||||
register_evaluator<random_number_store_evaluator>();
|
register_evaluator<random_number_store_evaluator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void database::initialize_hardforks()
|
||||||
|
{
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_357_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_359_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_385_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_409_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_413_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_415_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_416_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_419_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_436_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_445_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_453_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_480_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_483_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_516_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_533_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_538_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_555_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_563_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_572_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_599_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_607_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_613_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_615_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_999_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_1000_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_1001_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_5050_1_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_CORE_429_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_GPOS_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_NFT_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_SON_FOR_HIVE_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_SON_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_SON2_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_SON_FOR_ETHEREUM_TIME);
|
||||||
|
_hardfork_times.emplace_back(HARDFORK_SWEEPS_TIME);
|
||||||
|
|
||||||
|
std::sort(_hardfork_times.begin(), _hardfork_times.end());
|
||||||
|
}
|
||||||
|
|
||||||
void database::initialize_indexes()
|
void database::initialize_indexes()
|
||||||
{
|
{
|
||||||
reset_indexes();
|
reset_indexes();
|
||||||
_undo_db.set_max_size( GRAPHENE_MIN_UNDO_HISTORY );
|
|
||||||
|
const std::lock_guard<std::mutex> undo_db_lock{_undo_db_mutex};
|
||||||
|
_undo_db.set_max_size(GRAPHENE_MIN_UNDO_HISTORY);
|
||||||
|
|
||||||
//Protocol object indexes
|
//Protocol object indexes
|
||||||
add_index< primary_index<asset_index, 13> >(); // 8192 assets per chunk
|
add_index< primary_index<asset_index, 13> >(); // 8192 assets per chunk
|
||||||
|
|
@ -432,7 +476,9 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
||||||
FC_ASSERT(genesis_state.initial_active_witnesses <= genesis_state.initial_witness_candidates.size(),
|
FC_ASSERT(genesis_state.initial_active_witnesses <= genesis_state.initial_witness_candidates.size(),
|
||||||
"initial_active_witnesses is larger than the number of candidate witnesses.");
|
"initial_active_witnesses is larger than the number of candidate witnesses.");
|
||||||
|
|
||||||
|
const std::lock_guard<std::mutex> undo_db_lock{_undo_db_mutex};
|
||||||
_undo_db.disable();
|
_undo_db.disable();
|
||||||
|
|
||||||
struct auth_inhibitor {
|
struct auth_inhibitor {
|
||||||
auth_inhibitor(database& db) : db(db), old_flags(db.node_properties().skip_flags)
|
auth_inhibitor(database& db) : db(db), old_flags(db.node_properties().skip_flags)
|
||||||
{ db.node_properties().skip_flags |= skip_authority_check; }
|
{ db.node_properties().skip_flags |= skip_authority_check; }
|
||||||
|
|
@ -1058,8 +1104,9 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
||||||
FC_ASSERT( _p_witness_schedule_obj->id == witness_schedule_id_type() );
|
FC_ASSERT( _p_witness_schedule_obj->id == witness_schedule_id_type() );
|
||||||
|
|
||||||
// Initialize witness schedule
|
// Initialize witness schedule
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const son_schedule_object& sso =
|
const son_schedule_object& ssobitcoin =
|
||||||
#endif
|
#endif
|
||||||
create<son_schedule_object>([&](son_schedule_object& _sso)
|
create<son_schedule_object>([&](son_schedule_object& _sso)
|
||||||
{
|
{
|
||||||
|
|
@ -1068,24 +1115,64 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
||||||
|
|
||||||
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
|
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
|
||||||
|
|
||||||
auto init_witnesses = get_global_properties().active_witnesses;
|
auto init_bitcoin_sons = get_global_properties().active_sons.at(sidechain_type::bitcoin);
|
||||||
|
|
||||||
_sso.scheduler = son_scheduler();
|
_sso.scheduler = son_scheduler();
|
||||||
_sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1);
|
_sso.scheduler._min_token_count = std::max(int(init_bitcoin_sons.size()) / 2, 1);
|
||||||
|
|
||||||
|
|
||||||
_sso.last_scheduling_block = 0;
|
_sso.last_scheduling_block = 0;
|
||||||
|
|
||||||
_sso.recent_slots_filled = fc::uint128::max_value();
|
_sso.recent_slots_filled = fc::uint128::max_value();
|
||||||
});
|
});
|
||||||
assert( sso.id == son_schedule_id_type() );
|
assert( ssobitcoin.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::bitcoin)) );
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
const son_schedule_object& ssoethereum =
|
||||||
|
#endif
|
||||||
|
create<son_schedule_object>([&](son_schedule_object& _sso)
|
||||||
|
{
|
||||||
|
// for scheduled
|
||||||
|
memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size());
|
||||||
|
|
||||||
|
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
|
||||||
|
|
||||||
|
auto init_ethereum_sons = get_global_properties().active_sons.at(sidechain_type::ethereum);
|
||||||
|
|
||||||
|
_sso.scheduler = son_scheduler();
|
||||||
|
_sso.scheduler._min_token_count = std::max(int(init_ethereum_sons.size()) / 2, 1);
|
||||||
|
|
||||||
|
_sso.last_scheduling_block = 0;
|
||||||
|
|
||||||
|
_sso.recent_slots_filled = fc::uint128::max_value();
|
||||||
|
});
|
||||||
|
assert( ssoethereum.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::ethereum)) );
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
const son_schedule_object& ssohive =
|
||||||
|
#endif
|
||||||
|
create<son_schedule_object>([&](son_schedule_object& _sso)
|
||||||
|
{
|
||||||
|
// for scheduled
|
||||||
|
memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size());
|
||||||
|
|
||||||
|
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
|
||||||
|
|
||||||
|
auto init_hive_sons = get_global_properties().active_sons.at(sidechain_type::hive);
|
||||||
|
|
||||||
|
_sso.scheduler = son_scheduler();
|
||||||
|
_sso.scheduler._min_token_count = std::max(int(init_hive_sons.size()) / 2, 1);
|
||||||
|
|
||||||
|
_sso.last_scheduling_block = 0;
|
||||||
|
|
||||||
|
_sso.recent_slots_filled = fc::uint128::max_value();
|
||||||
|
});
|
||||||
|
assert( ssohive.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::hive)) );
|
||||||
|
|
||||||
// Enable fees
|
// Enable fees
|
||||||
modify(get_global_properties(), [&genesis_state](global_property_object& p) {
|
modify(get_global_properties(), [&genesis_state](global_property_object& p) {
|
||||||
p.parameters.current_fees = genesis_state.initial_parameters.current_fees;
|
p.parameters.current_fees = genesis_state.initial_parameters.current_fees;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Create FBA counters
|
// Create FBA counters
|
||||||
create<fba_accumulator_object>([&]( fba_accumulator_object& acc )
|
create<fba_accumulator_object>([&]( fba_accumulator_object& acc )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -44,6 +44,7 @@ database::database() :
|
||||||
{
|
{
|
||||||
initialize_indexes();
|
initialize_indexes();
|
||||||
initialize_evaluators();
|
initialize_evaluators();
|
||||||
|
initialize_hardforks();
|
||||||
}
|
}
|
||||||
|
|
||||||
database::~database()
|
database::~database()
|
||||||
|
|
|
||||||
|
|
@ -203,27 +203,10 @@ struct get_impacted_account_visitor
|
||||||
_impacted.insert( op.issuer );
|
_impacted.insert( op.issuer );
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()( const transfer_to_blind_operation& op )
|
//! We don't use this operations
|
||||||
{
|
void operator()( const transfer_to_blind_operation& op ){}
|
||||||
_impacted.insert( op.from );
|
void operator()( const blind_transfer_operation& op ){}
|
||||||
for( const auto& out : op.outputs )
|
void operator()( const transfer_from_blind_operation& op ){}
|
||||||
add_authority_accounts( _impacted, out.owner );
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()( const blind_transfer_operation& op )
|
|
||||||
{
|
|
||||||
for( const auto& in : op.inputs )
|
|
||||||
add_authority_accounts( _impacted, in.owner );
|
|
||||||
for( const auto& out : op.outputs )
|
|
||||||
add_authority_accounts( _impacted, out.owner );
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()( const transfer_from_blind_operation& op )
|
|
||||||
{
|
|
||||||
_impacted.insert( op.to );
|
|
||||||
for( const auto& in : op.inputs )
|
|
||||||
add_authority_accounts( _impacted, in.owner );
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()( const asset_settle_cancel_operation& op )
|
void operator()( const asset_settle_cancel_operation& op )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -74,21 +74,32 @@ witness_id_type database::get_scheduled_witness( uint32_t slot_num )const
|
||||||
return wid;
|
return wid;
|
||||||
}
|
}
|
||||||
|
|
||||||
son_id_type database::get_scheduled_son( uint32_t slot_num )const
|
unsigned_int database::get_son_schedule_id( sidechain_type type )const
|
||||||
|
{
|
||||||
|
static const map<sidechain_type, unsigned_int> schedule_map = {
|
||||||
|
{ sidechain_type::bitcoin, 0 },
|
||||||
|
{ sidechain_type::ethereum, 1 },
|
||||||
|
{ sidechain_type::hive, 2 }
|
||||||
|
};
|
||||||
|
|
||||||
|
return schedule_map.at(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
son_id_type database::get_scheduled_son( sidechain_type type, uint32_t slot_num )const
|
||||||
{
|
{
|
||||||
son_id_type sid;
|
son_id_type sid;
|
||||||
const global_property_object& gpo = get_global_properties();
|
const global_property_object& gpo = get_global_properties();
|
||||||
if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM)
|
if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM)
|
||||||
{
|
{
|
||||||
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
||||||
const son_schedule_object& sso = son_schedule_id_type()(*this);
|
const son_schedule_object& sso = son_schedule_id_type(get_son_schedule_id(type))(*this);
|
||||||
uint64_t current_aslot = dpo.current_aslot + slot_num;
|
uint64_t current_aslot = dpo.current_aslot + slot_num;
|
||||||
return sso.current_shuffled_sons[ current_aslot % sso.current_shuffled_sons.size() ];
|
return sso.current_shuffled_sons[ current_aslot % sso.current_shuffled_sons.size() ];
|
||||||
}
|
}
|
||||||
if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM &&
|
if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM &&
|
||||||
slot_num != 0 )
|
slot_num != 0 )
|
||||||
{
|
{
|
||||||
const son_schedule_object& sso = son_schedule_id_type()(*this);
|
const son_schedule_object& sso = son_schedule_id_type(get_son_schedule_id(type))(*this);
|
||||||
// ask the near scheduler who goes in the given slot
|
// ask the near scheduler who goes in the given slot
|
||||||
bool slot_is_near = sso.scheduler.get_slot(slot_num-1, sid);
|
bool slot_is_near = sso.scheduler.get_slot(slot_num-1, sid);
|
||||||
if(! slot_is_near)
|
if(! slot_is_near)
|
||||||
|
|
@ -189,36 +200,39 @@ void database::update_witness_schedule()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void database::update_son_schedule()
|
void database::update_son_schedule(sidechain_type type)
|
||||||
{
|
{
|
||||||
const son_schedule_object& sso = son_schedule_id_type()(*this);
|
|
||||||
const global_property_object& gpo = get_global_properties();
|
const global_property_object& gpo = get_global_properties();
|
||||||
|
|
||||||
if( head_block_num() % gpo.active_sons.size() == 0 )
|
const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(type)));
|
||||||
|
if( gpo.active_sons.at(type).size() != 0 &&
|
||||||
|
head_block_num() % gpo.active_sons.at(type).size() == 0)
|
||||||
{
|
{
|
||||||
modify( sso, [&]( son_schedule_object& _sso )
|
modify( sidechain_sso, [&]( son_schedule_object& _sso )
|
||||||
{
|
{
|
||||||
_sso.current_shuffled_sons.clear();
|
_sso.current_shuffled_sons.clear();
|
||||||
_sso.current_shuffled_sons.reserve( gpo.active_sons.size() );
|
_sso.current_shuffled_sons.reserve( gpo.active_sons.at(type).size() );
|
||||||
|
|
||||||
for( const son_info& w : gpo.active_sons )
|
for ( const auto &w : gpo.active_sons.at(type) ) {
|
||||||
_sso.current_shuffled_sons.push_back( w.son_id );
|
_sso.current_shuffled_sons.push_back(w.son_id);
|
||||||
|
}
|
||||||
|
|
||||||
auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32;
|
auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32;
|
||||||
for( uint32_t i = 0; i < _sso.current_shuffled_sons.size(); ++i )
|
|
||||||
|
for (uint32_t i = 0; i < _sso.current_shuffled_sons.size(); ++i)
|
||||||
{
|
{
|
||||||
/// High performance random generator
|
/// High performance random generator
|
||||||
/// http://xorshift.di.unimi.it/
|
/// http://xorshift.di.unimi.it/
|
||||||
uint64_t k = now_hi + uint64_t(i)*2685821657736338717ULL;
|
uint64_t k = now_hi + uint64_t(i) * 2685821657736338717ULL;
|
||||||
k ^= (k >> 12);
|
k ^= (k >> 12);
|
||||||
k ^= (k << 25);
|
k ^= (k << 25);
|
||||||
k ^= (k >> 27);
|
k ^= (k >> 27);
|
||||||
k *= 2685821657736338717ULL;
|
k *= 2685821657736338717ULL;
|
||||||
|
|
||||||
uint32_t jmax = _sso.current_shuffled_sons.size() - i;
|
uint32_t jmax = _sso.current_shuffled_sons.size() - i;
|
||||||
uint32_t j = i + k%jmax;
|
uint32_t j = i + k % jmax;
|
||||||
std::swap( _sso.current_shuffled_sons[i],
|
std::swap(_sso.current_shuffled_sons[i],
|
||||||
_sso.current_shuffled_sons[j] );
|
_sso.current_shuffled_sons[j]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -304,13 +318,15 @@ void database::update_witness_schedule(const signed_block& next_block)
|
||||||
idump( ( double(total_time/1000000.0)/calls) );
|
idump( ( double(total_time/1000000.0)/calls) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void database::update_son_schedule(const signed_block& next_block)
|
void database::update_son_schedule(sidechain_type type, const signed_block& next_block)
|
||||||
{
|
{
|
||||||
auto start = fc::time_point::now();
|
auto start = fc::time_point::now();
|
||||||
const global_property_object& gpo = get_global_properties();
|
#ifndef NDEBUG
|
||||||
const son_schedule_object& sso = get(son_schedule_id_type());
|
const son_schedule_object& sso = get(son_schedule_id_type());
|
||||||
uint32_t schedule_needs_filled = gpo.active_sons.size();
|
#endif
|
||||||
uint32_t schedule_slot = get_slot_at_time(next_block.timestamp);
|
const global_property_object& gpo = get_global_properties();
|
||||||
|
const uint32_t schedule_needs_filled = gpo.active_sons.at(type).size();
|
||||||
|
const uint32_t schedule_slot = get_slot_at_time(next_block.timestamp);
|
||||||
|
|
||||||
// We shouldn't be able to generate _pending_block with timestamp
|
// We shouldn't be able to generate _pending_block with timestamp
|
||||||
// in the past, and incoming blocks from the network with timestamp
|
// in the past, and incoming blocks from the network with timestamp
|
||||||
|
|
@ -319,48 +335,49 @@ void database::update_son_schedule(const signed_block& next_block)
|
||||||
|
|
||||||
assert( schedule_slot > 0 );
|
assert( schedule_slot > 0 );
|
||||||
|
|
||||||
son_id_type first_son;
|
|
||||||
bool slot_is_near = sso.scheduler.get_slot( schedule_slot-1, first_son );
|
|
||||||
|
|
||||||
son_id_type son;
|
|
||||||
|
|
||||||
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
||||||
|
|
||||||
assert( dpo.random.data_size() == witness_scheduler_rng::seed_length );
|
assert( dpo.random.data_size() == witness_scheduler_rng::seed_length );
|
||||||
assert( witness_scheduler_rng::seed_length == sso.rng_seed.size() );
|
assert( witness_scheduler_rng::seed_length == sso.rng_seed.size() );
|
||||||
|
|
||||||
modify(sso, [&](son_schedule_object& _sso)
|
const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(type)));
|
||||||
|
son_id_type first_son;
|
||||||
|
bool slot_is_near = sidechain_sso.scheduler.get_slot( schedule_slot-1, first_son );
|
||||||
|
son_id_type son_id;
|
||||||
|
|
||||||
|
modify(sidechain_sso, [&](son_schedule_object& _sso)
|
||||||
{
|
{
|
||||||
_sso.slots_since_genesis += schedule_slot;
|
_sso.slots_since_genesis += schedule_slot;
|
||||||
witness_scheduler_rng rng(sso.rng_seed.data, _sso.slots_since_genesis);
|
witness_scheduler_rng rng(_sso.rng_seed.data, _sso.slots_since_genesis);
|
||||||
|
|
||||||
_sso.scheduler._min_token_count = std::max(int(gpo.active_sons.size()) / 2, 1);
|
_sso.scheduler._min_token_count = std::max(int(gpo.active_sons.at(type).size()) / 2, 1);
|
||||||
|
|
||||||
if( slot_is_near )
|
if( slot_is_near )
|
||||||
{
|
{
|
||||||
uint32_t drain = schedule_slot;
|
uint32_t drain = schedule_slot;
|
||||||
while( drain > 0 )
|
while( drain > 0 )
|
||||||
{
|
{
|
||||||
if( _sso.scheduler.size() == 0 )
|
if( _sso.scheduler.size() == 0 )
|
||||||
break;
|
break;
|
||||||
_sso.scheduler.consume_schedule();
|
_sso.scheduler.consume_schedule();
|
||||||
--drain;
|
--drain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_sso.scheduler.reset_schedule( first_son );
|
_sso.scheduler.reset_schedule( first_son );
|
||||||
}
|
}
|
||||||
while( !_sso.scheduler.get_slot(schedule_needs_filled, son) )
|
while( !_sso.scheduler.get_slot(schedule_needs_filled, son_id) )
|
||||||
{
|
{
|
||||||
if( _sso.scheduler.produce_schedule(rng) & emit_turn )
|
if( _sso.scheduler.produce_schedule(rng) & emit_turn )
|
||||||
memcpy(_sso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size());
|
memcpy(_sso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size());
|
||||||
}
|
}
|
||||||
_sso.last_scheduling_block = next_block.block_num();
|
_sso.last_scheduling_block = next_block.block_num();
|
||||||
_sso.recent_slots_filled = (
|
_sso.recent_slots_filled = (
|
||||||
(_sso.recent_slots_filled << 1)
|
(_sso.recent_slots_filled << 1)
|
||||||
+ 1) << (schedule_slot - 1);
|
+ 1) << (schedule_slot - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto end = fc::time_point::now();
|
auto end = fc::time_point::now();
|
||||||
static uint64_t total_time = 0;
|
static uint64_t total_time = 0;
|
||||||
static uint64_t calls = 0;
|
static uint64_t calls = 0;
|
||||||
|
|
|
||||||
7
libraries/chain/hardfork.d/HOTFIX_2024.hf
Normal file
7
libraries/chain/hardfork.d/HOTFIX_2024.hf
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef HARDFORK_HOTFIX_2024_TIME
|
||||||
|
#ifdef BUILD_PEERPLAYS_TESTNET
|
||||||
|
#define HARDFORK_HOTFIX_2024_TIME (fc::time_point_sec::from_iso_string("2023-12-20T00:00:00"))
|
||||||
|
#else
|
||||||
|
#define HARDFORK_HOTFIX_2024_TIME (fc::time_point_sec::from_iso_string("2023-12-20T00:00:00"))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
#ifndef HARDFORK_SON3_TIME
|
|
||||||
#ifdef BUILD_PEERPLAYS_TESTNET
|
|
||||||
#define HARDFORK_SON3_TIME (fc::time_point_sec::from_iso_string("2022-07-16T00:00:00"))
|
|
||||||
#else
|
|
||||||
#define HARDFORK_SON3_TIME (fc::time_point_sec::from_iso_string("2022-07-16T00:00:00"))
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
7
libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf
Normal file
7
libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef HARDFORK_SON_FOR_ETHEREUM_TIME
|
||||||
|
#ifdef BUILD_PEERPLAYS_TESTNET
|
||||||
|
#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2023-07-17T12:00:00"))
|
||||||
|
#else
|
||||||
|
#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2023-10-24T12:00:00"))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
@ -158,7 +158,7 @@
|
||||||
#define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4
|
#define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4
|
||||||
#define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3
|
#define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3
|
||||||
|
|
||||||
#define GRAPHENE_CURRENT_DB_VERSION "PPY2.4"
|
#define GRAPHENE_CURRENT_DB_VERSION "PPY2.5"
|
||||||
|
|
||||||
#define GRAPHENE_IRREVERSIBLE_THRESHOLD (70 * GRAPHENE_1_PERCENT)
|
#define GRAPHENE_IRREVERSIBLE_THRESHOLD (70 * GRAPHENE_1_PERCENT)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ namespace graphene { namespace chain {
|
||||||
database();
|
database();
|
||||||
~database();
|
~database();
|
||||||
|
|
||||||
|
std::vector<fc::time_point_sec> _hardfork_times;
|
||||||
|
|
||||||
enum validation_steps
|
enum validation_steps
|
||||||
{
|
{
|
||||||
skip_nothing = 0,
|
skip_nothing = 0,
|
||||||
|
|
@ -243,7 +245,16 @@ namespace graphene { namespace chain {
|
||||||
witness_id_type get_scheduled_witness(uint32_t slot_num)const;
|
witness_id_type get_scheduled_witness(uint32_t slot_num)const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the son scheduled for block production in a slot.
|
* @brief Get son schedule id for the given sidechain_type.
|
||||||
|
*
|
||||||
|
* type sidechain_type we getting schedule.
|
||||||
|
*
|
||||||
|
* returns Id of the schedule object.
|
||||||
|
*/
|
||||||
|
unsigned_int get_son_schedule_id(sidechain_type type)const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the bitcoin or hive son scheduled for block production in a slot.
|
||||||
*
|
*
|
||||||
* slot_num always corresponds to a time in the future.
|
* slot_num always corresponds to a time in the future.
|
||||||
*
|
*
|
||||||
|
|
@ -256,7 +267,7 @@ namespace graphene { namespace chain {
|
||||||
*
|
*
|
||||||
* Passing slot_num == 0 returns GRAPHENE_NULL_WITNESS
|
* Passing slot_num == 0 returns GRAPHENE_NULL_WITNESS
|
||||||
*/
|
*/
|
||||||
son_id_type get_scheduled_son(uint32_t slot_num)const;
|
son_id_type get_scheduled_son(sidechain_type type, uint32_t slot_num)const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the time at which the given slot occurs.
|
* Get the time at which the given slot occurs.
|
||||||
|
|
@ -281,8 +292,8 @@ namespace graphene { namespace chain {
|
||||||
vector<witness_id_type> get_near_witness_schedule()const;
|
vector<witness_id_type> get_near_witness_schedule()const;
|
||||||
void update_witness_schedule();
|
void update_witness_schedule();
|
||||||
void update_witness_schedule(const signed_block& next_block);
|
void update_witness_schedule(const signed_block& next_block);
|
||||||
void update_son_schedule();
|
void update_son_schedule(sidechain_type type);
|
||||||
void update_son_schedule(const signed_block& next_block);
|
void update_son_schedule(sidechain_type type, const signed_block& next_block);
|
||||||
|
|
||||||
void check_lottery_end_by_participants( asset_id_type asset_id );
|
void check_lottery_end_by_participants( asset_id_type asset_id );
|
||||||
void check_ending_lotteries();
|
void check_ending_lotteries();
|
||||||
|
|
@ -311,7 +322,7 @@ namespace graphene { namespace chain {
|
||||||
fc::optional<operation> create_son_deregister_proposal( son_id_type son_id, account_id_type paying_son );
|
fc::optional<operation> create_son_deregister_proposal( son_id_type son_id, account_id_type paying_son );
|
||||||
signed_transaction create_signed_transaction( const fc::ecc::private_key& signing_private_key, const operation& op );
|
signed_transaction create_signed_transaction( const fc::ecc::private_key& signing_private_key, const operation& op );
|
||||||
bool is_son_dereg_valid( son_id_type son_id );
|
bool is_son_dereg_valid( son_id_type son_id );
|
||||||
bool is_son_active( son_id_type son_id );
|
bool is_son_active( sidechain_type type, son_id_type son_id );
|
||||||
bool is_asset_creation_allowed(const string& symbol);
|
bool is_asset_creation_allowed(const string& symbol);
|
||||||
|
|
||||||
time_point_sec head_block_time()const;
|
time_point_sec head_block_time()const;
|
||||||
|
|
@ -332,6 +343,8 @@ namespace graphene { namespace chain {
|
||||||
void initialize_evaluators();
|
void initialize_evaluators();
|
||||||
/// Reset the object graph in-memory
|
/// Reset the object graph in-memory
|
||||||
void initialize_indexes();
|
void initialize_indexes();
|
||||||
|
void initialize_hardforks();
|
||||||
|
|
||||||
void init_genesis(const genesis_state_type& genesis_state = genesis_state_type());
|
void init_genesis(const genesis_state_type& genesis_state = genesis_state_type());
|
||||||
|
|
||||||
template<typename EvaluatorType>
|
template<typename EvaluatorType>
|
||||||
|
|
@ -507,12 +520,16 @@ namespace graphene { namespace chain {
|
||||||
void notify_changed_objects();
|
void notify_changed_objects();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::mutex _pending_tx_session_mutex;
|
||||||
optional<undo_database::session> _pending_tx_session;
|
optional<undo_database::session> _pending_tx_session;
|
||||||
vector< unique_ptr<op_evaluator> > _operation_evaluators;
|
vector< unique_ptr<op_evaluator> > _operation_evaluators;
|
||||||
|
|
||||||
template<class Index>
|
template<class Index>
|
||||||
vector<std::reference_wrapper<const typename Index::object_type>> sort_votable_objects(size_t count)const;
|
vector<std::reference_wrapper<const typename Index::object_type>> sort_votable_objects(size_t count)const;
|
||||||
|
|
||||||
|
template<class Index>
|
||||||
|
vector<std::reference_wrapper<const typename Index::object_type>> sort_votable_objects(sidechain_type sidechain, size_t count)const;
|
||||||
|
|
||||||
//////////////////// db_block.cpp ////////////////////
|
//////////////////// db_block.cpp ////////////////////
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -562,19 +579,22 @@ namespace graphene { namespace chain {
|
||||||
void initialize_budget_record( fc::time_point_sec now, budget_record& rec )const;
|
void initialize_budget_record( fc::time_point_sec now, budget_record& rec )const;
|
||||||
void process_budget();
|
void process_budget();
|
||||||
void pay_workers( share_type& budget );
|
void pay_workers( share_type& budget );
|
||||||
void pay_sons();
|
void pay_sons_before_hf_ethereum();
|
||||||
|
void pay_sons_after_hf_ethereum();
|
||||||
void perform_son_tasks();
|
void perform_son_tasks();
|
||||||
void perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props);
|
void perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props);
|
||||||
void update_active_witnesses();
|
void update_active_witnesses();
|
||||||
void update_active_committee_members();
|
void update_active_committee_members();
|
||||||
void update_son_metrics( const vector<son_info>& curr_active_sons );
|
void update_son_metrics( const flat_map<sidechain_type, vector<son_sidechain_info> >& curr_active_sons );
|
||||||
void update_active_sons();
|
void update_active_sons();
|
||||||
void remove_son_proposal( const proposal_object& proposal );
|
void remove_son_proposal( const proposal_object& proposal );
|
||||||
void remove_inactive_son_down_proposals( const vector<son_id_type>& son_ids_to_remove );
|
void remove_inactive_son_down_proposals( const vector<son_id_type>& son_ids_to_remove );
|
||||||
void remove_inactive_son_proposals( const vector<son_id_type>& son_ids_to_remove );
|
void remove_inactive_son_proposals( const vector<son_id_type>& son_ids_to_remove );
|
||||||
void update_son_statuses( const vector<son_info>& cur_active_sons, const vector<son_info>& new_active_sons );
|
void update_son_statuses( const flat_map<sidechain_type, vector<son_sidechain_info> >& curr_active_sons,
|
||||||
void update_son_wallet( const vector<son_info>& new_active_sons );
|
const flat_map<sidechain_type, vector<son_sidechain_info> >& new_active_sons );
|
||||||
|
void update_son_wallet( const flat_map<sidechain_type, vector<son_sidechain_info> >& new_active_sons );
|
||||||
void update_worker_votes();
|
void update_worker_votes();
|
||||||
|
void hotfix_2024();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
double calculate_vesting_factor(const account_object& stake_account);
|
double calculate_vesting_factor(const account_object& stake_account);
|
||||||
|
|
@ -585,6 +605,7 @@ namespace graphene { namespace chain {
|
||||||
///@}
|
///@}
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
|
std::mutex _pending_tx_mutex;
|
||||||
vector< processed_transaction > _pending_tx;
|
vector< processed_transaction > _pending_tx;
|
||||||
fork_database _fork_db;
|
fork_database _fork_db;
|
||||||
|
|
||||||
|
|
@ -612,11 +633,17 @@ namespace graphene { namespace chain {
|
||||||
uint16_t _current_op_in_trx = 0;
|
uint16_t _current_op_in_trx = 0;
|
||||||
uint32_t _current_virtual_op = 0;
|
uint32_t _current_virtual_op = 0;
|
||||||
|
|
||||||
vector<uint64_t> _vote_tally_buffer;
|
vector<uint64_t> _vote_tally_buffer;
|
||||||
vector<uint64_t> _witness_count_histogram_buffer;
|
vector<uint64_t> _witness_count_histogram_buffer;
|
||||||
vector<uint64_t> _committee_count_histogram_buffer;
|
vector<uint64_t> _committee_count_histogram_buffer;
|
||||||
vector<uint64_t> _son_count_histogram_buffer;
|
flat_map<sidechain_type, vector<uint64_t> > _son_count_histogram_buffer = []{
|
||||||
uint64_t _total_voting_stake;
|
flat_map<sidechain_type, vector<uint64_t> > son_count_histogram_buffer;
|
||||||
|
for(const auto& active_sidechain_type : all_sidechain_types){
|
||||||
|
son_count_histogram_buffer[active_sidechain_type] = vector<uint64_t>{};
|
||||||
|
}
|
||||||
|
return son_count_histogram_buffer;
|
||||||
|
}();
|
||||||
|
uint64_t _total_voting_stake;
|
||||||
|
|
||||||
flat_map<uint32_t,block_id_type> _checkpoints;
|
flat_map<uint32_t,block_id_type> _checkpoints;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
#include <graphene/chain/protocol/chain_parameters.hpp>
|
#include <graphene/chain/protocol/chain_parameters.hpp>
|
||||||
#include <graphene/chain/protocol/types.hpp>
|
#include <graphene/chain/protocol/types.hpp>
|
||||||
#include <graphene/chain/database.hpp>
|
#include <graphene/chain/database.hpp>
|
||||||
#include <graphene/chain/son_info.hpp>
|
#include <graphene/chain/son_sidechain_info.hpp>
|
||||||
#include <graphene/db/object.hpp>
|
#include <graphene/db/object.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
@ -49,10 +49,18 @@ namespace graphene { namespace chain {
|
||||||
chain_parameters parameters;
|
chain_parameters parameters;
|
||||||
optional<chain_parameters> pending_parameters;
|
optional<chain_parameters> pending_parameters;
|
||||||
|
|
||||||
uint32_t next_available_vote_id = 0;
|
uint32_t next_available_vote_id = 0;
|
||||||
vector<committee_member_id_type> active_committee_members; // updated once per maintenance interval
|
vector<committee_member_id_type> active_committee_members; // updated once per maintenance interval
|
||||||
flat_set<witness_id_type> active_witnesses; // updated once per maintenance interval
|
flat_set<witness_id_type> active_witnesses; // updated once per maintenance interval
|
||||||
vector<son_info> active_sons; // updated once per maintenance interval
|
flat_map<sidechain_type, vector<son_sidechain_info> > active_sons = []() // updated once per maintenance interval
|
||||||
|
{
|
||||||
|
flat_map<sidechain_type, vector<son_sidechain_info> > active_sons;
|
||||||
|
for(const auto& active_sidechain_type : all_sidechain_types)
|
||||||
|
{
|
||||||
|
active_sons[active_sidechain_type] = vector<son_sidechain_info>();
|
||||||
|
}
|
||||||
|
return active_sons;
|
||||||
|
}();
|
||||||
// n.b. witness scheduling is done by witness_schedule object
|
// n.b. witness scheduling is done by witness_schedule object
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,9 @@ namespace graphene { namespace chain {
|
||||||
std::greater< uint32_t >,
|
std::greater< uint32_t >,
|
||||||
std::greater< object_id_type >
|
std::greater< object_id_type >
|
||||||
>
|
>
|
||||||
|
>,
|
||||||
|
ordered_non_unique< tag<by_owner>,
|
||||||
|
member<nft_metadata_object, account_id_type, &nft_metadata_object::owner>
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#include <graphene/chain/protocol/special_authority.hpp>
|
#include <graphene/chain/protocol/special_authority.hpp>
|
||||||
#include <graphene/chain/protocol/types.hpp>
|
#include <graphene/chain/protocol/types.hpp>
|
||||||
#include <graphene/chain/protocol/vote.hpp>
|
#include <graphene/chain/protocol/vote.hpp>
|
||||||
|
#include <graphene/chain/sidechain_defs.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
||||||
|
|
@ -35,8 +36,28 @@ namespace graphene { namespace chain {
|
||||||
bool is_cheap_name( const string& n );
|
bool is_cheap_name( const string& n );
|
||||||
|
|
||||||
/// These are the fields which can be updated by the active authority.
|
/// These are the fields which can be updated by the active authority.
|
||||||
struct account_options
|
struct account_options
|
||||||
{
|
{
|
||||||
|
struct ext
|
||||||
|
{
|
||||||
|
/// The number of active son members this account votes the blockchain should appoint
|
||||||
|
/// Must not exceed the actual number of son members voted for in @ref votes
|
||||||
|
optional< flat_map<sidechain_type, uint16_t> > num_son;
|
||||||
|
|
||||||
|
/// Returns and empty num_son map with all sidechains
|
||||||
|
static flat_map<sidechain_type, uint16_t> empty_num_son()
|
||||||
|
{
|
||||||
|
flat_map<sidechain_type, uint16_t> num_son;
|
||||||
|
for(const auto& active_sidechain_type : all_sidechain_types)
|
||||||
|
{
|
||||||
|
num_son[active_sidechain_type] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_son;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/// The memo key is the key this account will typically use to encrypt/sign transaction memos and other non-
|
/// The memo key is the key this account will typically use to encrypt/sign transaction memos and other non-
|
||||||
/// validated account activities. This field is here to prevent confusion if the active authority has zero or
|
/// validated account activities. This field is here to prevent confusion if the active authority has zero or
|
||||||
/// multiple keys in it.
|
/// multiple keys in it.
|
||||||
|
|
@ -52,14 +73,11 @@ namespace graphene { namespace chain {
|
||||||
/// The number of active committee members this account votes the blockchain should appoint
|
/// The number of active committee members this account votes the blockchain should appoint
|
||||||
/// Must not exceed the actual number of committee members voted for in @ref votes
|
/// Must not exceed the actual number of committee members voted for in @ref votes
|
||||||
uint16_t num_committee = 0;
|
uint16_t num_committee = 0;
|
||||||
/// The number of active son members this account votes the blockchain should appoint
|
|
||||||
/// Must not exceed the actual number of son members voted for in @ref votes
|
|
||||||
uint16_t num_son = 0;
|
|
||||||
/// This is the list of vote IDs this account votes for. The weight of these votes is determined by this
|
/// This is the list of vote IDs this account votes for. The weight of these votes is determined by this
|
||||||
/// account's balance of core asset.
|
/// account's balance of core asset.
|
||||||
flat_set<vote_id_type> votes;
|
flat_set<vote_id_type> votes;
|
||||||
extensions_type extensions;
|
extension< ext > extensions;
|
||||||
|
|
||||||
/// Whether this account is voting
|
/// Whether this account is voting
|
||||||
inline bool is_voting() const
|
inline bool is_voting() const
|
||||||
{
|
{
|
||||||
|
|
@ -244,7 +262,7 @@ namespace graphene { namespace chain {
|
||||||
*/
|
*/
|
||||||
struct account_upgrade_operation : public base_operation
|
struct account_upgrade_operation : public base_operation
|
||||||
{
|
{
|
||||||
struct fee_parameters_type {
|
struct fee_parameters_type {
|
||||||
uint64_t membership_annual_fee = 2000 * GRAPHENE_BLOCKCHAIN_PRECISION;
|
uint64_t membership_annual_fee = 2000 * GRAPHENE_BLOCKCHAIN_PRECISION;
|
||||||
uint64_t membership_lifetime_fee = 10000 * GRAPHENE_BLOCKCHAIN_PRECISION; ///< the cost to upgrade to a lifetime member
|
uint64_t membership_lifetime_fee = 10000 * GRAPHENE_BLOCKCHAIN_PRECISION; ///< the cost to upgrade to a lifetime member
|
||||||
};
|
};
|
||||||
|
|
@ -289,6 +307,7 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
||||||
|
FC_REFLECT(graphene::chain::account_options::ext, (num_son))
|
||||||
FC_REFLECT(graphene::chain::account_options, (memo_key)(voting_account)(num_witness)(num_committee)(votes)(extensions))
|
FC_REFLECT(graphene::chain::account_options, (memo_key)(voting_account)(num_witness)(num_committee)(votes)(extensions))
|
||||||
// FC_REFLECT_TYPENAME( graphene::chain::account_whitelist_operation::account_listing)
|
// FC_REFLECT_TYPENAME( graphene::chain::account_whitelist_operation::account_listing)
|
||||||
FC_REFLECT_ENUM( graphene::chain::account_whitelist_operation::account_listing,
|
FC_REFLECT_ENUM( graphene::chain::account_whitelist_operation::account_listing,
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ namespace graphene { namespace chain {
|
||||||
optional < uint16_t > maximum_son_count = GRAPHENE_DEFAULT_MAX_SONS; ///< maximum number of active SONS
|
optional < uint16_t > maximum_son_count = GRAPHENE_DEFAULT_MAX_SONS; ///< maximum number of active SONS
|
||||||
optional < asset_id_type > hbd_asset = asset_id_type();
|
optional < asset_id_type > hbd_asset = asset_id_type();
|
||||||
optional < asset_id_type > hive_asset = asset_id_type();
|
optional < asset_id_type > hive_asset = asset_id_type();
|
||||||
|
optional < asset_id_type > eth_asset = asset_id_type();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct chain_parameters
|
struct chain_parameters
|
||||||
|
|
@ -220,6 +221,9 @@ namespace graphene { namespace chain {
|
||||||
inline asset_id_type hive_asset() const {
|
inline asset_id_type hive_asset() const {
|
||||||
return extensions.value.hive_asset.valid() ? *extensions.value.hive_asset : asset_id_type();
|
return extensions.value.hive_asset.valid() ? *extensions.value.hive_asset : asset_id_type();
|
||||||
}
|
}
|
||||||
|
inline asset_id_type eth_asset() const {
|
||||||
|
return extensions.value.eth_asset.valid() ? *extensions.value.eth_asset : asset_id_type();
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
static void safe_copy(chain_parameters& to, const chain_parameters& from);
|
static void safe_copy(chain_parameters& to, const chain_parameters& from);
|
||||||
};
|
};
|
||||||
|
|
@ -257,6 +261,7 @@ FC_REFLECT( graphene::chain::parameter_extension,
|
||||||
(maximum_son_count)
|
(maximum_son_count)
|
||||||
(hbd_asset)
|
(hbd_asset)
|
||||||
(hive_asset)
|
(hive_asset)
|
||||||
|
(eth_asset)
|
||||||
)
|
)
|
||||||
|
|
||||||
FC_REFLECT( graphene::chain::chain_parameters,
|
FC_REFLECT( graphene::chain::chain_parameters,
|
||||||
|
|
|
||||||
|
|
@ -111,12 +111,12 @@ struct stealth_confirmation
|
||||||
/**
|
/**
|
||||||
* Packs *this then encodes as base58 encoded string.
|
* Packs *this then encodes as base58 encoded string.
|
||||||
*/
|
*/
|
||||||
operator string()const;
|
//operator string()const;
|
||||||
/**
|
/**
|
||||||
* Unpacks from a base58 string
|
* Unpacks from a base58 string
|
||||||
*/
|
*/
|
||||||
stealth_confirmation( const std::string& base58 );
|
//stealth_confirmation( const std::string& base58 );
|
||||||
stealth_confirmation(){}
|
//stealth_confirmation(){}
|
||||||
|
|
||||||
public_key_type one_time_key;
|
public_key_type one_time_key;
|
||||||
optional<public_key_type> to;
|
optional<public_key_type> to;
|
||||||
|
|
@ -152,7 +152,6 @@ struct transfer_to_blind_operation : public base_operation
|
||||||
uint32_t price_per_output = 5*GRAPHENE_BLOCKCHAIN_PRECISION;
|
uint32_t price_per_output = 5*GRAPHENE_BLOCKCHAIN_PRECISION;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
asset fee;
|
asset fee;
|
||||||
asset amount;
|
asset amount;
|
||||||
account_id_type from;
|
account_id_type from;
|
||||||
|
|
@ -160,8 +159,8 @@ struct transfer_to_blind_operation : public base_operation
|
||||||
vector<blind_output> outputs;
|
vector<blind_output> outputs;
|
||||||
|
|
||||||
account_id_type fee_payer()const { return from; }
|
account_id_type fee_payer()const { return from; }
|
||||||
void validate()const;
|
//void validate()const;
|
||||||
share_type calculate_fee(const fee_parameters_type& )const;
|
//share_type calculate_fee(const fee_parameters_type& )const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -181,13 +180,12 @@ struct transfer_from_blind_operation : public base_operation
|
||||||
vector<blind_input> inputs;
|
vector<blind_input> inputs;
|
||||||
|
|
||||||
account_id_type fee_payer()const { return GRAPHENE_TEMP_ACCOUNT; }
|
account_id_type fee_payer()const { return GRAPHENE_TEMP_ACCOUNT; }
|
||||||
void validate()const;
|
//void validate()const;
|
||||||
|
//void get_required_authorities( vector<authority>& a )const
|
||||||
void get_required_authorities( vector<authority>& a )const
|
//{
|
||||||
{
|
// for( const auto& in : inputs )
|
||||||
for( const auto& in : inputs )
|
// a.push_back( in.owner );
|
||||||
a.push_back( in.owner );
|
//}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -243,17 +241,16 @@ struct blind_transfer_operation : public base_operation
|
||||||
asset fee;
|
asset fee;
|
||||||
vector<blind_input> inputs;
|
vector<blind_input> inputs;
|
||||||
vector<blind_output> outputs;
|
vector<blind_output> outputs;
|
||||||
|
|
||||||
/** graphene TEMP account */
|
|
||||||
account_id_type fee_payer()const;
|
|
||||||
void validate()const;
|
|
||||||
share_type calculate_fee( const fee_parameters_type& k )const;
|
|
||||||
|
|
||||||
void get_required_authorities( vector<authority>& a )const
|
/** graphene TEMP account */
|
||||||
{
|
account_id_type fee_payer()const { return GRAPHENE_TEMP_ACCOUNT; }
|
||||||
for( const auto& in : inputs )
|
//void validate()const;
|
||||||
a.push_back( in.owner );
|
//share_type calculate_fee( const fee_parameters_type& k )const;
|
||||||
}
|
//void get_required_authorities( vector<authority>& a )const
|
||||||
|
//{
|
||||||
|
// for( const auto& in : inputs )
|
||||||
|
// a.push_back( in.owner );
|
||||||
|
//}
|
||||||
};
|
};
|
||||||
|
|
||||||
///@} endgroup stealth
|
///@} endgroup stealth
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace graphene
|
||||||
// Buyer purchasing lottery tickets
|
// Buyer purchasing lottery tickets
|
||||||
account_id_type buyer;
|
account_id_type buyer;
|
||||||
// count of tickets to buy
|
// count of tickets to buy
|
||||||
uint64_t tickets_to_buy;
|
share_type tickets_to_buy;
|
||||||
// amount that can spent
|
// amount that can spent
|
||||||
asset amount;
|
asset amount;
|
||||||
|
|
||||||
|
|
@ -83,4 +83,4 @@ FC_REFLECT(graphene::chain::nft_lottery_reward_operation::fee_parameters_type, (
|
||||||
FC_REFLECT(graphene::chain::nft_lottery_end_operation::fee_parameters_type, (fee))
|
FC_REFLECT(graphene::chain::nft_lottery_end_operation::fee_parameters_type, (fee))
|
||||||
FC_REFLECT(graphene::chain::nft_lottery_token_purchase_operation, (fee)(lottery_id)(buyer)(tickets_to_buy)(amount)(extensions))
|
FC_REFLECT(graphene::chain::nft_lottery_token_purchase_operation, (fee)(lottery_id)(buyer)(tickets_to_buy)(amount)(extensions))
|
||||||
FC_REFLECT(graphene::chain::nft_lottery_reward_operation, (fee)(lottery_id)(winner)(amount)(win_percentage)(is_benefactor_reward)(winner_ticket_id)(extensions))
|
FC_REFLECT(graphene::chain::nft_lottery_reward_operation, (fee)(lottery_id)(winner)(amount)(win_percentage)(is_benefactor_reward)(winner_ticket_id)(extensions))
|
||||||
FC_REFLECT(graphene::chain::nft_lottery_end_operation, (fee)(lottery_id)(extensions))
|
FC_REFLECT(graphene::chain::nft_lottery_end_operation, (fee)(lottery_id)(extensions))
|
||||||
|
|
|
||||||
|
|
@ -106,9 +106,9 @@ namespace graphene { namespace chain {
|
||||||
assert_operation,
|
assert_operation,
|
||||||
balance_claim_operation,
|
balance_claim_operation,
|
||||||
override_transfer_operation,
|
override_transfer_operation,
|
||||||
transfer_to_blind_operation,
|
transfer_to_blind_operation, //! We don't use this operation
|
||||||
blind_transfer_operation,
|
blind_transfer_operation, //! We don't use this operation
|
||||||
transfer_from_blind_operation,
|
transfer_from_blind_operation, //! We don't use this operation
|
||||||
asset_settle_cancel_operation, // VIRTUAL
|
asset_settle_cancel_operation, // VIRTUAL
|
||||||
asset_claim_fees_operation,
|
asset_claim_fees_operation,
|
||||||
fba_distribute_operation, // VIRTUAL
|
fba_distribute_operation, // VIRTUAL
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ FC_REFLECT( graphene::chain::sidechain_transaction_create_operation, (fee)(payer
|
||||||
(sidechain)
|
(sidechain)
|
||||||
(object_id)
|
(object_id)
|
||||||
(transaction)
|
(transaction)
|
||||||
(signers) )
|
(signers))
|
||||||
|
|
||||||
FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation::fee_parameters_type, (fee) )
|
FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation::fee_parameters_type, (fee) )
|
||||||
FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation, (fee)(signer)(payer)
|
FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation, (fee)(signer)(payer)
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,47 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <graphene/chain/protocol/base.hpp>
|
#include <graphene/chain/protocol/base.hpp>
|
||||||
#include <graphene/chain/son_info.hpp>
|
#include <graphene/chain/son_info.hpp>
|
||||||
|
#include <graphene/chain/son_sidechain_info.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
||||||
struct son_wallet_recreate_operation : public base_operation
|
struct son_wallet_recreate_operation : public base_operation
|
||||||
{
|
{
|
||||||
struct fee_parameters_type { uint64_t fee = 0; };
|
struct fee_parameters_type { uint64_t fee = 0; };
|
||||||
|
struct ext
|
||||||
|
{
|
||||||
|
optional<flat_map<sidechain_type, vector<son_sidechain_info> > > sidechain_sons;
|
||||||
|
};
|
||||||
|
|
||||||
asset fee;
|
asset fee;
|
||||||
account_id_type payer;
|
account_id_type payer;
|
||||||
|
|
||||||
vector<son_info> sons;
|
vector<son_info> sons;
|
||||||
|
extension< ext > extensions;
|
||||||
|
|
||||||
account_id_type fee_payer()const { return payer; }
|
account_id_type fee_payer()const { return payer; }
|
||||||
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
|
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct son_wallet_update_operation : public base_operation
|
struct son_wallet_update_operation : public base_operation
|
||||||
{
|
{
|
||||||
struct fee_parameters_type { uint64_t fee = 0; };
|
struct fee_parameters_type { uint64_t fee = 0; };
|
||||||
|
|
||||||
asset fee;
|
asset fee;
|
||||||
account_id_type payer;
|
account_id_type payer;
|
||||||
|
|
||||||
son_wallet_id_type son_wallet_id;
|
son_wallet_id_type son_wallet_id;
|
||||||
sidechain_type sidechain;
|
sidechain_type sidechain;
|
||||||
string address;
|
string address;
|
||||||
|
|
||||||
account_id_type fee_payer()const { return payer; }
|
account_id_type fee_payer()const { return payer; }
|
||||||
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
|
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // namespace graphene::chain
|
} } // namespace graphene::chain
|
||||||
|
|
||||||
FC_REFLECT(graphene::chain::son_wallet_recreate_operation::fee_parameters_type, (fee) )
|
FC_REFLECT(graphene::chain::son_wallet_recreate_operation::fee_parameters_type, (fee) )
|
||||||
FC_REFLECT(graphene::chain::son_wallet_recreate_operation, (fee)(payer)(sons) )
|
FC_REFLECT(graphene::chain::son_wallet_recreate_operation::ext, (sidechain_sons))
|
||||||
|
FC_REFLECT(graphene::chain::son_wallet_recreate_operation, (fee)(payer)(sons)(extensions) )
|
||||||
FC_REFLECT(graphene::chain::son_wallet_update_operation::fee_parameters_type, (fee) )
|
FC_REFLECT(graphene::chain::son_wallet_update_operation::fee_parameters_type, (fee) )
|
||||||
FC_REFLECT(graphene::chain::son_wallet_update_operation, (fee)(payer)(son_wallet_id)(sidechain)(address) )
|
FC_REFLECT(graphene::chain::son_wallet_update_operation, (fee)(payer)(son_wallet_id)(sidechain)(address) )
|
||||||
|
|
|
||||||
|
|
@ -395,6 +395,13 @@ namespace graphene { namespace chain {
|
||||||
bool is_valid_muse( const std::string& base58str );
|
bool is_valid_muse( const std::string& base58str );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class pubkey_comparator {
|
||||||
|
public:
|
||||||
|
inline bool operator()(const public_key_type& a, const public_key_type& b) const {
|
||||||
|
return a.key_data < b.key_data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct extended_public_key_type
|
struct extended_public_key_type
|
||||||
{
|
{
|
||||||
struct binary_key
|
struct binary_key
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,9 @@ struct vote_id_type
|
||||||
committee,
|
committee,
|
||||||
witness,
|
witness,
|
||||||
worker,
|
worker,
|
||||||
son,
|
son_bitcoin,
|
||||||
|
son_hive,
|
||||||
|
son_ethereum,
|
||||||
VOTE_TYPE_COUNT
|
VOTE_TYPE_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -144,7 +146,7 @@ void from_variant( const fc::variant& var, graphene::chain::vote_id_type& vo, ui
|
||||||
|
|
||||||
FC_REFLECT_TYPENAME( fc::flat_set<graphene::chain::vote_id_type> )
|
FC_REFLECT_TYPENAME( fc::flat_set<graphene::chain::vote_id_type> )
|
||||||
|
|
||||||
FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(son)(VOTE_TYPE_COUNT) )
|
FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(son_bitcoin)(son_hive)(son_ethereum)(VOTE_TYPE_COUNT) )
|
||||||
FC_REFLECT( graphene::chain::vote_id_type, (content) )
|
FC_REFLECT( graphene::chain::vote_id_type, (content) )
|
||||||
|
|
||||||
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vote_id_type )
|
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vote_id_type )
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,20 @@ namespace graphene { namespace chain {
|
||||||
time_point_sec expires;
|
time_point_sec expires;
|
||||||
|
|
||||||
sidechain_address_object() :
|
sidechain_address_object() :
|
||||||
sidechain(sidechain_type::bitcoin),
|
sidechain(sidechain_type::bitcoin), //! FIXME - bitcoin ???
|
||||||
deposit_public_key(""),
|
deposit_public_key(""),
|
||||||
deposit_address(""),
|
deposit_address(""),
|
||||||
withdraw_public_key(""),
|
withdraw_public_key(""),
|
||||||
withdraw_address("") {}
|
withdraw_address("") {}
|
||||||
|
|
||||||
|
inline string get_deposit_address() const {
|
||||||
|
if(sidechain_type::ethereum != sidechain)
|
||||||
|
return deposit_address;
|
||||||
|
|
||||||
|
auto deposit_address_lower = deposit_address;
|
||||||
|
std::transform(deposit_address_lower.begin(), deposit_address_lower.end(), deposit_address_lower.begin(), ::tolower);
|
||||||
|
return deposit_address_lower;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct by_account;
|
struct by_account;
|
||||||
|
|
@ -76,7 +85,7 @@ namespace graphene { namespace chain {
|
||||||
ordered_non_unique< tag<by_sidechain_and_deposit_address_and_expires>,
|
ordered_non_unique< tag<by_sidechain_and_deposit_address_and_expires>,
|
||||||
composite_key<sidechain_address_object,
|
composite_key<sidechain_address_object,
|
||||||
member<sidechain_address_object, sidechain_type, &sidechain_address_object::sidechain>,
|
member<sidechain_address_object, sidechain_type, &sidechain_address_object::sidechain>,
|
||||||
member<sidechain_address_object, string, &sidechain_address_object::deposit_address>,
|
const_mem_fun<sidechain_address_object, string, &sidechain_address_object::get_deposit_address>,
|
||||||
member<sidechain_address_object, time_point_sec, &sidechain_address_object::expires>
|
member<sidechain_address_object, time_point_sec, &sidechain_address_object::expires>
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <graphene/chain/hardfork.hpp>
|
||||||
|
|
||||||
#include <fc/reflect/reflect.hpp>
|
#include <fc/reflect/reflect.hpp>
|
||||||
|
#include <fc/time.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
||||||
|
|
@ -13,12 +18,28 @@ enum class sidechain_type {
|
||||||
hive
|
hive
|
||||||
};
|
};
|
||||||
|
|
||||||
} }
|
static const std::set<sidechain_type> all_sidechain_types = {sidechain_type::bitcoin, sidechain_type::ethereum, sidechain_type::hive};
|
||||||
|
|
||||||
|
inline std::set<sidechain_type> active_sidechain_types(const fc::time_point_sec block_time) {
|
||||||
|
std::set<sidechain_type> active_sidechain_types{};
|
||||||
|
|
||||||
|
if (block_time >= HARDFORK_SON_TIME)
|
||||||
|
active_sidechain_types.insert(sidechain_type::bitcoin);
|
||||||
|
if (block_time >= HARDFORK_SON_FOR_HIVE_TIME)
|
||||||
|
active_sidechain_types.insert(sidechain_type::hive);
|
||||||
|
if (block_time >= HARDFORK_SON_FOR_ETHEREUM_TIME)
|
||||||
|
active_sidechain_types.insert(sidechain_type::ethereum);
|
||||||
|
|
||||||
|
return active_sidechain_types;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chain
|
||||||
|
} // namespace graphene
|
||||||
|
|
||||||
FC_REFLECT_ENUM(graphene::chain::sidechain_type,
|
FC_REFLECT_ENUM(graphene::chain::sidechain_type,
|
||||||
(unknown)
|
(unknown)
|
||||||
(bitcoin)
|
(bitcoin)
|
||||||
(ethereum)
|
(ethereum)
|
||||||
(eos)
|
(eos)
|
||||||
(hive)
|
(hive)
|
||||||
(peerplays) )
|
(peerplays) )
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#include <boost/multi_index/composite_key.hpp>
|
#include <boost/multi_index/composite_key.hpp>
|
||||||
#include <graphene/chain/protocol/types.hpp>
|
#include <graphene/chain/protocol/types.hpp>
|
||||||
#include <graphene/chain/sidechain_defs.hpp>
|
#include <graphene/chain/sidechain_defs.hpp>
|
||||||
#include <graphene/chain/son_info.hpp>
|
#include <graphene/chain/son_sidechain_info.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
using namespace graphene::db;
|
using namespace graphene::db;
|
||||||
|
|
@ -30,7 +30,7 @@ namespace graphene { namespace chain {
|
||||||
sidechain_type sidechain = sidechain_type::unknown;
|
sidechain_type sidechain = sidechain_type::unknown;
|
||||||
object_id_type object_id;
|
object_id_type object_id;
|
||||||
std::string transaction;
|
std::string transaction;
|
||||||
std::vector<son_info> signers;
|
std::vector<son_sidechain_info> signers;
|
||||||
std::vector<std::pair<son_id_type, std::string>> signatures;
|
std::vector<std::pair<son_id_type, std::string>> signatures;
|
||||||
std::string sidechain_transaction;
|
std::string sidechain_transaction;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,11 @@
|
||||||
#include <graphene/chain/sidechain_defs.hpp>
|
#include <graphene/chain/sidechain_defs.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
using namespace graphene::db;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class son_info
|
* @class son_info
|
||||||
* @brief tracks information about a SON info required to re/create primary wallet
|
* @brief tracks information about a SON info required to re/create primary wallet
|
||||||
* @ingroup object
|
* @ingroup object
|
||||||
*/
|
*/
|
||||||
struct son_info {
|
struct son_info {
|
||||||
son_id_type son_id;
|
son_id_type son_id;
|
||||||
|
|
@ -26,11 +25,11 @@ namespace graphene { namespace chain {
|
||||||
if (son_sets_equal) {
|
if (son_sets_equal) {
|
||||||
bool sidechain_public_keys_equal = true;
|
bool sidechain_public_keys_equal = true;
|
||||||
for (size_t i = 0; i < sidechain_public_keys.size(); i++) {
|
for (size_t i = 0; i < sidechain_public_keys.size(); i++) {
|
||||||
const auto lhs_scpk = sidechain_public_keys.nth(i);
|
const auto lhs_scpk = sidechain_public_keys.nth(i);
|
||||||
const auto rhs_scpk = rhs.sidechain_public_keys.nth(i);
|
const auto rhs_scpk = rhs.sidechain_public_keys.nth(i);
|
||||||
sidechain_public_keys_equal = sidechain_public_keys_equal &&
|
sidechain_public_keys_equal = sidechain_public_keys_equal &&
|
||||||
(lhs_scpk->first == rhs_scpk->first) &&
|
(lhs_scpk->first == rhs_scpk->first) &&
|
||||||
(lhs_scpk->second == rhs_scpk->second);
|
(lhs_scpk->second == rhs_scpk->second);
|
||||||
}
|
}
|
||||||
son_sets_equal = son_sets_equal && sidechain_public_keys_equal;
|
son_sets_equal = son_sets_equal && sidechain_public_keys_equal;
|
||||||
}
|
}
|
||||||
|
|
@ -40,8 +39,4 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
|
||||||
FC_REFLECT( graphene::chain::son_info,
|
FC_REFLECT( graphene::chain::son_info, (son_id) (weight) (signing_key) (sidechain_public_keys) )
|
||||||
(son_id)
|
|
||||||
(weight)
|
|
||||||
(signing_key)
|
|
||||||
(sidechain_public_keys) )
|
|
||||||
|
|
|
||||||
|
|
@ -35,15 +35,15 @@ namespace graphene { namespace chain {
|
||||||
// Transactions signed since the last son payouts
|
// Transactions signed since the last son payouts
|
||||||
flat_map<sidechain_type, uint64_t> txs_signed;
|
flat_map<sidechain_type, uint64_t> txs_signed;
|
||||||
// Total Voted Active time i.e. duration selected as part of voted active SONs
|
// Total Voted Active time i.e. duration selected as part of voted active SONs
|
||||||
uint64_t total_voted_time = 0;
|
flat_map<sidechain_type, uint64_t> total_voted_time;
|
||||||
// Total Downtime barring the current down time in seconds, used for stats to present to user
|
// Total Downtime barring the current down time in seconds, used for stats to present to user
|
||||||
uint64_t total_downtime = 0;
|
flat_map<sidechain_type, uint64_t> total_downtime;
|
||||||
// Current Interval Downtime since last maintenance
|
// Current Interval Downtime since last maintenance
|
||||||
uint64_t current_interval_downtime = 0;
|
flat_map<sidechain_type, uint64_t> current_interval_downtime;
|
||||||
// Down timestamp, if son status is in_maintenance use this
|
// Down timestamp, if son status is in_maintenance use this
|
||||||
fc::time_point_sec last_down_timestamp;
|
flat_map<sidechain_type, fc::time_point_sec> last_down_timestamp;
|
||||||
// Last Active heartbeat timestamp
|
// Last Active heartbeat timestamp
|
||||||
fc::time_point_sec last_active_timestamp;
|
flat_map<sidechain_type, fc::time_point_sec> last_active_timestamp;
|
||||||
// Deregistered Timestamp
|
// Deregistered Timestamp
|
||||||
fc::time_point_sec deregistered_timestamp;
|
fc::time_point_sec deregistered_timestamp;
|
||||||
// Total sidechain transactions reported by SON network while SON was active
|
// Total sidechain transactions reported by SON network while SON was active
|
||||||
|
|
@ -64,23 +64,48 @@ namespace graphene { namespace chain {
|
||||||
static const uint8_t type_id = son_object_type;
|
static const uint8_t type_id = son_object_type;
|
||||||
|
|
||||||
account_id_type son_account;
|
account_id_type son_account;
|
||||||
vote_id_type vote_id;
|
flat_map<sidechain_type, vote_id_type> sidechain_vote_ids;
|
||||||
uint64_t total_votes = 0;
|
flat_map<sidechain_type, uint64_t> total_votes = []()
|
||||||
|
{
|
||||||
|
flat_map<sidechain_type, uint64_t> total_votes;
|
||||||
|
for(const auto& active_sidechain_type : all_sidechain_types)
|
||||||
|
{
|
||||||
|
total_votes[active_sidechain_type] = 0;
|
||||||
|
}
|
||||||
|
return total_votes;
|
||||||
|
}();
|
||||||
string url;
|
string url;
|
||||||
vesting_balance_id_type deposit;
|
vesting_balance_id_type deposit;
|
||||||
public_key_type signing_key;
|
public_key_type signing_key;
|
||||||
vesting_balance_id_type pay_vb;
|
vesting_balance_id_type pay_vb;
|
||||||
son_statistics_id_type statistics;
|
son_statistics_id_type statistics;
|
||||||
son_status status = son_status::inactive;
|
flat_map<sidechain_type, son_status> statuses = []()
|
||||||
|
{
|
||||||
|
flat_map<sidechain_type, son_status> statuses;
|
||||||
|
for(const auto& active_sidechain_type : all_sidechain_types)
|
||||||
|
{
|
||||||
|
statuses[active_sidechain_type] = son_status::inactive;
|
||||||
|
}
|
||||||
|
return statuses;
|
||||||
|
}();
|
||||||
flat_map<sidechain_type, string> sidechain_public_keys;
|
flat_map<sidechain_type, string> sidechain_public_keys;
|
||||||
|
|
||||||
void pay_son_fee(share_type pay, database& db);
|
void pay_son_fee(share_type pay, database& db);
|
||||||
bool has_valid_config()const;
|
bool has_valid_config(time_point_sec head_block_time, sidechain_type sidechain) const;
|
||||||
bool has_valid_config(time_point_sec head_block_time)const;
|
|
||||||
|
inline optional<vote_id_type> get_sidechain_vote_id(sidechain_type sidechain) const { return sidechain_vote_ids.contains(sidechain) ? sidechain_vote_ids.at(sidechain) : optional<vote_id_type>{}; }
|
||||||
|
inline optional<vote_id_type> get_bitcoin_vote_id() const { return get_sidechain_vote_id(sidechain_type::bitcoin); }
|
||||||
|
inline optional<vote_id_type> get_hive_vote_id() const { return get_sidechain_vote_id(sidechain_type::hive); }
|
||||||
|
inline optional<vote_id_type> get_ethereum_vote_id() const { return get_sidechain_vote_id(sidechain_type::ethereum); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool has_valid_config(sidechain_type sidechain) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct by_account;
|
struct by_account;
|
||||||
struct by_vote_id;
|
struct by_vote_id_bitcoin;
|
||||||
|
struct by_vote_id_hive;
|
||||||
|
struct by_vote_id_ethereum;
|
||||||
using son_multi_index_type = multi_index_container<
|
using son_multi_index_type = multi_index_container<
|
||||||
son_object,
|
son_object,
|
||||||
indexed_by<
|
indexed_by<
|
||||||
|
|
@ -90,8 +115,14 @@ namespace graphene { namespace chain {
|
||||||
ordered_unique< tag<by_account>,
|
ordered_unique< tag<by_account>,
|
||||||
member<son_object, account_id_type, &son_object::son_account>
|
member<son_object, account_id_type, &son_object::son_account>
|
||||||
>,
|
>,
|
||||||
ordered_unique< tag<by_vote_id>,
|
ordered_non_unique< tag<by_vote_id_bitcoin>,
|
||||||
member<son_object, vote_id_type, &son_object::vote_id>
|
const_mem_fun<son_object, optional<vote_id_type>, &son_object::get_bitcoin_vote_id>
|
||||||
|
>,
|
||||||
|
ordered_non_unique< tag<by_vote_id_hive>,
|
||||||
|
const_mem_fun<son_object, optional<vote_id_type>, &son_object::get_hive_vote_id>
|
||||||
|
>,
|
||||||
|
ordered_non_unique< tag<by_vote_id_ethereum>,
|
||||||
|
const_mem_fun<son_object, optional<vote_id_type>, &son_object::get_ethereum_vote_id>
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
|
|
@ -117,14 +148,14 @@ FC_REFLECT_ENUM(graphene::chain::son_status, (inactive)(active)(request_maintena
|
||||||
|
|
||||||
FC_REFLECT_DERIVED( graphene::chain::son_object, (graphene::db::object),
|
FC_REFLECT_DERIVED( graphene::chain::son_object, (graphene::db::object),
|
||||||
(son_account)
|
(son_account)
|
||||||
(vote_id)
|
(sidechain_vote_ids)
|
||||||
(total_votes)
|
(total_votes)
|
||||||
(url)
|
(url)
|
||||||
(deposit)
|
(deposit)
|
||||||
(signing_key)
|
(signing_key)
|
||||||
(pay_vb)
|
(pay_vb)
|
||||||
(statistics)
|
(statistics)
|
||||||
(status)
|
(statuses)
|
||||||
(sidechain_public_keys)
|
(sidechain_public_keys)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
#include <graphene/chain/protocol/types.hpp>
|
||||||
|
#include <graphene/chain/sidechain_defs.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace chain {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class son_sidechain_info
|
||||||
|
* @brief tracks information about a SON info required to re/create primary wallet
|
||||||
|
* @ingroup object
|
||||||
|
*/
|
||||||
|
struct son_sidechain_info {
|
||||||
|
son_id_type son_id;
|
||||||
|
weight_type weight = 0;
|
||||||
|
public_key_type signing_key;
|
||||||
|
string public_key;
|
||||||
|
|
||||||
|
bool operator==(const son_sidechain_info& rhs) const {
|
||||||
|
bool son_sets_equal =
|
||||||
|
(son_id == rhs.son_id) &&
|
||||||
|
(weight == rhs.weight) &&
|
||||||
|
(signing_key == rhs.signing_key) &&
|
||||||
|
(public_key == rhs.public_key);
|
||||||
|
|
||||||
|
return son_sets_equal;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
||||||
|
|
||||||
|
FC_REFLECT( graphene::chain::son_sidechain_info, (son_id) (weight) (signing_key) (public_key) )
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <graphene/chain/protocol/types.hpp>
|
#include <graphene/chain/protocol/types.hpp>
|
||||||
#include <graphene/chain/son_info.hpp>
|
#include <graphene/chain/son_sidechain_info.hpp>
|
||||||
#include <graphene/chain/sidechain_defs.hpp>
|
#include <graphene/chain/sidechain_defs.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
@ -21,7 +21,7 @@ namespace graphene { namespace chain {
|
||||||
time_point_sec expires;
|
time_point_sec expires;
|
||||||
|
|
||||||
flat_map<sidechain_type, string> addresses;
|
flat_map<sidechain_type, string> addresses;
|
||||||
vector<son_info> sons;
|
flat_map<sidechain_type, vector<son_sidechain_info> > sons;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct by_valid_from;
|
struct by_valid_from;
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@ namespace graphene { namespace chain {
|
||||||
* @ingroup object
|
* @ingroup object
|
||||||
*/
|
*/
|
||||||
struct voters_info {
|
struct voters_info {
|
||||||
optional<voters_info_object> voters_for_committee_member;
|
optional<voters_info_object> voters_for_committee_member;
|
||||||
optional<voters_info_object> voters_for_witness;
|
optional<voters_info_object> voters_for_witness;
|
||||||
optional<vector<voters_info_object> > voters_for_workers;
|
optional<vector<voters_info_object> > voters_for_workers;
|
||||||
optional<vector<voters_info_object> > voters_against_workers;
|
optional<vector<voters_info_object> > voters_against_workers;
|
||||||
optional<voters_info_object> voters_for_son;
|
optional<flat_map<sidechain_type, voters_info_object> > voters_for_son;
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
@ -37,4 +37,4 @@ FC_REFLECT( graphene::chain::voters_info,
|
||||||
(voters_for_witness)
|
(voters_for_witness)
|
||||||
(voters_for_workers)
|
(voters_for_workers)
|
||||||
(voters_against_workers)
|
(voters_against_workers)
|
||||||
(voters_for_son) )
|
(voters_for_son))
|
||||||
|
|
@ -19,11 +19,11 @@ namespace graphene { namespace chain {
|
||||||
* @ingroup object
|
* @ingroup object
|
||||||
*/
|
*/
|
||||||
struct votes_info {
|
struct votes_info {
|
||||||
optional< vector< votes_info_object > > votes_for_committee_members;
|
optional< vector< votes_info_object > > votes_for_committee_members;
|
||||||
optional< vector< votes_info_object > > votes_for_witnesses;
|
optional< vector< votes_info_object > > votes_for_witnesses;
|
||||||
optional< vector< votes_info_object > > votes_for_workers;
|
optional< vector< votes_info_object > > votes_for_workers;
|
||||||
optional< vector< votes_info_object > > votes_against_workers;
|
optional< vector< votes_info_object > > votes_against_workers;
|
||||||
optional< vector< votes_info_object > > votes_for_sons;
|
optional< flat_map<sidechain_type, vector< votes_info_object > > > votes_for_sons;
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
@ -37,4 +37,4 @@ FC_REFLECT( graphene::chain::votes_info,
|
||||||
(votes_for_witnesses)
|
(votes_for_witnesses)
|
||||||
(votes_for_workers)
|
(votes_for_workers)
|
||||||
(votes_against_workers)
|
(votes_against_workers)
|
||||||
(votes_for_sons) )
|
(votes_for_sons))
|
||||||
|
|
@ -96,7 +96,7 @@ class son_schedule_object : public graphene::db::abstract_object<son_schedule_ob
|
||||||
static const uint8_t space_id = implementation_ids;
|
static const uint8_t space_id = implementation_ids;
|
||||||
static const uint8_t type_id = impl_son_schedule_object_type;
|
static const uint8_t type_id = impl_son_schedule_object_type;
|
||||||
|
|
||||||
vector< son_id_type > current_shuffled_sons;
|
vector<son_id_type > current_shuffled_sons;
|
||||||
|
|
||||||
son_scheduler scheduler;
|
son_scheduler scheduler;
|
||||||
uint32_t last_scheduling_block;
|
uint32_t last_scheduling_block;
|
||||||
|
|
|
||||||
|
|
@ -162,8 +162,12 @@ class generic_witness_scheduler
|
||||||
_schedule.pop_front();
|
_schedule.pop_front();
|
||||||
|
|
||||||
auto it = _lame_duck.find( result );
|
auto it = _lame_duck.find( result );
|
||||||
if( it != _lame_duck.end() )
|
if( it != _lame_duck.end() ) {
|
||||||
_lame_duck.erase( it );
|
set< WitnessID > removal_set;
|
||||||
|
removal_set.insert(*it);
|
||||||
|
remove_all( removal_set );
|
||||||
|
_lame_duck.erase(it);
|
||||||
|
}
|
||||||
if( debug ) check_invariant();
|
if( debug ) check_invariant();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -389,7 +393,7 @@ class generic_witness_scheduler
|
||||||
// scheduled
|
// scheduled
|
||||||
std::deque < WitnessID > _schedule;
|
std::deque < WitnessID > _schedule;
|
||||||
|
|
||||||
// in _schedule, but not to be replaced
|
// in _schedule, but must be removed
|
||||||
set< WitnessID > _lame_duck;
|
set< WitnessID > _lame_duck;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace graphene
|
||||||
|
|
||||||
auto lottery_options = lottery_md_obj.lottery_data->lottery_options;
|
auto lottery_options = lottery_md_obj.lottery_data->lottery_options;
|
||||||
FC_ASSERT(lottery_options.ticket_price.asset_id == op.amount.asset_id);
|
FC_ASSERT(lottery_options.ticket_price.asset_id == op.amount.asset_id);
|
||||||
FC_ASSERT((double)op.amount.amount.value / lottery_options.ticket_price.amount.value == (double)op.tickets_to_buy);
|
FC_ASSERT(op.tickets_to_buy * lottery_options.ticket_price.amount.value == op.amount.amount.value);
|
||||||
return void_result();
|
return void_result();
|
||||||
}
|
}
|
||||||
FC_CAPTURE_AND_RETHROW((op))
|
FC_CAPTURE_AND_RETHROW((op))
|
||||||
|
|
@ -142,4 +142,4 @@ namespace graphene
|
||||||
FC_CAPTURE_AND_RETHROW((op))
|
FC_CAPTURE_AND_RETHROW((op))
|
||||||
}
|
}
|
||||||
} // namespace chain
|
} // namespace chain
|
||||||
} // namespace graphene
|
} // namespace graphene
|
||||||
|
|
|
||||||
|
|
@ -174,22 +174,37 @@ void account_options::validate() const
|
||||||
{
|
{
|
||||||
auto needed_witnesses = num_witness;
|
auto needed_witnesses = num_witness;
|
||||||
auto needed_committee = num_committee;
|
auto needed_committee = num_committee;
|
||||||
auto needed_sons = num_son;
|
|
||||||
|
|
||||||
for( vote_id_type id : votes )
|
for( vote_id_type id : votes )
|
||||||
if( id.type() == vote_id_type::witness && needed_witnesses )
|
if( id.type() == vote_id_type::witness && needed_witnesses )
|
||||||
--needed_witnesses;
|
--needed_witnesses;
|
||||||
else if ( id.type() == vote_id_type::committee && needed_committee )
|
else if ( id.type() == vote_id_type::committee && needed_committee )
|
||||||
--needed_committee;
|
--needed_committee;
|
||||||
else if ( id.type() == vote_id_type::son && needed_sons )
|
|
||||||
--needed_sons;
|
|
||||||
|
|
||||||
FC_ASSERT( needed_witnesses == 0,
|
FC_ASSERT( needed_witnesses == 0,
|
||||||
"May not specify fewer witnesses than the number voted for.");
|
"May not specify fewer witnesses than the number voted for.");
|
||||||
FC_ASSERT( needed_committee == 0,
|
FC_ASSERT( needed_committee == 0,
|
||||||
"May not specify fewer committee members than the number voted for.");
|
"May not specify fewer committee members than the number voted for.");
|
||||||
FC_ASSERT( needed_sons == 0,
|
|
||||||
"May not specify fewer SONs than the number voted for.");
|
if ( extensions.value.num_son.valid() )
|
||||||
|
{
|
||||||
|
flat_map<sidechain_type, uint16_t> needed_sons = *extensions.value.num_son;
|
||||||
|
|
||||||
|
for( vote_id_type id : votes )
|
||||||
|
if ( id.type() == vote_id_type::son_bitcoin && needed_sons[sidechain_type::bitcoin] )
|
||||||
|
--needed_sons[sidechain_type::bitcoin];
|
||||||
|
else if ( id.type() == vote_id_type::son_hive && needed_sons[sidechain_type::hive] )
|
||||||
|
--needed_sons[sidechain_type::hive];
|
||||||
|
else if ( id.type() == vote_id_type::son_ethereum && needed_sons[sidechain_type::ethereum] )
|
||||||
|
--needed_sons[sidechain_type::ethereum];
|
||||||
|
|
||||||
|
FC_ASSERT( needed_sons[sidechain_type::bitcoin] == 0,
|
||||||
|
"May not specify fewer Bitcoin SONs than the number voted for.");
|
||||||
|
FC_ASSERT( needed_sons[sidechain_type::hive] == 0,
|
||||||
|
"May not specify fewer Hive SONs than the number voted for.");
|
||||||
|
FC_ASSERT( needed_sons[sidechain_type::ethereum] == 0,
|
||||||
|
"May not specify fewer Ethereum SONs than the number voted for.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void affiliate_reward_distribution::validate() const
|
void affiliate_reward_distribution::validate() const
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,10 @@
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include <graphene/chain/protocol/confidential.hpp>
|
#include <graphene/chain/protocol/confidential.hpp>
|
||||||
#include <graphene/chain/confidential_evaluator.hpp>
|
|
||||||
#include <graphene/chain/database.hpp>
|
|
||||||
|
|
||||||
#include <fc/crypto/base58.hpp>
|
|
||||||
#include <fc/io/raw.hpp>
|
#include <fc/io/raw.hpp>
|
||||||
|
|
||||||
|
/*
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
||||||
void transfer_to_blind_operation::validate()const
|
void transfer_to_blind_operation::validate()const
|
||||||
|
|
@ -47,19 +45,6 @@ void transfer_to_blind_operation::validate()const
|
||||||
FC_ASSERT( !outputs[i].owner.is_impossible() );
|
FC_ASSERT( !outputs[i].owner.is_impossible() );
|
||||||
}
|
}
|
||||||
FC_ASSERT( out.size(), "there must be at least one output" );
|
FC_ASSERT( out.size(), "there must be at least one output" );
|
||||||
|
|
||||||
auto public_c = fc::ecc::blind(blinding_factor,net_public);
|
|
||||||
|
|
||||||
FC_ASSERT( fc::ecc::verify_sum( {public_c}, out, 0 ), "", ("net_public",net_public) );
|
|
||||||
|
|
||||||
if( outputs.size() > 1 )
|
|
||||||
{
|
|
||||||
for( auto out : outputs )
|
|
||||||
{
|
|
||||||
auto info = fc::ecc::range_get_info( out.range_proof );
|
|
||||||
FC_ASSERT( info.max_value <= GRAPHENE_MAX_SHARE_SUPPLY );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
share_type transfer_to_blind_operation::calculate_fee( const fee_parameters_type& k )const
|
share_type transfer_to_blind_operation::calculate_fee( const fee_parameters_type& k )const
|
||||||
|
|
@ -79,31 +64,15 @@ void transfer_from_blind_operation::validate()const
|
||||||
vector<commitment_type> in(inputs.size());
|
vector<commitment_type> in(inputs.size());
|
||||||
vector<commitment_type> out;
|
vector<commitment_type> out;
|
||||||
int64_t net_public = fee.amount.value + amount.amount.value;
|
int64_t net_public = fee.amount.value + amount.amount.value;
|
||||||
out.push_back( fc::ecc::blind( blinding_factor, net_public ) );
|
|
||||||
for( uint32_t i = 0; i < in.size(); ++i )
|
|
||||||
{
|
|
||||||
in[i] = inputs[i].commitment;
|
|
||||||
/// by requiring all inputs to be sorted we also prevent duplicate commitments on the input
|
|
||||||
if( i > 0 ) FC_ASSERT( in[i-1] < in[i], "all inputs must be sorted by commitment id" );
|
|
||||||
}
|
|
||||||
FC_ASSERT( in.size(), "there must be at least one input" );
|
|
||||||
FC_ASSERT( fc::ecc::verify_sum( in, out, 0 ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If fee_payer = temp_account_id, then the fee is paid by the surplus balance of inputs-outputs and
|
|
||||||
* 100% of the fee goes to the network.
|
|
||||||
*/
|
|
||||||
account_id_type blind_transfer_operation::fee_payer()const
|
account_id_type blind_transfer_operation::fee_payer()const
|
||||||
{
|
{
|
||||||
return GRAPHENE_TEMP_ACCOUNT;
|
return GRAPHENE_TEMP_ACCOUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method can be computationally intensive because it verifies that input commitments - output commitments add up to 0
|
|
||||||
*/
|
|
||||||
void blind_transfer_operation::validate()const
|
void blind_transfer_operation::validate()const
|
||||||
{ try {
|
{ try {
|
||||||
vector<commitment_type> in(inputs.size());
|
vector<commitment_type> in(inputs.size());
|
||||||
|
|
@ -122,17 +91,6 @@ void blind_transfer_operation::validate()const
|
||||||
FC_ASSERT( !outputs[i].owner.is_impossible() );
|
FC_ASSERT( !outputs[i].owner.is_impossible() );
|
||||||
}
|
}
|
||||||
FC_ASSERT( in.size(), "there must be at least one input" );
|
FC_ASSERT( in.size(), "there must be at least one input" );
|
||||||
FC_ASSERT( fc::ecc::verify_sum( in, out, net_public ), "", ("net_public", net_public) );
|
|
||||||
|
|
||||||
if( outputs.size() > 1 )
|
|
||||||
{
|
|
||||||
for( auto out : outputs )
|
|
||||||
{
|
|
||||||
auto info = fc::ecc::range_get_info( out.range_proof );
|
|
||||||
FC_ASSERT( info.max_value <= GRAPHENE_MAX_SHARE_SUPPLY );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FC_ASSERT( fc::ecc::verify_sum( in, out, net_public ), "", ("net_public", net_public) );
|
|
||||||
} FC_CAPTURE_AND_RETHROW( (*this) ) }
|
} FC_CAPTURE_AND_RETHROW( (*this) ) }
|
||||||
|
|
||||||
share_type blind_transfer_operation::calculate_fee( const fee_parameters_type& k )const
|
share_type blind_transfer_operation::calculate_fee( const fee_parameters_type& k )const
|
||||||
|
|
@ -140,16 +98,12 @@ share_type blind_transfer_operation::calculate_fee( const fee_parameters_type& k
|
||||||
return k.fee + outputs.size() * k.price_per_output;
|
return k.fee + outputs.size() * k.price_per_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Packs *this then encodes as base58 encoded string.
|
|
||||||
*/
|
|
||||||
stealth_confirmation::operator string()const
|
stealth_confirmation::operator string()const
|
||||||
{
|
{
|
||||||
return fc::to_base58( fc::raw::pack( *this ) );
|
return fc::to_base58( fc::raw::pack( *this ) );
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Unpacks from a base58 string
|
|
||||||
*/
|
|
||||||
stealth_confirmation::stealth_confirmation( const std::string& base58 )
|
stealth_confirmation::stealth_confirmation( const std::string& base58 )
|
||||||
{
|
{
|
||||||
*this = fc::raw::unpack<stealth_confirmation>( fc::from_base58( base58 ) );
|
*this = fc::raw::unpack<stealth_confirmation>( fc::from_base58( base58 ) );
|
||||||
|
|
@ -157,6 +111,8 @@ stealth_confirmation::stealth_confirmation( const std::string& base58 )
|
||||||
|
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transfer_to_blind_operation::fee_parameters_type )
|
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transfer_to_blind_operation::fee_parameters_type )
|
||||||
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transfer_from_blind_operation::fee_parameters_type )
|
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transfer_from_blind_operation::fee_parameters_type )
|
||||||
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::blind_transfer_operation::fee_parameters_type )
|
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::blind_transfer_operation::fee_parameters_type )
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ void_result update_sidechain_address_evaluator::do_evaluate(const sidechain_addr
|
||||||
{ try {
|
{ try {
|
||||||
const auto& sidx = db().get_index_type<son_index>().indices().get<by_account>();
|
const auto& sidx = db().get_index_type<son_index>().indices().get<by_account>();
|
||||||
const auto& son_obj = sidx.find(op.payer);
|
const auto& son_obj = sidx.find(op.payer);
|
||||||
FC_ASSERT( son_obj != sidx.end() && db().is_son_active(son_obj->id), "Non active SON trying to update deposit address object" );
|
FC_ASSERT( son_obj != sidx.end() && db().is_son_active(op.sidechain, son_obj->id), "Non active SON trying to update deposit address object" );
|
||||||
const auto& sdpke_idx = db().get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_public_key_and_expires>();
|
const auto& sdpke_idx = db().get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_public_key_and_expires>();
|
||||||
FC_ASSERT( op.deposit_address.valid() && op.deposit_public_key.valid() && op.deposit_address_data.valid(), "Update operation by SON is not valid");
|
FC_ASSERT( op.deposit_address.valid() && op.deposit_public_key.valid() && op.deposit_address_data.valid(), "Update operation by SON is not valid");
|
||||||
FC_ASSERT( (*op.deposit_address).length() > 0 && (*op.deposit_public_key).length() > 0 && (*op.deposit_address_data).length() > 0, "SON should create a valid deposit address with valid deposit public key");
|
FC_ASSERT( (*op.deposit_address).length() > 0 && (*op.deposit_public_key).length() > 0 && (*op.deposit_address_data).length() > 0, "SON should create a valid deposit address with valid deposit public key");
|
||||||
|
|
@ -108,7 +108,6 @@ void_result delete_sidechain_address_evaluator::do_apply(const sidechain_address
|
||||||
{ try {
|
{ try {
|
||||||
const auto& idx = db().get_index_type<sidechain_address_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<sidechain_address_index>().indices().get<by_id>();
|
||||||
auto sidechain_address = idx.find(op.sidechain_address_id);
|
auto sidechain_address = idx.find(op.sidechain_address_id);
|
||||||
|
|
||||||
if (sidechain_address != idx.end()) {
|
if (sidechain_address != idx.end()) {
|
||||||
if (db().head_block_time() >= HARDFORK_SIDECHAIN_DELETE_TIME) {
|
if (db().head_block_time() >= HARDFORK_SIDECHAIN_DELETE_TIME) {
|
||||||
db().remove(*sidechain_address);
|
db().remove(*sidechain_address);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ namespace graphene { namespace chain {
|
||||||
void_result sidechain_transaction_create_evaluator::do_evaluate(const sidechain_transaction_create_operation &op)
|
void_result sidechain_transaction_create_evaluator::do_evaluate(const sidechain_transaction_create_operation &op)
|
||||||
{ try {
|
{ try {
|
||||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
||||||
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
|
FC_ASSERT(op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer.");
|
||||||
|
|
||||||
FC_ASSERT((op.object_id.is<son_wallet_id_type>() || op.object_id.is<son_wallet_deposit_id_type>() || op.object_id.is<son_wallet_withdraw_id_type>()), "Invalid object id");
|
FC_ASSERT((op.object_id.is<son_wallet_id_type>() || op.object_id.is<son_wallet_deposit_id_type>() || op.object_id.is<son_wallet_withdraw_id_type>()), "Invalid object id");
|
||||||
|
|
||||||
|
|
@ -28,15 +28,26 @@ void_result sidechain_transaction_create_evaluator::do_evaluate(const sidechain_
|
||||||
object_id_type sidechain_transaction_create_evaluator::do_apply(const sidechain_transaction_create_operation &op)
|
object_id_type sidechain_transaction_create_evaluator::do_apply(const sidechain_transaction_create_operation &op)
|
||||||
{ try {
|
{ try {
|
||||||
const auto &new_sidechain_transaction_object = db().create<sidechain_transaction_object>([&](sidechain_transaction_object &sto) {
|
const auto &new_sidechain_transaction_object = db().create<sidechain_transaction_object>([&](sidechain_transaction_object &sto) {
|
||||||
|
|
||||||
sto.timestamp = db().head_block_time();
|
sto.timestamp = db().head_block_time();
|
||||||
sto.sidechain = op.sidechain;
|
sto.sidechain = op.sidechain;
|
||||||
sto.object_id = op.object_id;
|
sto.object_id = op.object_id;
|
||||||
sto.transaction = op.transaction;
|
sto.transaction = op.transaction;
|
||||||
sto.signers = op.signers;
|
std::vector<son_sidechain_info> signers;
|
||||||
std::transform(op.signers.begin(), op.signers.end(), std::inserter(sto.signatures, sto.signatures.end()), [](const son_info &si) {
|
for(const auto& signer : op.signers){
|
||||||
|
son_sidechain_info ssi;
|
||||||
|
ssi.son_id = signer.son_id;
|
||||||
|
ssi.weight = signer.weight;
|
||||||
|
ssi.signing_key = signer.signing_key;
|
||||||
|
ssi.public_key = signer.sidechain_public_keys.at(op.sidechain);
|
||||||
|
signers.emplace_back(std::move(ssi));
|
||||||
|
}
|
||||||
|
sto.signers = std::move(signers);
|
||||||
|
|
||||||
|
std::transform(sto.signers.begin(), sto.signers.end(), std::inserter(sto.signatures, sto.signatures.end()), [](const son_sidechain_info &si) {
|
||||||
return std::make_pair(si.son_id, std::string());
|
return std::make_pair(si.son_id, std::string());
|
||||||
});
|
});
|
||||||
for (const auto &si : op.signers) {
|
for (const auto &si : sto.signers) {
|
||||||
sto.total_weight = sto.total_weight + si.weight;
|
sto.total_weight = sto.total_weight + si.weight;
|
||||||
}
|
}
|
||||||
sto.sidechain_transaction = "";
|
sto.sidechain_transaction = "";
|
||||||
|
|
|
||||||
|
|
@ -39,13 +39,28 @@ void_result create_son_evaluator::do_evaluate(const son_create_operation& op)
|
||||||
object_id_type create_son_evaluator::do_apply(const son_create_operation& op)
|
object_id_type create_son_evaluator::do_apply(const son_create_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
vote_id_type vote_id;
|
vote_id_type vote_id;
|
||||||
db().modify(db().get_global_properties(), [&vote_id](global_property_object& p) {
|
flat_map<sidechain_type, vote_id_type> vote_ids;
|
||||||
vote_id = get_next_vote_id(p, vote_id_type::son);
|
|
||||||
});
|
|
||||||
|
|
||||||
const auto& new_son_object = db().create<son_object>( [&]( son_object& obj ){
|
const auto now = db().head_block_time();
|
||||||
|
if( now < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
|
||||||
|
db().modify(db().get_global_properties(), [&vote_id](global_property_object &p) {
|
||||||
|
vote_id = get_next_vote_id(p, vote_id_type::son_bitcoin);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
db().modify(db().get_global_properties(), [&vote_ids](global_property_object &p) {
|
||||||
|
vote_ids[sidechain_type::bitcoin] = get_next_vote_id(p, vote_id_type::son_bitcoin);
|
||||||
|
vote_ids[sidechain_type::hive] = get_next_vote_id(p, vote_id_type::son_hive);
|
||||||
|
vote_ids[sidechain_type::ethereum] = get_next_vote_id(p, vote_id_type::son_ethereum);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& new_son_object = db().create<son_object>( [&]( son_object& obj ) {
|
||||||
obj.son_account = op.owner_account;
|
obj.son_account = op.owner_account;
|
||||||
obj.vote_id = vote_id;
|
if( now < HARDFORK_SON_FOR_ETHEREUM_TIME )
|
||||||
|
obj.sidechain_vote_ids[sidechain_type::bitcoin] = vote_id;
|
||||||
|
else
|
||||||
|
obj.sidechain_vote_ids = vote_ids;
|
||||||
obj.url = op.url;
|
obj.url = op.url;
|
||||||
obj.deposit = op.deposit;
|
obj.deposit = op.deposit;
|
||||||
obj.signing_key = op.signing_key;
|
obj.signing_key = op.signing_key;
|
||||||
|
|
@ -94,7 +109,8 @@ object_id_type update_son_evaluator::do_apply(const son_update_operation& op)
|
||||||
if(op.new_signing_key.valid()) so.signing_key = *op.new_signing_key;
|
if(op.new_signing_key.valid()) so.signing_key = *op.new_signing_key;
|
||||||
if(op.new_sidechain_public_keys.valid()) so.sidechain_public_keys = *op.new_sidechain_public_keys;
|
if(op.new_sidechain_public_keys.valid()) so.sidechain_public_keys = *op.new_sidechain_public_keys;
|
||||||
if(op.new_pay_vb.valid()) so.pay_vb = *op.new_pay_vb;
|
if(op.new_pay_vb.valid()) so.pay_vb = *op.new_pay_vb;
|
||||||
if(so.status == son_status::deregistered) so.status = son_status::inactive;
|
for(auto& status : so.statuses)
|
||||||
|
if(status.second == son_status::deregistered) status.second = son_status::inactive;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return op.son_id;
|
return op.son_id;
|
||||||
|
|
@ -127,7 +143,8 @@ void_result deregister_son_evaluator::do_apply(const son_deregister_operation& o
|
||||||
});
|
});
|
||||||
|
|
||||||
db().modify(*son, [&op](son_object &so) {
|
db().modify(*son, [&op](son_object &so) {
|
||||||
so.status = son_status::deregistered;
|
for(auto& status : so.statuses)
|
||||||
|
status.second = son_status::deregistered;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto stats_obj = ss_idx.find(son->statistics);
|
auto stats_obj = ss_idx.find(son->statistics);
|
||||||
|
|
@ -144,18 +161,28 @@ void_result son_heartbeat_evaluator::do_evaluate(const son_heartbeat_operation&
|
||||||
{ try {
|
{ try {
|
||||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); // can be removed after HF date pass
|
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); // can be removed after HF date pass
|
||||||
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
||||||
auto itr = idx.find(op.son_id);
|
const auto itr = idx.find(op.son_id);
|
||||||
FC_ASSERT( itr != idx.end() );
|
FC_ASSERT( itr != idx.end() );
|
||||||
FC_ASSERT(itr->son_account == op.owner_account);
|
FC_ASSERT(itr->son_account == op.owner_account);
|
||||||
auto stats = itr->statistics( db() );
|
auto stats = itr->statistics( db() );
|
||||||
// Inactive SONs need not send heartbeats
|
// Inactive SONs need not send heartbeats
|
||||||
FC_ASSERT((itr->status == son_status::active) || (itr->status == son_status::in_maintenance) || (itr->status == son_status::request_maintenance), "Inactive SONs need not send heartbeats");
|
bool status_need_to_send_heartbeats = false;
|
||||||
|
for(const auto& status : itr->statuses)
|
||||||
|
{
|
||||||
|
if( (status.second == son_status::active) || (status.second == son_status::in_maintenance) || (status.second == son_status::request_maintenance) )
|
||||||
|
status_need_to_send_heartbeats = true;
|
||||||
|
}
|
||||||
|
FC_ASSERT(status_need_to_send_heartbeats, "Inactive SONs need not send heartbeats");
|
||||||
// Account for network delays
|
// Account for network delays
|
||||||
fc::time_point_sec min_ts = db().head_block_time() - fc::seconds(5 * db().block_interval());
|
fc::time_point_sec min_ts = db().head_block_time() - fc::seconds(5 * db().block_interval());
|
||||||
// Account for server ntp sync difference
|
// Account for server ntp sync difference
|
||||||
fc::time_point_sec max_ts = db().head_block_time() + fc::seconds(5 * db().block_interval());
|
fc::time_point_sec max_ts = db().head_block_time() + fc::seconds(5 * db().block_interval());
|
||||||
FC_ASSERT(op.ts > stats.last_active_timestamp, "Heartbeat sent without waiting minimum time");
|
for(const auto& active_sidechain_type : active_sidechain_types(db().head_block_time())) {
|
||||||
FC_ASSERT(op.ts > stats.last_down_timestamp, "Heartbeat sent is invalid can't be <= last down timestamp");
|
if(stats.last_active_timestamp.contains(active_sidechain_type))
|
||||||
|
FC_ASSERT(op.ts > stats.last_active_timestamp.at(active_sidechain_type), "Heartbeat sent for sidechain = ${sidechain} without waiting minimum time", ("sidechain", active_sidechain_type));
|
||||||
|
if(stats.last_down_timestamp.contains(active_sidechain_type))
|
||||||
|
FC_ASSERT(op.ts > stats.last_down_timestamp.at(active_sidechain_type), "Heartbeat sent for sidechain = ${sidechain} is invalid can't be <= last down timestamp", ("sidechain", active_sidechain_type));
|
||||||
|
}
|
||||||
FC_ASSERT(op.ts >= min_ts, "Heartbeat ts is behind the min threshold");
|
FC_ASSERT(op.ts >= min_ts, "Heartbeat ts is behind the min threshold");
|
||||||
FC_ASSERT(op.ts <= max_ts, "Heartbeat ts is above the max threshold");
|
FC_ASSERT(op.ts <= max_ts, "Heartbeat ts is above the max threshold");
|
||||||
return void_result();
|
return void_result();
|
||||||
|
|
@ -164,44 +191,48 @@ void_result son_heartbeat_evaluator::do_evaluate(const son_heartbeat_operation&
|
||||||
object_id_type son_heartbeat_evaluator::do_apply(const son_heartbeat_operation& op)
|
object_id_type son_heartbeat_evaluator::do_apply(const son_heartbeat_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
||||||
auto itr = idx.find(op.son_id);
|
const auto itr = idx.find(op.son_id);
|
||||||
if(itr != idx.end())
|
if(itr != idx.end())
|
||||||
{
|
{
|
||||||
const global_property_object& gpo = db().get_global_properties();
|
const global_property_object& gpo = db().get_global_properties();
|
||||||
vector<son_id_type> active_son_ids;
|
|
||||||
active_son_ids.reserve(gpo.active_sons.size());
|
|
||||||
std::transform(gpo.active_sons.begin(), gpo.active_sons.end(),
|
|
||||||
std::inserter(active_son_ids, active_son_ids.end()),
|
|
||||||
[](const son_info& swi) {
|
|
||||||
return swi.son_id;
|
|
||||||
});
|
|
||||||
|
|
||||||
auto it_son = std::find(active_son_ids.begin(), active_son_ids.end(), op.son_id);
|
for(const auto& active_sidechain_sons : gpo.active_sons) {
|
||||||
bool is_son_active = true;
|
const auto& sidechain = active_sidechain_sons.first;
|
||||||
|
const auto& active_sons = active_sidechain_sons.second;
|
||||||
|
|
||||||
if(it_son == active_son_ids.end()) {
|
vector<son_id_type> active_son_ids;
|
||||||
is_son_active = false;
|
active_son_ids.reserve(active_sons.size());
|
||||||
}
|
std::transform(active_sons.cbegin(), active_sons.cend(),
|
||||||
|
std::inserter(active_son_ids, active_son_ids.end()),
|
||||||
|
[](const son_sidechain_info &swi) {
|
||||||
|
return swi.son_id;
|
||||||
|
});
|
||||||
|
|
||||||
if(itr->status == son_status::in_maintenance) {
|
const auto it_son = std::find(active_son_ids.begin(), active_son_ids.end(), op.son_id);
|
||||||
db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso )
|
bool is_son_active = true;
|
||||||
{
|
|
||||||
sso.current_interval_downtime += op.ts.sec_since_epoch() - sso.last_down_timestamp.sec_since_epoch();
|
|
||||||
sso.last_active_timestamp = op.ts;
|
|
||||||
} );
|
|
||||||
|
|
||||||
db().modify(*itr, [&is_son_active](son_object &so) {
|
if (it_son == active_son_ids.end()) {
|
||||||
if(is_son_active) {
|
is_son_active = false;
|
||||||
so.status = son_status::active;
|
}
|
||||||
} else {
|
|
||||||
so.status = son_status::inactive;
|
if (itr->statuses.at(sidechain) == son_status::in_maintenance) {
|
||||||
}
|
db().modify(itr->statistics(db()), [&](son_statistics_object &sso) {
|
||||||
});
|
sso.current_interval_downtime[sidechain] += op.ts.sec_since_epoch() - (sso.last_down_timestamp.contains(sidechain) ? sso.last_down_timestamp.at(sidechain).sec_since_epoch() : op.ts.sec_since_epoch());
|
||||||
} else if ((itr->status == son_status::active) || (itr->status == son_status::request_maintenance)) {
|
sso.last_active_timestamp[sidechain] = op.ts;
|
||||||
db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso )
|
});
|
||||||
{
|
|
||||||
sso.last_active_timestamp = op.ts;
|
db().modify(*itr, [&is_son_active, &sidechain](son_object &so) {
|
||||||
} );
|
if (is_son_active) {
|
||||||
|
so.statuses[sidechain] = son_status::active;
|
||||||
|
} else {
|
||||||
|
so.statuses[sidechain] = son_status::inactive;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if ((itr->statuses.at(sidechain) == son_status::active) || (itr->statuses.at(sidechain) == son_status::request_maintenance)) {
|
||||||
|
db().modify(itr->statistics(db()), [&](son_statistics_object &sso) {
|
||||||
|
sso.last_active_timestamp[sidechain] = op.ts;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return op.son_id;
|
return op.son_id;
|
||||||
|
|
@ -213,29 +244,41 @@ void_result son_report_down_evaluator::do_evaluate(const son_report_down_operati
|
||||||
FC_ASSERT(op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer.");
|
FC_ASSERT(op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer.");
|
||||||
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
||||||
FC_ASSERT( idx.find(op.son_id) != idx.end() );
|
FC_ASSERT( idx.find(op.son_id) != idx.end() );
|
||||||
auto itr = idx.find(op.son_id);
|
const auto itr = idx.find(op.son_id);
|
||||||
auto stats = itr->statistics( db() );
|
const auto stats = itr->statistics( db() );
|
||||||
FC_ASSERT(itr->status == son_status::active || itr->status == son_status::request_maintenance, "Inactive/Deregistered/in_maintenance SONs cannot be reported on as down");
|
bool status_need_to_report_down = false;
|
||||||
FC_ASSERT(op.down_ts >= stats.last_active_timestamp, "down_ts should be greater than last_active_timestamp");
|
for(const auto& status : itr->statuses)
|
||||||
|
{
|
||||||
|
if( (status.second == son_status::active) || (status.second == son_status::request_maintenance) )
|
||||||
|
status_need_to_report_down = true;
|
||||||
|
}
|
||||||
|
FC_ASSERT(status_need_to_report_down, "Inactive/Deregistered/in_maintenance SONs cannot be reported on as down");
|
||||||
|
for(const auto& active_sidechain_type : active_sidechain_types(db().head_block_time())) {
|
||||||
|
if(stats.last_active_timestamp.contains(active_sidechain_type))
|
||||||
|
FC_ASSERT(op.down_ts >= stats.last_active_timestamp.at(active_sidechain_type), "sidechain = ${sidechain} down_ts should be greater than last_active_timestamp", ("sidechain", active_sidechain_type));
|
||||||
|
}
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
object_id_type son_report_down_evaluator::do_apply(const son_report_down_operation& op)
|
object_id_type son_report_down_evaluator::do_apply(const son_report_down_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
||||||
auto itr = idx.find(op.son_id);
|
const auto itr = idx.find(op.son_id);
|
||||||
if(itr != idx.end())
|
if(itr != idx.end())
|
||||||
{
|
{
|
||||||
if ((itr->status == son_status::active) || (itr->status == son_status::request_maintenance)) {
|
for( const auto& status : itr->statuses ) {
|
||||||
db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso )
|
const auto& sidechain = status.first;
|
||||||
{
|
|
||||||
sso.last_down_timestamp = op.down_ts;
|
|
||||||
});
|
|
||||||
|
|
||||||
db().modify(*itr, [&op](son_object &so) {
|
if ((status.second == son_status::active) || (status.second == son_status::request_maintenance)) {
|
||||||
so.status = son_status::in_maintenance;
|
db().modify(*itr, [&sidechain](son_object &so) {
|
||||||
});
|
so.statuses[sidechain] = son_status::in_maintenance;
|
||||||
}
|
});
|
||||||
|
|
||||||
|
db().modify(itr->statistics(db()), [&](son_statistics_object &sso) {
|
||||||
|
sso.last_down_timestamp[sidechain] = op.down_ts;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return op.son_id;
|
return op.son_id;
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
@ -249,9 +292,19 @@ void_result son_maintenance_evaluator::do_evaluate(const son_maintenance_operati
|
||||||
FC_ASSERT( itr != idx.end() );
|
FC_ASSERT( itr != idx.end() );
|
||||||
// Inactive SONs can't go to maintenance, toggle between active and request_maintenance states
|
// Inactive SONs can't go to maintenance, toggle between active and request_maintenance states
|
||||||
if(op.request_type == son_maintenance_request_type::request_maintenance) {
|
if(op.request_type == son_maintenance_request_type::request_maintenance) {
|
||||||
FC_ASSERT(itr->status == son_status::active, "Inactive SONs can't request for maintenance");
|
bool status_active = false;
|
||||||
} else if(op.request_type == son_maintenance_request_type::cancel_request_maintenance) {
|
for(const auto& status : itr->statuses) {
|
||||||
FC_ASSERT(itr->status == son_status::request_maintenance, "Only maintenance requested SONs can cancel the request");
|
if( (status.second == son_status::active) )
|
||||||
|
status_active = true;
|
||||||
|
}
|
||||||
|
FC_ASSERT(status_active, "Inactive SONs can't request for maintenance");
|
||||||
|
} else if(op.request_type == son_maintenance_request_type::cancel_request_maintenance) {
|
||||||
|
bool status_request_maintenance = false;
|
||||||
|
for(const auto& status : itr->statuses) {
|
||||||
|
if( (status.second == son_status::request_maintenance) )
|
||||||
|
status_request_maintenance = true;
|
||||||
|
}
|
||||||
|
FC_ASSERT(status_request_maintenance, "Only maintenance requested SONs can cancel the request");
|
||||||
} else {
|
} else {
|
||||||
FC_ASSERT(false, "Invalid maintenance operation");
|
FC_ASSERT(false, "Invalid maintenance operation");
|
||||||
}
|
}
|
||||||
|
|
@ -264,15 +317,33 @@ object_id_type son_maintenance_evaluator::do_apply(const son_maintenance_operati
|
||||||
auto itr = idx.find(op.son_id);
|
auto itr = idx.find(op.son_id);
|
||||||
if(itr != idx.end())
|
if(itr != idx.end())
|
||||||
{
|
{
|
||||||
if(itr->status == son_status::active && op.request_type == son_maintenance_request_type::request_maintenance) {
|
bool status_active = false;
|
||||||
db().modify(*itr, [](son_object &so) {
|
for(const auto& status : itr->statuses) {
|
||||||
so.status = son_status::request_maintenance;
|
if( (status.second == son_status::active) )
|
||||||
});
|
status_active = true;
|
||||||
} else if(itr->status == son_status::request_maintenance && op.request_type == son_maintenance_request_type::cancel_request_maintenance) {
|
}
|
||||||
db().modify(*itr, [](son_object &so) {
|
if(status_active && op.request_type == son_maintenance_request_type::request_maintenance) {
|
||||||
so.status = son_status::active;
|
db().modify(*itr, [](son_object &so) {
|
||||||
});
|
for(auto& status : so.statuses) {
|
||||||
}
|
status.second = son_status::request_maintenance;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool status_request_maintenance = false;
|
||||||
|
for(const auto& status : itr->statuses) {
|
||||||
|
if( (status.second == son_status::request_maintenance) )
|
||||||
|
status_request_maintenance = true;
|
||||||
|
}
|
||||||
|
if(status_request_maintenance && op.request_type == son_maintenance_request_type::cancel_request_maintenance) {
|
||||||
|
db().modify(*itr, [](son_object &so) {
|
||||||
|
for(auto& status : so.statuses) {
|
||||||
|
status.second = son_status::active;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return op.son_id;
|
return op.son_id;
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
|
||||||
|
|
@ -6,20 +6,22 @@ namespace graphene { namespace chain {
|
||||||
db.adjust_balance(son_account, pay);
|
db.adjust_balance(son_account, pay);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool son_object::has_valid_config()const {
|
bool son_object::has_valid_config(sidechain_type sidechain) const {
|
||||||
return ((std::string(signing_key).length() > 0) &&
|
return (sidechain_public_keys.find( sidechain ) != sidechain_public_keys.end()) &&
|
||||||
(sidechain_public_keys.size() > 0) &&
|
(sidechain_public_keys.at(sidechain).length() > 0);
|
||||||
(sidechain_public_keys.find( sidechain_type::bitcoin ) != sidechain_public_keys.end()) &&
|
|
||||||
(sidechain_public_keys.at(sidechain_type::bitcoin).length() > 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool son_object::has_valid_config(time_point_sec head_block_time)const {
|
bool son_object::has_valid_config(time_point_sec head_block_time, sidechain_type sidechain) const {
|
||||||
bool retval = has_valid_config();
|
bool retval = (std::string(signing_key).length() > 0) && (sidechain_public_keys.size() > 0);
|
||||||
|
|
||||||
if (head_block_time >= HARDFORK_SON_FOR_HIVE_TIME) {
|
if (head_block_time < HARDFORK_SON_FOR_HIVE_TIME) {
|
||||||
retval = retval &&
|
retval = retval && has_valid_config(sidechain_type::bitcoin);
|
||||||
(sidechain_public_keys.find( sidechain_type::hive ) != sidechain_public_keys.end()) &&
|
}
|
||||||
(sidechain_public_keys.at(sidechain_type::hive).length() > 0);
|
if (head_block_time >= HARDFORK_SON_FOR_HIVE_TIME && head_block_time < HARDFORK_SON_FOR_ETHEREUM_TIME) {
|
||||||
|
retval = retval && has_valid_config(sidechain_type::bitcoin) && has_valid_config(sidechain_type::hive);
|
||||||
|
}
|
||||||
|
else if (head_block_time >= HARDFORK_SON_FOR_ETHEREUM_TIME) {
|
||||||
|
retval = retval && has_valid_config(sidechain);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ void_result create_son_wallet_deposit_evaluator::do_evaluate(const son_wallet_de
|
||||||
const auto &swdo_idx = db().get_index_type<son_wallet_deposit_index>().indices().get<by_sidechain_uid>();
|
const auto &swdo_idx = db().get_index_type<son_wallet_deposit_index>().indices().get<by_sidechain_uid>();
|
||||||
const auto swdo = swdo_idx.find(op.sidechain_uid);
|
const auto swdo = swdo_idx.find(op.sidechain_uid);
|
||||||
if (swdo == swdo_idx.end()) {
|
if (swdo == swdo_idx.end()) {
|
||||||
auto &gpo = db().get_global_properties();
|
const auto &gpo = db().get_global_properties();
|
||||||
bool expected = false;
|
bool expected = false;
|
||||||
for (auto &si : gpo.active_sons) {
|
for (auto &si : gpo.active_sons.at(op.sidechain)) {
|
||||||
if (op.son_id == si.son_id) {
|
if (op.son_id == si.son_id) {
|
||||||
expected = true;
|
expected = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -78,8 +78,8 @@ object_id_type create_son_wallet_deposit_evaluator::do_apply(const son_wallet_de
|
||||||
swdo.peerplays_to = op.peerplays_to;
|
swdo.peerplays_to = op.peerplays_to;
|
||||||
swdo.peerplays_asset = op.peerplays_asset;
|
swdo.peerplays_asset = op.peerplays_asset;
|
||||||
|
|
||||||
auto &gpo = db().get_global_properties();
|
const auto &gpo = db().get_global_properties();
|
||||||
for (auto &si : gpo.active_sons) {
|
for (auto &si : gpo.active_sons.at(op.sidechain)) {
|
||||||
swdo.expected_reports.insert(std::make_pair(si.son_id, si.weight));
|
swdo.expected_reports.insert(std::make_pair(si.son_id, si.weight));
|
||||||
|
|
||||||
auto stats_itr = db().get_index_type<son_stats_index>().indices().get<by_owner>().find(si.son_id);
|
auto stats_itr = db().get_index_type<son_stats_index>().indices().get<by_owner>().find(si.son_id);
|
||||||
|
|
@ -142,11 +142,11 @@ void_result process_son_wallet_deposit_evaluator::do_evaluate(const son_wallet_d
|
||||||
{ try{
|
{ try{
|
||||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
||||||
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
|
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
|
||||||
FC_ASSERT(db().get_global_properties().active_sons.size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present");
|
|
||||||
|
|
||||||
const auto& idx = db().get_index_type<son_wallet_deposit_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_wallet_deposit_index>().indices().get<by_id>();
|
||||||
const auto& itr = idx.find(op.son_wallet_deposit_id);
|
const auto& itr = idx.find(op.son_wallet_deposit_id);
|
||||||
FC_ASSERT(itr != idx.end(), "Son wallet deposit not found");
|
FC_ASSERT(itr != idx.end(), "Son wallet deposit not found");
|
||||||
|
FC_ASSERT(db().get_global_properties().active_sons.at(itr->sidechain).size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present");
|
||||||
FC_ASSERT(!itr->processed, "Son wallet deposit is already processed");
|
FC_ASSERT(!itr->processed, "Son wallet deposit is already processed");
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
void_result recreate_son_wallet_evaluator::do_evaluate(const son_wallet_recreate_operation& op)
|
void_result recreate_son_wallet_evaluator::do_evaluate(const son_wallet_recreate_operation& op)
|
||||||
{ try{
|
{ try{
|
||||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
const auto now = db().head_block_time();
|
||||||
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
|
FC_ASSERT(now >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
||||||
|
FC_ASSERT(op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer.");
|
||||||
|
|
||||||
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||||
auto itr = idx.rbegin();
|
auto itr = idx.rbegin();
|
||||||
|
|
@ -16,12 +17,36 @@ void_result recreate_son_wallet_evaluator::do_evaluate(const son_wallet_recreate
|
||||||
{
|
{
|
||||||
// Compare current wallet SONs and to-be lists of active sons
|
// Compare current wallet SONs and to-be lists of active sons
|
||||||
auto cur_wallet_sons = (*itr).sons;
|
auto cur_wallet_sons = (*itr).sons;
|
||||||
auto new_wallet_sons = op.sons;
|
flat_map<sidechain_type, vector<son_sidechain_info> > new_wallet_sons;
|
||||||
|
if( now < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
|
||||||
|
for(const auto& son : op.sons){
|
||||||
|
for(const auto& active_sidechain_type : active_sidechain_types(db().head_block_time())){
|
||||||
|
son_sidechain_info ssi;
|
||||||
|
ssi.son_id = son.son_id;
|
||||||
|
ssi.weight = son.weight;
|
||||||
|
ssi.signing_key = son.signing_key;
|
||||||
|
ssi.public_key = son.sidechain_public_keys.at(active_sidechain_type);
|
||||||
|
new_wallet_sons[active_sidechain_type].emplace_back(std::move(ssi));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
FC_ASSERT(op.extensions.value.sidechain_sons.valid(), "Sons is not valid");
|
||||||
|
new_wallet_sons = *op.extensions.value.sidechain_sons;
|
||||||
|
}
|
||||||
|
|
||||||
bool son_sets_equal = (cur_wallet_sons.size() == new_wallet_sons.size());
|
bool son_sets_equal = (cur_wallet_sons.size() == new_wallet_sons.size());
|
||||||
if (son_sets_equal) {
|
if (son_sets_equal) {
|
||||||
for( size_t i = 0; i < cur_wallet_sons.size(); i++ ) {
|
for( const auto& cur_wallet_sidechain_sons : cur_wallet_sons ) {
|
||||||
son_sets_equal = son_sets_equal && cur_wallet_sons.at(i) == new_wallet_sons.at(i);
|
const auto& sidechain = cur_wallet_sidechain_sons.first;
|
||||||
|
const auto& _cur_wallet_sidechain_sons = cur_wallet_sidechain_sons.second;
|
||||||
|
|
||||||
|
son_sets_equal = son_sets_equal && (_cur_wallet_sidechain_sons.size() == new_wallet_sons.at(sidechain).size());
|
||||||
|
if (son_sets_equal) {
|
||||||
|
for (size_t i = 0; i < cur_wallet_sons.size(); i++) {
|
||||||
|
son_sets_equal = son_sets_equal && _cur_wallet_sidechain_sons.at(i) == new_wallet_sons.at(sidechain).at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,9 +68,26 @@ object_id_type recreate_son_wallet_evaluator::do_apply(const son_wallet_recreate
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& new_son_wallet_object = db().create<son_wallet_object>( [&]( son_wallet_object& obj ){
|
const auto& new_son_wallet_object = db().create<son_wallet_object>( [&]( son_wallet_object& obj ){
|
||||||
obj.valid_from = db().head_block_time();
|
const auto now = db().head_block_time();
|
||||||
|
obj.valid_from = now;
|
||||||
obj.expires = time_point_sec::maximum();
|
obj.expires = time_point_sec::maximum();
|
||||||
obj.sons = op.sons;
|
if( now < HARDFORK_SON_FOR_ETHEREUM_TIME ) {
|
||||||
|
flat_map<sidechain_type, vector<son_sidechain_info> > sons;
|
||||||
|
for(const auto& son : op.sons){
|
||||||
|
for(const auto& active_sidechain_type : active_sidechain_types(db().head_block_time())){
|
||||||
|
son_sidechain_info ssi;
|
||||||
|
ssi.son_id = son.son_id;
|
||||||
|
ssi.weight = son.weight;
|
||||||
|
ssi.signing_key = son.signing_key;
|
||||||
|
ssi.public_key = son.sidechain_public_keys.at(active_sidechain_type);
|
||||||
|
sons[active_sidechain_type].emplace_back(std::move(ssi));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.sons = std::move(sons);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
obj.sons = *op.extensions.value.sidechain_sons;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return new_son_wallet_object.id;
|
return new_son_wallet_object.id;
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
@ -55,8 +97,19 @@ void_result update_son_wallet_evaluator::do_evaluate(const son_wallet_update_ope
|
||||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
||||||
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
|
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
|
||||||
|
|
||||||
|
const son_wallet_id_type son_wallet_id = [&]{
|
||||||
|
if(db().head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME)
|
||||||
|
{
|
||||||
|
const auto ast = active_sidechain_types(db().head_block_time());
|
||||||
|
const auto id = (op.son_wallet_id.instance.value - std::distance(ast.begin(), ast.find(op.sidechain))) / ast.size();
|
||||||
|
return son_wallet_id_type{ id };
|
||||||
|
}
|
||||||
|
|
||||||
|
return op.son_wallet_id;
|
||||||
|
}();
|
||||||
|
|
||||||
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||||
FC_ASSERT( idx.find(op.son_wallet_id) != idx.end() );
|
FC_ASSERT( idx.find(son_wallet_id) != idx.end() );
|
||||||
//auto itr = idx.find(op.son_wallet_id);
|
//auto itr = idx.find(op.son_wallet_id);
|
||||||
//FC_ASSERT( itr->addresses.find(op.sidechain) == itr->addresses.end() ||
|
//FC_ASSERT( itr->addresses.find(op.sidechain) == itr->addresses.end() ||
|
||||||
// itr->addresses.at(op.sidechain).empty(), "Sidechain wallet address already set");
|
// itr->addresses.at(op.sidechain).empty(), "Sidechain wallet address already set");
|
||||||
|
|
@ -65,8 +118,19 @@ void_result update_son_wallet_evaluator::do_evaluate(const son_wallet_update_ope
|
||||||
|
|
||||||
object_id_type update_son_wallet_evaluator::do_apply(const son_wallet_update_operation& op)
|
object_id_type update_son_wallet_evaluator::do_apply(const son_wallet_update_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
|
const son_wallet_id_type son_wallet_id = [&]{
|
||||||
|
if(db().head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME)
|
||||||
|
{
|
||||||
|
const auto ast = active_sidechain_types(db().head_block_time());
|
||||||
|
const auto id = (op.son_wallet_id.instance.value - std::distance(ast.begin(), ast.find(op.sidechain))) / ast.size();
|
||||||
|
return son_wallet_id_type{ id };
|
||||||
|
}
|
||||||
|
|
||||||
|
return op.son_wallet_id;
|
||||||
|
}();
|
||||||
|
|
||||||
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||||
auto itr = idx.find(op.son_wallet_id);
|
auto itr = idx.find(son_wallet_id);
|
||||||
if (itr != idx.end())
|
if (itr != idx.end())
|
||||||
{
|
{
|
||||||
if (itr->addresses.find(op.sidechain) == itr->addresses.end()) {
|
if (itr->addresses.find(op.sidechain) == itr->addresses.end()) {
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,13 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
void_result create_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_withdraw_create_operation& op)
|
void_result create_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_withdraw_create_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
const auto now = db().head_block_time();
|
||||||
|
FC_ASSERT(now >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
||||||
const auto &son_idx = db().get_index_type<son_index>().indices().get<by_id>();
|
const auto &son_idx = db().get_index_type<son_index>().indices().get<by_id>();
|
||||||
const auto so = son_idx.find(op.son_id);
|
const auto so = son_idx.find(op.son_id);
|
||||||
FC_ASSERT(so != son_idx.end(), "SON not found");
|
FC_ASSERT(so != son_idx.end(), "SON not found");
|
||||||
FC_ASSERT(so->son_account == op.payer, "Payer is not SON account owner");
|
FC_ASSERT(so->son_account == op.payer, "Payer is not SON account owner");
|
||||||
|
FC_ASSERT(!(op.sidechain == sidechain_type::peerplays && now >= HARDFORK_SON_FOR_ETHEREUM_TIME), "Peerplays sidechain type is not allowed");
|
||||||
|
|
||||||
const auto &ss_idx = db().get_index_type<son_stats_index>().indices().get<by_owner>();
|
const auto &ss_idx = db().get_index_type<son_stats_index>().indices().get<by_owner>();
|
||||||
FC_ASSERT(ss_idx.find(op.son_id) != ss_idx.end(), "Statistic object for a given SON ID does not exists");
|
FC_ASSERT(ss_idx.find(op.son_id) != ss_idx.end(), "Statistic object for a given SON ID does not exists");
|
||||||
|
|
@ -23,15 +24,23 @@ void_result create_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_w
|
||||||
const auto &swwo_idx = db().get_index_type<son_wallet_withdraw_index>().indices().get<by_peerplays_uid>();
|
const auto &swwo_idx = db().get_index_type<son_wallet_withdraw_index>().indices().get<by_peerplays_uid>();
|
||||||
const auto swwo = swwo_idx.find(op.peerplays_uid);
|
const auto swwo = swwo_idx.find(op.peerplays_uid);
|
||||||
if (swwo == swwo_idx.end()) {
|
if (swwo == swwo_idx.end()) {
|
||||||
auto &gpo = db().get_global_properties();
|
const sidechain_type sidechain = [&op]{
|
||||||
|
if(op.sidechain == sidechain_type::peerplays){
|
||||||
|
return op.withdraw_sidechain;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return op.sidechain;
|
||||||
|
}();
|
||||||
|
|
||||||
|
const auto &gpo = db().get_global_properties();
|
||||||
bool expected = false;
|
bool expected = false;
|
||||||
for (auto &si : gpo.active_sons) {
|
for (auto &si : gpo.active_sons.at(sidechain)) {
|
||||||
if (op.son_id == si.son_id) {
|
if (op.son_id == si.son_id) {
|
||||||
expected = true;
|
expected = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FC_ASSERT(expected, "Only active SON can create deposit");
|
FC_ASSERT(expected, "Only active SON can create withdraw");
|
||||||
} else {
|
} else {
|
||||||
bool exactly_the_same = true;
|
bool exactly_the_same = true;
|
||||||
exactly_the_same = exactly_the_same && (swwo->sidechain == op.sidechain);
|
exactly_the_same = exactly_the_same && (swwo->sidechain == op.sidechain);
|
||||||
|
|
@ -76,8 +85,16 @@ object_id_type create_son_wallet_withdraw_evaluator::do_apply(const son_wallet_w
|
||||||
swwo.withdraw_currency = op.withdraw_currency;
|
swwo.withdraw_currency = op.withdraw_currency;
|
||||||
swwo.withdraw_amount = op.withdraw_amount;
|
swwo.withdraw_amount = op.withdraw_amount;
|
||||||
|
|
||||||
auto &gpo = db().get_global_properties();
|
const sidechain_type sidechain = [&op]{
|
||||||
for (auto &si : gpo.active_sons) {
|
if(op.sidechain == sidechain_type::peerplays){
|
||||||
|
return op.withdraw_sidechain;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return op.sidechain;
|
||||||
|
}();
|
||||||
|
|
||||||
|
const auto &gpo = db().get_global_properties();
|
||||||
|
for (auto &si : gpo.active_sons.at(sidechain)) {
|
||||||
swwo.expected_reports.insert(std::make_pair(si.son_id, si.weight));
|
swwo.expected_reports.insert(std::make_pair(si.son_id, si.weight));
|
||||||
|
|
||||||
auto stats_itr = db().get_index_type<son_stats_index>().indices().get<by_owner>().find(si.son_id);
|
auto stats_itr = db().get_index_type<son_stats_index>().indices().get<by_owner>().find(si.son_id);
|
||||||
|
|
@ -138,13 +155,17 @@ object_id_type create_son_wallet_withdraw_evaluator::do_apply(const son_wallet_w
|
||||||
|
|
||||||
void_result process_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_withdraw_process_operation& op)
|
void_result process_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_withdraw_process_operation& op)
|
||||||
{ try{
|
{ try{
|
||||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
const auto now = db().head_block_time();
|
||||||
|
FC_ASSERT(now >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
||||||
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
|
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
|
||||||
FC_ASSERT(db().get_global_properties().active_sons.size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present");
|
|
||||||
|
|
||||||
const auto& idx = db().get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
|
||||||
const auto& itr = idx.find(op.son_wallet_withdraw_id);
|
const auto& itr = idx.find(op.son_wallet_withdraw_id);
|
||||||
FC_ASSERT(itr != idx.end(), "Son wallet withdraw not found");
|
FC_ASSERT(itr != idx.end(), "Son wallet withdraw not found");
|
||||||
|
FC_ASSERT(!(itr->sidechain == sidechain_type::peerplays && now >= HARDFORK_SON_FOR_ETHEREUM_TIME), "Peerplays sidechain type is not allowed");
|
||||||
|
if(itr->sidechain != sidechain_type::peerplays) {
|
||||||
|
FC_ASSERT(db().get_global_properties().active_sons.at(itr->sidechain).size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present");
|
||||||
|
}
|
||||||
FC_ASSERT(!itr->processed, "Son wallet withdraw is already processed");
|
FC_ASSERT(!itr->processed, "Son wallet withdraw is already processed");
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include <fc/log/logger.hpp>
|
#include <fc/log/logger.hpp>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace graphene { namespace db {
|
namespace graphene { namespace db {
|
||||||
|
|
||||||
|
|
@ -144,6 +145,7 @@ namespace graphene { namespace db {
|
||||||
fc::path get_data_dir()const { return _data_dir; }
|
fc::path get_data_dir()const { return _data_dir; }
|
||||||
|
|
||||||
/** public for testing purposes only... should be private in practice. */
|
/** public for testing purposes only... should be private in practice. */
|
||||||
|
mutable std::mutex _undo_db_mutex;
|
||||||
undo_database _undo_db;
|
undo_database _undo_db;
|
||||||
protected:
|
protected:
|
||||||
template<typename IndexType>
|
template<typename IndexType>
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit e7369949bea26f3201d8442ba78286a88df74762
|
Subproject commit 156b0c4e41c9215eadb2af8009b05e0f38c16dda
|
||||||
|
|
@ -47,4 +47,3 @@ namespace graphene { namespace net {
|
||||||
const core_message_type_enum get_current_connections_reply_message::type = core_message_type_enum::get_current_connections_reply_message_type;
|
const core_message_type_enum get_current_connections_reply_message::type = core_message_type_enum::get_current_connections_reply_message_type;
|
||||||
|
|
||||||
} } // graphene::net
|
} } // graphene::net
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#define GRAPHENE_NET_PROTOCOL_VERSION 106
|
#define GRAPHENE_NET_PROTOCOL_VERSION 106
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -110,3 +112,6 @@
|
||||||
#define GRAPHENE_NET_MAX_NESTED_OBJECTS (250)
|
#define GRAPHENE_NET_MAX_NESTED_OBJECTS (250)
|
||||||
|
|
||||||
#define MAXIMUM_PEERDB_SIZE 1000
|
#define MAXIMUM_PEERDB_SIZE 1000
|
||||||
|
|
||||||
|
constexpr size_t MAX_BLOCKS_TO_HANDLE_AT_ONCE = 200;
|
||||||
|
constexpr size_t MAX_SYNC_BLOCKS_TO_PREFETCH = 10 * MAX_BLOCKS_TO_HANDLE_AT_ONCE;
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ namespace graphene { namespace net {
|
||||||
class node_delegate
|
class node_delegate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~node_delegate(){}
|
virtual ~node_delegate() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If delegate has the item, the network has no need to fetch it.
|
* If delegate has the item, the network has no need to fetch it.
|
||||||
|
|
@ -71,7 +71,9 @@ namespace graphene { namespace net {
|
||||||
/**
|
/**
|
||||||
* @brief Called when a new block comes in from the network
|
* @brief Called when a new block comes in from the network
|
||||||
*
|
*
|
||||||
|
* @param blk_msg the message which contains the block
|
||||||
* @param sync_mode true if the message was fetched through the sync process, false during normal operation
|
* @param sync_mode true if the message was fetched through the sync process, false during normal operation
|
||||||
|
* @param contained_transaction_msg_ids container for the transactions to write back into
|
||||||
* @returns true if this message caused the blockchain to switch forks, false if it did not
|
* @returns true if this message caused the blockchain to switch forks, false if it did not
|
||||||
*
|
*
|
||||||
* @throws exception if error validating the item, otherwise the item is
|
* @throws exception if error validating the item, otherwise the item is
|
||||||
|
|
@ -152,6 +154,8 @@ namespace graphene { namespace net {
|
||||||
|
|
||||||
virtual uint32_t get_block_number(const item_hash_t& block_id) = 0;
|
virtual uint32_t get_block_number(const item_hash_t& block_id) = 0;
|
||||||
|
|
||||||
|
virtual fc::time_point_sec get_last_known_hardfork_time() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the time a block was produced (if block_id = 0, returns genesis time).
|
* Returns the time a block was produced (if block_id = 0, returns genesis time).
|
||||||
* If we don't know about the block, returns time_point_sec::min()
|
* If we don't know about the block, returns time_point_sec::min()
|
||||||
|
|
@ -193,7 +197,7 @@ namespace graphene { namespace net {
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
node(const std::string& user_agent);
|
node(const std::string& user_agent);
|
||||||
~node();
|
virtual ~node();
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
|
|
@ -211,11 +215,34 @@ namespace graphene { namespace net {
|
||||||
*/
|
*/
|
||||||
void add_node( const fc::ip::endpoint& ep );
|
void add_node( const fc::ip::endpoint& ep );
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* @brief add a list of nodes to seed the p2p network
|
||||||
|
* @param seeds a vector of url strings
|
||||||
|
*/
|
||||||
|
void add_seed_nodes( std::vector<std::string> seeds );
|
||||||
|
|
||||||
|
/****
|
||||||
|
* @brief add a node to seed the p2p network
|
||||||
|
* @param in the url as a string
|
||||||
|
*/
|
||||||
|
void add_seed_node( const std::string& in);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to connect to the specified endpoint immediately.
|
* Attempt to connect to the specified endpoint immediately.
|
||||||
*/
|
*/
|
||||||
virtual void connect_to_endpoint( const fc::ip::endpoint& ep );
|
virtual void connect_to_endpoint( const fc::ip::endpoint& ep );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper to convert a string to a collection of endpoints
|
||||||
|
*
|
||||||
|
* This converts a string (i.e. "bitshares.eu:665535" to a collection of endpoints.
|
||||||
|
* NOTE: Throws an exception if not in correct format or was unable to resolve URL.
|
||||||
|
*
|
||||||
|
* @param in the incoming string
|
||||||
|
* @returns a vector of endpoints
|
||||||
|
*/
|
||||||
|
static std::vector<fc::ip::endpoint> resolve_string_to_ip_endpoints( const std::string& in );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the network interface and port upon which incoming
|
* Specifies the network interface and port upon which incoming
|
||||||
* connections should be accepted.
|
* connections should be accepted.
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ namespace graphene { namespace net
|
||||||
class peer_connection_delegate
|
class peer_connection_delegate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~peer_connection_delegate() = default;
|
||||||
virtual void on_message(peer_connection* originating_peer,
|
virtual void on_message(peer_connection* originating_peer,
|
||||||
const message& received_message) = 0;
|
const message& received_message) = 0;
|
||||||
virtual void on_connection_closed(peer_connection* originating_peer) = 0;
|
virtual void on_connection_closed(peer_connection* originating_peer) = 0;
|
||||||
|
|
@ -125,7 +126,7 @@ namespace graphene { namespace net
|
||||||
* it is sitting on the queue
|
* it is sitting on the queue
|
||||||
*/
|
*/
|
||||||
virtual size_t get_size_in_queue() = 0;
|
virtual size_t get_size_in_queue() = 0;
|
||||||
virtual ~queued_message() {}
|
virtual ~queued_message() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* when you queue up a 'real_queued_message', a full copy of the message is
|
/* when you queue up a 'real_queued_message', a full copy of the message is
|
||||||
|
|
@ -258,6 +259,8 @@ namespace graphene { namespace net
|
||||||
|
|
||||||
uint32_t last_known_fork_block_number = 0;
|
uint32_t last_known_fork_block_number = 0;
|
||||||
|
|
||||||
|
fc::time_point_sec last_known_hardfork_time;
|
||||||
|
|
||||||
fc::future<void> accept_or_connect_task_done;
|
fc::future<void> accept_or_connect_task_done;
|
||||||
|
|
||||||
firewall_check_state_data *firewall_check_state = nullptr;
|
firewall_check_state_data *firewall_check_state = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ namespace graphene { namespace net {
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
peer_database();
|
peer_database();
|
||||||
~peer_database();
|
virtual ~peer_database();
|
||||||
|
|
||||||
void open(const fc::path& databaseFilename);
|
void open(const fc::path& databaseFilename);
|
||||||
void close();
|
void close();
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -50,7 +50,8 @@ namespace graphene { namespace net {
|
||||||
indexed_by<ordered_non_unique<tag<last_seen_time_index>,
|
indexed_by<ordered_non_unique<tag<last_seen_time_index>,
|
||||||
member<potential_peer_record,
|
member<potential_peer_record,
|
||||||
fc::time_point_sec,
|
fc::time_point_sec,
|
||||||
&potential_peer_record::last_seen_time> >,
|
&potential_peer_record::last_seen_time>,
|
||||||
|
std::greater<fc::time_point_sec> >,
|
||||||
hashed_unique<tag<endpoint_index>,
|
hashed_unique<tag<endpoint_index>,
|
||||||
member<potential_peer_record,
|
member<potential_peer_record,
|
||||||
fc::ip::endpoint,
|
fc::ip::endpoint,
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ void account_history_plugin_impl::update_account_histories( const signed_block&
|
||||||
vector<optional< operation_history_object > >& hist = db.get_applied_operations();
|
vector<optional< operation_history_object > >& hist = db.get_applied_operations();
|
||||||
bool is_first = true;
|
bool is_first = true;
|
||||||
auto skip_oho_id = [&is_first,&db,this]() {
|
auto skip_oho_id = [&is_first,&db,this]() {
|
||||||
|
const std::lock_guard<std::mutex> undo_db_lock{db._undo_db_mutex};
|
||||||
if( is_first && db._undo_db.enabled() ) // this ensures that the current id is rolled back on undo
|
if( is_first && db._undo_db.enabled() ) // this ensures that the current id is rolled back on undo
|
||||||
{
|
{
|
||||||
db.remove( db.create<operation_history_object>( []( operation_history_object& obj) {} ) );
|
db.remove( db.create<operation_history_object>( []( operation_history_object& obj) {} ) );
|
||||||
|
|
|
||||||
|
|
@ -16,3 +16,4 @@ install( TARGETS
|
||||||
LIBRARY DESTINATION lib
|
LIBRARY DESTINATION lib
|
||||||
ARCHIVE DESTINATION lib
|
ARCHIVE DESTINATION lib
|
||||||
)
|
)
|
||||||
|
INSTALL( FILES ${HEADERS} DESTINATION "include/graphene/debug_witness" )
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,9 @@ class debug_api_impl
|
||||||
};
|
};
|
||||||
|
|
||||||
debug_api_impl::debug_api_impl( graphene::app::application& _app ) : app( _app )
|
debug_api_impl::debug_api_impl( graphene::app::application& _app ) : app( _app )
|
||||||
{}
|
{
|
||||||
|
// Nothing else to do
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void debug_api_impl::debug_push_blocks( const std::string& src_filename, uint32_t count )
|
void debug_api_impl::debug_push_blocks( const std::string& src_filename, uint32_t count )
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,10 @@ using std::vector;
|
||||||
|
|
||||||
namespace bpo = boost::program_options;
|
namespace bpo = boost::program_options;
|
||||||
|
|
||||||
debug_witness_plugin::~debug_witness_plugin() {}
|
debug_witness_plugin::~debug_witness_plugin()
|
||||||
|
{
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
void debug_witness_plugin::plugin_set_program_options(
|
void debug_witness_plugin::plugin_set_program_options(
|
||||||
boost::program_options::options_description& command_line_options,
|
boost::program_options::options_description& command_line_options,
|
||||||
|
|
@ -62,7 +65,7 @@ void debug_witness_plugin::plugin_initialize(const boost::program_options::varia
|
||||||
ilog("debug_witness plugin: plugin_initialize() begin");
|
ilog("debug_witness plugin: plugin_initialize() begin");
|
||||||
_options = &options;
|
_options = &options;
|
||||||
|
|
||||||
if( options.count("debug-private-key") )
|
if( options.count("debug-private-key") > 0 )
|
||||||
{
|
{
|
||||||
const std::vector<std::string> key_id_to_wif_pair_strings = options["debug-private-key"].as<std::vector<std::string>>();
|
const std::vector<std::string> key_id_to_wif_pair_strings = options["debug-private-key"].as<std::vector<std::string>>();
|
||||||
for (const std::string& key_id_to_wif_pair_string : key_id_to_wif_pair_strings)
|
for (const std::string& key_id_to_wif_pair_string : key_id_to_wif_pair_strings)
|
||||||
|
|
@ -100,7 +103,6 @@ void debug_witness_plugin::plugin_startup()
|
||||||
_changed_objects_conn = db.changed_objects.connect([this](const std::vector<graphene::db::object_id_type>& ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts){ on_changed_objects(ids, impacted_accounts); });
|
_changed_objects_conn = db.changed_objects.connect([this](const std::vector<graphene::db::object_id_type>& ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts){ on_changed_objects(ids, impacted_accounts); });
|
||||||
_removed_objects_conn = db.removed_objects.connect([this](const std::vector<graphene::db::object_id_type>& ids, const std::vector<const graphene::db::object*>& objs, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts){ on_removed_objects(ids, objs, impacted_accounts); });
|
_removed_objects_conn = db.removed_objects.connect([this](const std::vector<graphene::db::object_id_type>& ids, const std::vector<const graphene::db::object*>& objs, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts){ on_removed_objects(ids, objs, impacted_accounts); });
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void debug_witness_plugin::on_changed_objects( const std::vector<graphene::db::object_id_type>& ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts )
|
void debug_witness_plugin::on_changed_objects( const std::vector<graphene::db::object_id_type>& ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts )
|
||||||
|
|
@ -155,11 +157,15 @@ void debug_witness_plugin::flush_json_object_stream()
|
||||||
}
|
}
|
||||||
|
|
||||||
void debug_witness_plugin::plugin_shutdown()
|
void debug_witness_plugin::plugin_shutdown()
|
||||||
|
{
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_witness_plugin::cleanup()
|
||||||
{
|
{
|
||||||
if( _json_object_stream )
|
if( _json_object_stream )
|
||||||
{
|
{
|
||||||
_json_object_stream->close();
|
_json_object_stream->close();
|
||||||
_json_object_stream.reset();
|
_json_object_stream.reset();
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,23 +34,25 @@ namespace graphene { namespace debug_witness_plugin {
|
||||||
|
|
||||||
class debug_witness_plugin : public graphene::app::plugin {
|
class debug_witness_plugin : public graphene::app::plugin {
|
||||||
public:
|
public:
|
||||||
~debug_witness_plugin();
|
using graphene::app::plugin::plugin;
|
||||||
|
~debug_witness_plugin() override;
|
||||||
|
|
||||||
std::string plugin_name()const override;
|
std::string plugin_name()const override;
|
||||||
|
|
||||||
virtual void plugin_set_program_options(
|
void plugin_set_program_options(
|
||||||
boost::program_options::options_description &command_line_options,
|
boost::program_options::options_description &command_line_options,
|
||||||
boost::program_options::options_description &config_file_options
|
boost::program_options::options_description &config_file_options
|
||||||
) override;
|
) override;
|
||||||
|
|
||||||
virtual void plugin_initialize( const boost::program_options::variables_map& options ) override;
|
void plugin_initialize( const boost::program_options::variables_map& options ) override;
|
||||||
virtual void plugin_startup() override;
|
void plugin_startup() override;
|
||||||
virtual void plugin_shutdown() override;
|
void plugin_shutdown() override;
|
||||||
|
|
||||||
void set_json_object_stream( const std::string& filename );
|
void set_json_object_stream( const std::string& filename );
|
||||||
void flush_json_object_stream();
|
void flush_json_object_stream();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
void on_changed_objects( const std::vector<graphene::db::object_id_type>& ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts );
|
void on_changed_objects( const std::vector<graphene::db::object_id_type>& ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts );
|
||||||
void on_removed_objects( const std::vector<graphene::db::object_id_type>& ids, const std::vector<const graphene::db::object*> objs, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts );
|
void on_removed_objects( const std::vector<graphene::db::object_id_type>& ids, const std::vector<const graphene::db::object*> objs, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts );
|
||||||
|
|
@ -58,7 +60,7 @@ private:
|
||||||
|
|
||||||
boost::program_options::variables_map _options;
|
boost::program_options::variables_map _options;
|
||||||
|
|
||||||
std::map<chain::public_key_type, fc::ecc::private_key> _private_keys;
|
std::map<chain::public_key_type, fc::ecc::private_key, chain::pubkey_comparator> _private_keys;
|
||||||
|
|
||||||
std::shared_ptr< std::ofstream > _json_object_stream;
|
std::shared_ptr< std::ofstream > _json_object_stream;
|
||||||
boost::signals2::scoped_connection _applied_block_conn;
|
boost::signals2::scoped_connection _applied_block_conn;
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,24 @@ void delayed_node_plugin::plugin_set_program_options(bpo::options_description& c
|
||||||
|
|
||||||
void delayed_node_plugin::connect()
|
void delayed_node_plugin::connect()
|
||||||
{
|
{
|
||||||
my->client_connection = std::make_shared<fc::rpc::websocket_api_connection>(my->client.connect(my->remote_endpoint), GRAPHENE_MAX_NESTED_OBJECTS);
|
fc::http::websocket_connection_ptr con;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
con = my->client.connect(my->remote_endpoint);
|
||||||
|
}
|
||||||
|
catch( const fc::exception& e )
|
||||||
|
{
|
||||||
|
wlog("Error while connecting: ${e}", ("e", e.to_detail_string()));
|
||||||
|
connection_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
my->client_connection = std::make_shared<fc::rpc::websocket_api_connection>(
|
||||||
|
con, GRAPHENE_NET_MAX_NESTED_OBJECTS );
|
||||||
my->database_api = my->client_connection->get_remote_api<graphene::app::database_api>(0);
|
my->database_api = my->client_connection->get_remote_api<graphene::app::database_api>(0);
|
||||||
|
my->database_api->set_block_applied_callback([this]( const fc::variant& block_id )
|
||||||
|
{
|
||||||
|
fc::from_variant( block_id, my->last_received_remote_head, GRAPHENE_MAX_NESTED_OBJECTS );
|
||||||
|
} );
|
||||||
my->client_connection_closed = my->client_connection->closed.connect([this] {
|
my->client_connection_closed = my->client_connection->closed.connect([this] {
|
||||||
connection_failed();
|
connection_failed();
|
||||||
});
|
});
|
||||||
|
|
@ -73,7 +89,9 @@ void delayed_node_plugin::connect()
|
||||||
void delayed_node_plugin::plugin_initialize(const boost::program_options::variables_map& options)
|
void delayed_node_plugin::plugin_initialize(const boost::program_options::variables_map& options)
|
||||||
{
|
{
|
||||||
FC_ASSERT(options.count("trusted-node") > 0);
|
FC_ASSERT(options.count("trusted-node") > 0);
|
||||||
|
ilog("delayed_node_plugin: plugin_initialize() begin");
|
||||||
my->remote_endpoint = "ws://" + options.at("trusted-node").as<std::string>();
|
my->remote_endpoint = "ws://" + options.at("trusted-node").as<std::string>();
|
||||||
|
ilog("delayed_node_plugin: plugin_initialize() end");
|
||||||
}
|
}
|
||||||
|
|
||||||
void delayed_node_plugin::sync_with_trusted_node()
|
void delayed_node_plugin::sync_with_trusted_node()
|
||||||
|
|
@ -100,8 +118,11 @@ void delayed_node_plugin::sync_with_trusted_node()
|
||||||
while( remote_dpo.last_irreversible_block_num > db.head_block_num() )
|
while( remote_dpo.last_irreversible_block_num > db.head_block_num() )
|
||||||
{
|
{
|
||||||
fc::optional<graphene::chain::signed_block> block = my->database_api->get_block( db.head_block_num()+1 );
|
fc::optional<graphene::chain::signed_block> block = my->database_api->get_block( db.head_block_num()+1 );
|
||||||
|
// TODO: during sync, decouple requesting blocks from preprocessing + applying them
|
||||||
FC_ASSERT(block, "Trusted node claims it has blocks it doesn't actually have.");
|
FC_ASSERT(block, "Trusted node claims it has blocks it doesn't actually have.");
|
||||||
ilog("Pushing block #${n}", ("n", block->block_num()));
|
ilog("Pushing block #${n}", ("n", block->block_num()));
|
||||||
|
// timur: failed to merge from bitshares, API n/a in peerplays
|
||||||
|
// db.precompute_parallel( *block, graphene::chain::database::skip_nothing ).wait();
|
||||||
db.push_block(*block);
|
db.push_block(*block);
|
||||||
synced_blocks++;
|
synced_blocks++;
|
||||||
}
|
}
|
||||||
|
|
@ -136,24 +157,12 @@ void delayed_node_plugin::plugin_startup()
|
||||||
mainloop();
|
mainloop();
|
||||||
});
|
});
|
||||||
|
|
||||||
try
|
connect();
|
||||||
{
|
|
||||||
connect();
|
|
||||||
my->database_api->set_block_applied_callback([this]( const fc::variant& block_id )
|
|
||||||
{
|
|
||||||
fc::from_variant( block_id, my->last_received_remote_head, GRAPHENE_MAX_NESTED_OBJECTS );
|
|
||||||
} );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (const fc::exception& e)
|
|
||||||
{
|
|
||||||
elog("Error during connection: ${e}", ("e", e.to_detail_string()));
|
|
||||||
}
|
|
||||||
fc::async([this]{connection_failed();});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void delayed_node_plugin::connection_failed()
|
void delayed_node_plugin::connection_failed()
|
||||||
{
|
{
|
||||||
|
my->last_received_remote_head = my->last_processed_remote_head;
|
||||||
elog("Connection to trusted node failed; retrying in 5 seconds...");
|
elog("Connection to trusted node failed; retrying in 5 seconds...");
|
||||||
fc::schedule([this]{connect();}, fc::time_point::now() + fc::seconds(5));
|
fc::schedule([this]{connect();}, fc::time_point::now() + fc::seconds(5));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@ bool elasticsearch_plugin_impl::update_account_histories( const signed_block& b
|
||||||
const vector<optional< operation_history_object > >& hist = db.get_applied_operations();
|
const vector<optional< operation_history_object > >& hist = db.get_applied_operations();
|
||||||
bool is_first = true;
|
bool is_first = true;
|
||||||
auto skip_oho_id = [&is_first,&db,this]() {
|
auto skip_oho_id = [&is_first,&db,this]() {
|
||||||
|
const std::lock_guard<std::mutex> undo_db_lock{db._undo_db_mutex};
|
||||||
if( is_first && db._undo_db.enabled() ) // this ensures that the current id is rolled back on undo
|
if( is_first && db._undo_db.enabled() ) // this ensures that the current id is rolled back on undo
|
||||||
{
|
{
|
||||||
db.remove( db.create<operation_history_object>( []( operation_history_object& obj) {} ) );
|
db.remove( db.create<operation_history_object>( []( operation_history_object& obj) {} ) );
|
||||||
|
|
|
||||||
12
libraries/plugins/peerplays_sidechain/CMakeLists.txt
Executable file → Normal file
12
libraries/plugins/peerplays_sidechain/CMakeLists.txt
Executable file → Normal file
|
|
@ -3,9 +3,10 @@ file(GLOB_RECURSE HEADERS "include/graphene/peerplays_sidechain/*.hpp")
|
||||||
add_library( peerplays_sidechain
|
add_library( peerplays_sidechain
|
||||||
peerplays_sidechain_plugin.cpp
|
peerplays_sidechain_plugin.cpp
|
||||||
sidechain_api.cpp
|
sidechain_api.cpp
|
||||||
sidechain_net_manager.cpp
|
sidechain_net_handler_factory.cpp
|
||||||
sidechain_net_handler.cpp
|
sidechain_net_handler.cpp
|
||||||
sidechain_net_handler_bitcoin.cpp
|
sidechain_net_handler_bitcoin.cpp
|
||||||
|
sidechain_net_handler_ethereum.cpp
|
||||||
sidechain_net_handler_hive.cpp
|
sidechain_net_handler_hive.cpp
|
||||||
sidechain_net_handler_peerplays.cpp
|
sidechain_net_handler_peerplays.cpp
|
||||||
bitcoin/bech32.cpp
|
bitcoin/bech32.cpp
|
||||||
|
|
@ -15,8 +16,15 @@ 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/decoders.cpp
|
||||||
|
ethereum/transaction.cpp
|
||||||
|
ethereum/types.cpp
|
||||||
|
ethereum/utils.cpp
|
||||||
hive/asset.cpp
|
hive/asset.cpp
|
||||||
hive/operations.cpp
|
hive/operations.cpp
|
||||||
hive/transaction.cpp
|
hive/transaction.cpp
|
||||||
|
|
@ -36,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 curl graphene_plugin 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) :
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ void bitcoin_transaction_builder::add_in(payment_type type, tx_in txin, const by
|
||||||
txin.scriptSig = script_code;
|
txin.scriptSig = script_code;
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
if (txin.prevout.hash == fc::sha256("0000000000000000000000000000000000000000000000000000000000000000")) { //coinbase
|
if (txin.prevout.hash == fc::sha256("0000000000000000000000000000000000000000000000000000000000000000")) { // coinbase
|
||||||
FC_ASSERT(script_code != bytes());
|
FC_ASSERT(script_code != bytes());
|
||||||
txin.scriptSig = script_code;
|
txin.scriptSig = script_code;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include <graphene/peerplays_sidechain/bitcoin/serialize.hpp>
|
#include <graphene/peerplays_sidechain/bitcoin/serialize.hpp>
|
||||||
|
#include <secp256k1.h>
|
||||||
|
|
||||||
#include <fc/io/raw.hpp>
|
#include <fc/io/raw.hpp>
|
||||||
|
|
||||||
|
|
@ -6,8 +7,8 @@
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
|
namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
|
||||||
|
|
||||||
const secp256k1_context_t *btc_context() {
|
const secp256k1_context *btc_context() {
|
||||||
static secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
|
static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,20 +32,14 @@ fc::sha256 get_signature_hash(const bitcoin_transaction &tx, const bytes &script
|
||||||
return fc::sha256::hash(fc::sha256::hash(vec.data(), vec.size()));
|
return fc::sha256::hash(fc::sha256::hash(vec.data(), vec.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> privkey_sign(const bytes &privkey, const fc::sha256 &hash, const secp256k1_context_t *context_sign) {
|
std::vector<char> privkey_sign(const bytes &privkey, const fc::sha256 &hash, const secp256k1_context *context_sign) {
|
||||||
bytes sig;
|
bytes sig;
|
||||||
sig.resize(72);
|
sig.resize(72);
|
||||||
int sig_len = sig.size();
|
int sig_len = sig.size();
|
||||||
|
|
||||||
FC_ASSERT(secp256k1_ecdsa_sign(
|
secp256k1_ecdsa_signature sign;
|
||||||
context_sign,
|
FC_ASSERT(secp256k1_ecdsa_sign(context_sign, &sign, (const unsigned char *)hash.data(), (const unsigned char *)privkey.data(), secp256k1_nonce_function_rfc6979, nullptr));
|
||||||
reinterpret_cast<unsigned char *>(hash.data()),
|
FC_ASSERT(secp256k1_ecdsa_signature_serialize_der(context_sign, (unsigned char *)sig.data(), (size_t *)&sig_len, &sign));
|
||||||
reinterpret_cast<unsigned char *>(sig.data()),
|
|
||||||
&sig_len,
|
|
||||||
reinterpret_cast<const unsigned char *>(privkey.data()),
|
|
||||||
secp256k1_nonce_function_rfc6979,
|
|
||||||
nullptr)); // TODO: replace assert with exception
|
|
||||||
|
|
||||||
sig.resize(sig_len);
|
sig.resize(sig_len);
|
||||||
|
|
||||||
return sig;
|
return sig;
|
||||||
|
|
@ -52,7 +47,7 @@ std::vector<char> privkey_sign(const bytes &privkey, const fc::sha256 &hash, con
|
||||||
|
|
||||||
std::vector<bytes> sign_witness_transaction_part(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
|
std::vector<bytes> sign_witness_transaction_part(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
|
||||||
const std::vector<uint64_t> &amounts, const bytes &privkey,
|
const std::vector<uint64_t> &amounts, const bytes &privkey,
|
||||||
const secp256k1_context_t *context_sign, int hash_type) {
|
const secp256k1_context *context_sign, int hash_type) {
|
||||||
FC_ASSERT(tx.vin.size() == redeem_scripts.size() && tx.vin.size() == amounts.size());
|
FC_ASSERT(tx.vin.size() == redeem_scripts.size() && tx.vin.size() == amounts.size());
|
||||||
FC_ASSERT(!privkey.empty());
|
FC_ASSERT(!privkey.empty());
|
||||||
|
|
||||||
|
|
@ -77,17 +72,34 @@ void sign_witness_transaction_finalize(bitcoin_transaction &tx, const std::vecto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool verify_sig(const bytes &sig, const bytes &pubkey, const bytes &msg, const secp256k1_context_t *context) {
|
bool verify_sig(const bytes &sig, const bytes &pubkey, const bytes &msg, const secp256k1_context *context) {
|
||||||
std::vector<unsigned char> sig_temp(sig.begin(), sig.end());
|
//! Get sig_temp
|
||||||
|
FC_ASSERT(sig.size() > 70);
|
||||||
|
FC_ASSERT(sig[0] == 0x30);
|
||||||
|
FC_ASSERT(sig[1] == static_cast<char>(sig.size() - 3));
|
||||||
|
FC_ASSERT(sig[2] == 0x02);
|
||||||
|
const uint r_size = sig[3];
|
||||||
|
std::vector<unsigned char> sig_temp(sig.begin() + 4 + (r_size - 32), sig.begin() + 4 + r_size);
|
||||||
|
FC_ASSERT(sig[4 + r_size] == 0x02);
|
||||||
|
const uint s_size = sig[5 + r_size];
|
||||||
|
FC_ASSERT(sig.size() == r_size + s_size + 7);
|
||||||
|
sig_temp.insert(sig_temp.end(), sig.begin() + 6 + r_size, sig.end());
|
||||||
|
|
||||||
std::vector<unsigned char> pubkey_temp(pubkey.begin(), pubkey.end());
|
std::vector<unsigned char> pubkey_temp(pubkey.begin(), pubkey.end());
|
||||||
std::vector<unsigned char> msg_temp(msg.begin(), msg.end());
|
std::vector<unsigned char> msg_temp(msg.begin(), msg.end());
|
||||||
|
|
||||||
int result = secp256k1_ecdsa_verify(context, msg_temp.data(), sig_temp.data(), sig_temp.size(), pubkey_temp.data(), pubkey_temp.size());
|
secp256k1_pubkey pub_key;
|
||||||
|
FC_ASSERT(secp256k1_ec_pubkey_parse(context, &pub_key, (const unsigned char *)pubkey_temp.data(), pubkey_temp.size()));
|
||||||
|
|
||||||
|
secp256k1_ecdsa_signature sign;
|
||||||
|
FC_ASSERT(secp256k1_ecdsa_signature_parse_compact(context, &sign, (const unsigned char *)sig_temp.data()));
|
||||||
|
|
||||||
|
int result = secp256k1_ecdsa_verify(context, &sign, (const unsigned char *)msg_temp.data(), &pub_key);
|
||||||
return result == 1;
|
return result == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::vector<bytes>> sort_sigs(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
|
std::vector<std::vector<bytes>> sort_sigs(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
|
||||||
const std::vector<uint64_t> &amounts, const secp256k1_context_t *context) {
|
const std::vector<uint64_t> &amounts, const secp256k1_context *context) {
|
||||||
FC_ASSERT(redeem_scripts.size() == amounts.size());
|
FC_ASSERT(redeem_scripts.size() == amounts.size());
|
||||||
|
|
||||||
using data = std::pair<size_t, bytes>;
|
using data = std::pair<size_t, bytes>;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,8 +1,64 @@
|
||||||
#include <graphene/peerplays_sidechain/common/utils.hpp>
|
#include <graphene/peerplays_sidechain/common/utils.hpp>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/archive/iterators/base64_from_binary.hpp>
|
||||||
|
#include <boost/archive/iterators/binary_from_base64.hpp>
|
||||||
|
#include <boost/archive/iterators/transform_width.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
|
const std::string base64_padding[] = {"", "==", "="};
|
||||||
|
|
||||||
|
std::string base64_encode(const std::string &s) {
|
||||||
|
using namespace boost::archive::iterators;
|
||||||
|
|
||||||
|
typedef base64_from_binary<transform_width<const char *, 6, 8>> base64_enc;
|
||||||
|
|
||||||
|
std::stringstream os;
|
||||||
|
std::copy(base64_enc(s.c_str()), base64_enc(s.c_str() + s.size()), std::ostream_iterator<char>(os));
|
||||||
|
os << base64_padding[s.size() % 3];
|
||||||
|
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string base64_decode(const std::string &s) {
|
||||||
|
using namespace boost::archive::iterators;
|
||||||
|
|
||||||
|
typedef transform_width<binary_from_base64<const char *>, 8, 6> base64_dec;
|
||||||
|
|
||||||
|
std::stringstream os;
|
||||||
|
unsigned int size = s.size();
|
||||||
|
if (size && s[size - 1] == '=') {
|
||||||
|
--size;
|
||||||
|
if (size && s[size - 1] == '=')
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
if (size == 0)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
std::copy(base64_dec(s.data()), base64_dec(s.data() + size), std::ostream_iterator<char>(os));
|
||||||
|
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
std::string object_id_to_string(graphene::chain::object_id_type id) {
|
std::string object_id_to_string(graphene::chain::object_id_type id) {
|
||||||
std::string object_id = fc::to_string(id.space()) + "." +
|
std::string object_id = fc::to_string(id.space()) + "." +
|
||||||
fc::to_string(id.type()) + "." +
|
fc::to_string(id.type()) + "." +
|
||||||
fc::to_string(id.instance());
|
fc::to_string(id.instance());
|
||||||
return object_id;
|
return object_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
graphene::chain::object_id_type string_to_object_id(const std::string &id) {
|
||||||
|
std::vector<std::string> strs;
|
||||||
|
boost::split(strs, id, boost::is_any_of("."));
|
||||||
|
if (strs.size() != 3) {
|
||||||
|
elog("Wrong object_id format: ${id}", ("id", id));
|
||||||
|
return graphene::chain::object_id_type{};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto s = boost::lexical_cast<int>(strs.at(0));
|
||||||
|
auto t = boost::lexical_cast<int>(strs.at(1));
|
||||||
|
return graphene::chain::object_id_type{(uint8_t)s, (uint8_t)t, boost::lexical_cast<uint64_t>(strs.at(2))};
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
|
||||||
267
libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp
Normal file
267
libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp
Normal file
|
|
@ -0,0 +1,267 @@
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
|
||||||
|
|
||||||
|
#include <fc/exception/exception.hpp>
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
//! base_decoder
|
||||||
|
boost::multiprecision::uint256_t base_decoder::decode_uint256(const std::string &value) {
|
||||||
|
boost::multiprecision::uint256_t result = 0;
|
||||||
|
|
||||||
|
boost::multiprecision::uint256_t power(1);
|
||||||
|
uint8_t digit;
|
||||||
|
int pos = value.size() - 1;
|
||||||
|
while (pos >= 0) {
|
||||||
|
digit = 0;
|
||||||
|
if ('0' <= value[pos] && value[pos] <= '9') {
|
||||||
|
digit = value[pos] - '0';
|
||||||
|
} else if ('a' <= value[pos] && value[pos] <= 'z') {
|
||||||
|
digit = value[pos] - 'a' + 10;
|
||||||
|
}
|
||||||
|
result += digit * power;
|
||||||
|
pos--;
|
||||||
|
power *= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string base_decoder::decode_address(const std::string &value) {
|
||||||
|
return value.substr(24, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! deposit_erc20_decoder
|
||||||
|
const std::string deposit_erc20_decoder::function_signature = "97feb926"; //! depositERC20(address,uint256)
|
||||||
|
fc::optional<deposit_erc20_transaction> deposit_erc20_decoder::decode(const std::string &input) {
|
||||||
|
const auto input_without_0x = remove_0x(input);
|
||||||
|
if (function_signature != input_without_0x.substr(0, 8)) {
|
||||||
|
return fc::optional<deposit_erc20_transaction>{};
|
||||||
|
}
|
||||||
|
if (input_without_0x.size() != 136) {
|
||||||
|
return fc::optional<deposit_erc20_transaction>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
deposit_erc20_transaction erc_20;
|
||||||
|
erc_20.token = add_0x(base_decoder::decode_address(input_without_0x.substr(8, 64)));
|
||||||
|
erc_20.amount = base_decoder::decode_uint256(input_without_0x.substr(72, 64));
|
||||||
|
|
||||||
|
return erc_20;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! rlp_decoder
|
||||||
|
namespace {
|
||||||
|
const signed char p_util_hexdigit[256] =
|
||||||
|
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> rlp_decoder::decode(const std::string &str) {
|
||||||
|
size_t consumed = 0;
|
||||||
|
const auto raw_vec = parse_hex(str);
|
||||||
|
const std::vector<std::string> rlp_array = decode_rlp(raw_vec.data(), raw_vec.size(), consumed);
|
||||||
|
std::vector<std::string> result_array;
|
||||||
|
for (const auto &rlp : decode_rlp(raw_vec.data(), raw_vec.size(), consumed)) {
|
||||||
|
result_array.emplace_back(bytes2hex(rlp));
|
||||||
|
}
|
||||||
|
return result_array;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> rlp_decoder::decode_rlp(const unsigned char *raw, size_t len, size_t &consumed) {
|
||||||
|
std::vector<std::string> rlp_result;
|
||||||
|
|
||||||
|
consumed = 0;
|
||||||
|
|
||||||
|
const unsigned char *end = raw + len;
|
||||||
|
const size_t prefixlen = 1;
|
||||||
|
unsigned char ch = *raw;
|
||||||
|
|
||||||
|
if (len < 1) {
|
||||||
|
return rlp_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 1: [prefix is 1-byte data buffer]
|
||||||
|
if (ch <= 0x7f) {
|
||||||
|
const unsigned char *tok_start = raw;
|
||||||
|
const unsigned char *tok_end = tok_start + prefixlen;
|
||||||
|
FC_ASSERT(tok_end <= end);
|
||||||
|
|
||||||
|
// parsing done; assign data buffer value.
|
||||||
|
const std::vector<unsigned char> buf{tok_start, tok_end};
|
||||||
|
rlp_result.emplace_back(buf.cbegin(), buf.cend());
|
||||||
|
|
||||||
|
consumed = buf.size();
|
||||||
|
}
|
||||||
|
// Case 2: [prefix, including buffer length][data]
|
||||||
|
else if ((ch >= 0x80) && (ch <= 0xb7)) {
|
||||||
|
const size_t blen = ch - 0x80;
|
||||||
|
const size_t expected = prefixlen + blen;
|
||||||
|
|
||||||
|
if (len < expected)
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
const unsigned char *tok_start = raw + 1;
|
||||||
|
const unsigned char *tok_end = tok_start + blen;
|
||||||
|
FC_ASSERT(tok_end <= end);
|
||||||
|
|
||||||
|
// require minimal encoding
|
||||||
|
if ((blen == 1) && (tok_start[0] <= 0x7f))
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
// parsing done; assign data buffer value.
|
||||||
|
const std::vector<unsigned char> buf{tok_start, tok_end};
|
||||||
|
rlp_result.emplace_back(buf.cbegin(), buf.cend());
|
||||||
|
|
||||||
|
consumed = expected;
|
||||||
|
}
|
||||||
|
// Case 3: [prefix][buffer length][data]
|
||||||
|
else if ((ch >= 0xb8) && (ch <= 0xbf)) {
|
||||||
|
const size_t uintlen = ch - 0xb7;
|
||||||
|
size_t expected = prefixlen + uintlen;
|
||||||
|
|
||||||
|
if (len < expected)
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen);
|
||||||
|
|
||||||
|
const unsigned char *tok_start = raw + prefixlen;
|
||||||
|
if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
// read buffer length
|
||||||
|
const uint64_t slen = to_int(tok_start, uintlen);
|
||||||
|
|
||||||
|
// validate buffer length, including possible addition overflows.
|
||||||
|
expected = prefixlen + uintlen + slen;
|
||||||
|
if ((slen < (RLP_listStart - RLP_bufferLenStart - RLP_maxUintLen)) || (expected > len) || (slen > len))
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
// parsing done; assign data buffer value.
|
||||||
|
tok_start = raw + prefixlen + uintlen;
|
||||||
|
const unsigned char *tok_end = tok_start + slen;
|
||||||
|
const std::vector<unsigned char> buf{tok_start, tok_end};
|
||||||
|
rlp_result.emplace_back(buf.cbegin(), buf.cend());
|
||||||
|
|
||||||
|
consumed = expected;
|
||||||
|
}
|
||||||
|
// Case 4: [prefix][list]
|
||||||
|
else if ((ch >= 0xc0) && (ch <= 0xf7)) {
|
||||||
|
const size_t payloadlen = ch - 0xc0;
|
||||||
|
const size_t expected = prefixlen + payloadlen;
|
||||||
|
|
||||||
|
// read list payload
|
||||||
|
const auto array = decode_array(raw, len, 0, payloadlen);
|
||||||
|
rlp_result.insert(rlp_result.end(), array.cbegin(), array.cend());
|
||||||
|
|
||||||
|
consumed = expected;
|
||||||
|
}
|
||||||
|
// Case 5: [prefix][list length][list]
|
||||||
|
else {
|
||||||
|
FC_ASSERT((ch >= 0xf8) && (ch <= 0xff));
|
||||||
|
|
||||||
|
const size_t uintlen = ch - 0xf7;
|
||||||
|
const size_t expected = prefixlen + uintlen;
|
||||||
|
|
||||||
|
if (len < expected)
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen);
|
||||||
|
|
||||||
|
const unsigned char *tok_start = raw + prefixlen;
|
||||||
|
if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
// read list length
|
||||||
|
const size_t payloadlen = to_int(tok_start, uintlen);
|
||||||
|
|
||||||
|
// special requirement for non-immediate length
|
||||||
|
if (payloadlen < (0x100 - RLP_listStart - RLP_maxUintLen))
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
// read list payload
|
||||||
|
const auto array = decode_array(raw, len, uintlen, payloadlen);
|
||||||
|
rlp_result.insert(rlp_result.end(), array.cbegin(), array.cend());
|
||||||
|
|
||||||
|
consumed = prefixlen + uintlen + payloadlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rlp_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> rlp_decoder::decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen) {
|
||||||
|
std::vector<std::string> rlp_result;
|
||||||
|
const size_t prefixlen = 1;
|
||||||
|
|
||||||
|
// validate list length, including possible addition overflows.
|
||||||
|
const size_t expected = prefixlen + uintlen + payloadlen;
|
||||||
|
if ((expected > len) || (payloadlen > len))
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
size_t child_len = payloadlen;
|
||||||
|
const unsigned char *list_ent = raw + prefixlen + uintlen;
|
||||||
|
|
||||||
|
// recursively read until payloadlen bytes parsed, or error
|
||||||
|
while (child_len > 0) {
|
||||||
|
size_t child_consumed = 0;
|
||||||
|
|
||||||
|
const auto val = decode_rlp(list_ent, child_len, child_consumed);
|
||||||
|
rlp_result.insert(rlp_result.end(), val.cbegin(), val.cend());
|
||||||
|
|
||||||
|
list_ent += child_consumed;
|
||||||
|
child_len -= child_consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rlp_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t rlp_decoder::to_int(const unsigned char *raw, size_t len) {
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
else if (len == 1)
|
||||||
|
return *raw;
|
||||||
|
else
|
||||||
|
return (raw[len - 1]) + (to_int(raw, len - 1) * 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> rlp_decoder::parse_hex(const std::string &str) {
|
||||||
|
return parse_hex(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> rlp_decoder::parse_hex(const char *psz) {
|
||||||
|
// convert hex dump to vector
|
||||||
|
std::vector<unsigned char> vch;
|
||||||
|
while (true) {
|
||||||
|
while (isspace(*psz))
|
||||||
|
psz++;
|
||||||
|
signed char c = hex_digit(*psz++);
|
||||||
|
if (c == (signed char)-1)
|
||||||
|
break;
|
||||||
|
unsigned char n = (c << 4);
|
||||||
|
c = hex_digit(*psz++);
|
||||||
|
if (c == (signed char)-1)
|
||||||
|
break;
|
||||||
|
n |= c;
|
||||||
|
vch.push_back(n);
|
||||||
|
}
|
||||||
|
return vch;
|
||||||
|
}
|
||||||
|
|
||||||
|
signed char rlp_decoder::hex_digit(char c) {
|
||||||
|
return p_util_hexdigit[(unsigned char)c];
|
||||||
|
}
|
||||||
|
|
||||||
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
171
libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp
Normal file
171
libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
|
||||||
|
|
||||||
|
#include <boost/algorithm/hex.hpp>
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
//! base_encoder
|
||||||
|
std::string base_encoder::encode_uint256(boost::multiprecision::uint256_t value) {
|
||||||
|
return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string base_encoder::encode_address(const std::string &value) {
|
||||||
|
return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string base_encoder::encode_string(const std::string &value) {
|
||||||
|
std::string data = (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value.size())).str();
|
||||||
|
data += boost::algorithm::hex(value);
|
||||||
|
if (value.size() % 32 != 0) {
|
||||||
|
data += std::string((64 - value.size() * 2 % 64), '0');
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! update_owners_encoder
|
||||||
|
const std::string update_owners_encoder::function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string)
|
||||||
|
std::string update_owners_encoder::encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) {
|
||||||
|
std::string data = add_0x(function_signature);
|
||||||
|
data += base_encoder::encode_uint256(64);
|
||||||
|
data += base_encoder::encode_uint256((owners_weights.size() * 2 + 3) * 32);
|
||||||
|
data += base_encoder::encode_uint256(owners_weights.size());
|
||||||
|
for (const auto &owner : owners_weights) {
|
||||||
|
data += base_encoder::encode_address(owner.first);
|
||||||
|
data += base_encoder::encode_uint256(owner.second);
|
||||||
|
}
|
||||||
|
data += base_encoder::encode_string(object_id);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! withdrawal_encoder
|
||||||
|
const std::string withdrawal_encoder::function_signature = "e088747b"; //! withdraw(address,uint256,string)
|
||||||
|
std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) {
|
||||||
|
std::string data = add_0x(function_signature);
|
||||||
|
data += base_encoder::encode_address(to);
|
||||||
|
data += base_encoder::encode_uint256(amount);
|
||||||
|
data += base_encoder::encode_uint256(32 * 3);
|
||||||
|
data += base_encoder::encode_string(object_id);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! withdrawal_erc20_encoder
|
||||||
|
const std::string withdrawal_erc20_encoder::function_signature = "483c0467"; //! withdrawERC20(address,address,uint256,string)
|
||||||
|
std::string withdrawal_erc20_encoder::encode(const std::string &token, const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) {
|
||||||
|
std::string data = add_0x(function_signature);
|
||||||
|
data += base_encoder::encode_address(token);
|
||||||
|
data += base_encoder::encode_address(to);
|
||||||
|
data += base_encoder::encode_uint256(amount);
|
||||||
|
data += base_encoder::encode_uint256(32 * 4);
|
||||||
|
data += base_encoder::encode_string(object_id);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! signature_encoder
|
||||||
|
const std::string update_owners_function_signature = "9d608673"; //! updateOwners((bytes,(uint8,bytes32,bytes32))[])
|
||||||
|
const std::string withdrawal_function_signature = "daac6c81"; //! withdraw((bytes,(uint8,bytes32,bytes32))[])
|
||||||
|
const std::string withdrawal_erc20_function_signature = "d2bf2866"; //! withdrawERC20((bytes,(uint8,bytes32,bytes32))[])
|
||||||
|
signature_encoder::signature_encoder(const std::string &function_hash) :
|
||||||
|
function_signature{function_hash} {
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string signature_encoder::get_function_signature_from_transaction(const std::string &transaction) {
|
||||||
|
const std::string tr = remove_0x(transaction);
|
||||||
|
if (tr.substr(0, 8) == update_owners_encoder::function_signature)
|
||||||
|
return update_owners_function_signature;
|
||||||
|
|
||||||
|
if (tr.substr(0, 8) == withdrawal_encoder::function_signature)
|
||||||
|
return withdrawal_function_signature;
|
||||||
|
|
||||||
|
if (tr.substr(0, 8) == withdrawal_erc20_encoder::function_signature)
|
||||||
|
return withdrawal_erc20_function_signature;
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string signature_encoder::encode(const std::vector<encoded_sign_transaction> &transactions) const {
|
||||||
|
std::string data = add_0x(function_signature);
|
||||||
|
data += base_encoder::encode_uint256(32);
|
||||||
|
data += base_encoder::encode_uint256(transactions.size());
|
||||||
|
size_t offset = (transactions.size()) * 32;
|
||||||
|
for (const auto &transaction : transactions) {
|
||||||
|
data += base_encoder::encode_uint256(offset);
|
||||||
|
const auto transaction_data = remove_0x(transaction.data);
|
||||||
|
offset += 5 * 32 + transaction_data.size() / 2;
|
||||||
|
if (transaction_data.size() / 2 % 32 != 0) {
|
||||||
|
offset += 32 - transaction_data.size() / 2 % 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto &transaction : transactions) {
|
||||||
|
data += base_encoder::encode_uint256(4 * 32);
|
||||||
|
data += base_encoder::encode_address(transaction.sign.v);
|
||||||
|
data += base_encoder::encode_address(transaction.sign.r);
|
||||||
|
data += base_encoder::encode_address(transaction.sign.s);
|
||||||
|
const auto transaction_data = remove_0x(transaction.data);
|
||||||
|
data += base_encoder::encode_uint256(transaction_data.size() / 2);
|
||||||
|
data += transaction_data;
|
||||||
|
if (transaction_data.size() % 64 != 0) {
|
||||||
|
data += std::string((64 - transaction_data.size() % 64), '0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! rlp_encoder
|
||||||
|
std::string rlp_encoder::encode(const std::string &s) {
|
||||||
|
return encode_rlp(hex2bytes(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string rlp_encoder::encode_length(int len, int offset) {
|
||||||
|
if (len < 56) {
|
||||||
|
std::string temp;
|
||||||
|
temp = (char)(len + offset);
|
||||||
|
return temp;
|
||||||
|
} else {
|
||||||
|
const std::string hexLength = to_hex(len);
|
||||||
|
const int lLength = hexLength.size() / 2;
|
||||||
|
const std::string fByte = to_hex(offset + 55 + lLength);
|
||||||
|
return hex2bytes(fByte + hexLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string rlp_encoder::hex2bytes(const std::string &s) {
|
||||||
|
std::string dest;
|
||||||
|
const auto s_final = s.size() % 2 == 0 ? s : "0" + s;
|
||||||
|
dest.resize(s_final.size() / 2);
|
||||||
|
hex2bin(s_final.c_str(), &dest[0]);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string rlp_encoder::encode_rlp(const std::string &s) {
|
||||||
|
if (s.size() == 1 && (unsigned char)s[0] < 128)
|
||||||
|
return s;
|
||||||
|
else
|
||||||
|
return encode_length(s.size(), 128) + s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rlp_encoder::char2int(char input) {
|
||||||
|
if (input >= '0' && input <= '9')
|
||||||
|
return input - '0';
|
||||||
|
if (input >= 'A' && input <= 'F')
|
||||||
|
return input - 'A' + 10;
|
||||||
|
if (input >= 'a' && input <= 'f')
|
||||||
|
return input - 'a' + 10;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rlp_encoder::hex2bin(const char *src, char *target) {
|
||||||
|
while (*src && src[1]) {
|
||||||
|
*(target++) = char2int(*src) * 16 + char2int(src[1]);
|
||||||
|
src += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
243
libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp
Normal file
243
libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp
Normal file
|
|
@ -0,0 +1,243 @@
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
|
||||||
|
|
||||||
|
#include <boost/algorithm/hex.hpp>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
|
||||||
|
#include <secp256k1_recovery.h>
|
||||||
|
#include <sha3/sha3.h>
|
||||||
|
|
||||||
|
#include <fc/crypto/elliptic.hpp>
|
||||||
|
#include <fc/crypto/hex.hpp>
|
||||||
|
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
const secp256k1_context *eth_context() {
|
||||||
|
static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes keccak_hash(const std::string &data) {
|
||||||
|
bytes hash;
|
||||||
|
hash.resize(32);
|
||||||
|
const auto transaction_string = boost::algorithm::unhex(remove_0x(data));
|
||||||
|
keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data());
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
signature sign_hash(const bytes &hash, const std::string &chain_id, const std::string &private_key) {
|
||||||
|
const bytes priv_key = parse_hex(private_key);
|
||||||
|
|
||||||
|
int recid = 0;
|
||||||
|
secp256k1_ecdsa_recoverable_signature sig;
|
||||||
|
FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), NULL, NULL));
|
||||||
|
fc::ecc::compact_signature result;
|
||||||
|
FC_ASSERT(secp256k1_ecdsa_recoverable_signature_serialize_compact(eth_context(), (unsigned char *)result.begin() + 1, &recid, &sig));
|
||||||
|
|
||||||
|
unsigned int v = recid + from_hex<unsigned int>(chain_id) * 2 + 35;
|
||||||
|
|
||||||
|
bytes r;
|
||||||
|
for (int i = 1; i < 33; i++)
|
||||||
|
r.emplace_back((char)result.at(i));
|
||||||
|
|
||||||
|
bytes s;
|
||||||
|
for (int i = 33; i < 65; i++)
|
||||||
|
s.emplace_back((char)result.at(i));
|
||||||
|
|
||||||
|
signature eth_sig;
|
||||||
|
eth_sig.v = to_hex(v);
|
||||||
|
eth_sig.r = fc::to_hex((char *)&r[0], r.size());
|
||||||
|
eth_sig.s = fc::to_hex((char *)&s[0], s.size());
|
||||||
|
|
||||||
|
return eth_sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! base_transaction
|
||||||
|
|
||||||
|
base_transaction::base_transaction(const std::string &raw_tx) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//! transaction
|
||||||
|
|
||||||
|
transaction::transaction(const std::string &raw_tx) :
|
||||||
|
base_transaction{raw_tx} {
|
||||||
|
deserialize(raw_tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const transaction &transaction::sign(const std::string &private_key) const {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string transaction::serialize() const {
|
||||||
|
boost::property_tree::ptree pt;
|
||||||
|
pt.put("from", from);
|
||||||
|
pt.put("to", to);
|
||||||
|
pt.put("data", data);
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
boost::property_tree::json_parser::write_json(ss, pt);
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void transaction::deserialize(const std::string &raw_tx) {
|
||||||
|
std::stringstream ss_tx(raw_tx);
|
||||||
|
boost::property_tree::ptree tx_json;
|
||||||
|
boost::property_tree::read_json(ss_tx, tx_json);
|
||||||
|
|
||||||
|
if (tx_json.count("from"))
|
||||||
|
from = tx_json.get<std::string>("from");
|
||||||
|
if (tx_json.count("to"))
|
||||||
|
to = tx_json.get<std::string>("to");
|
||||||
|
if (tx_json.count("data"))
|
||||||
|
data = tx_json.get<std::string>("data");
|
||||||
|
}
|
||||||
|
|
||||||
|
//! raw_transaction
|
||||||
|
|
||||||
|
raw_transaction::raw_transaction(const std::string &raw_tx) :
|
||||||
|
base_transaction{raw_tx} {
|
||||||
|
deserialize(raw_tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes raw_transaction::hash() const {
|
||||||
|
return keccak_hash(serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
signed_transaction raw_transaction::sign(const std::string &private_key) const {
|
||||||
|
//! Prepare signed transaction
|
||||||
|
signed_transaction tr;
|
||||||
|
tr.nonce = nonce;
|
||||||
|
tr.gas_price = gas_price;
|
||||||
|
tr.gas_limit = gas_limit;
|
||||||
|
tr.to = to;
|
||||||
|
tr.value = value;
|
||||||
|
tr.data = data;
|
||||||
|
|
||||||
|
const auto sig = sign_hash(hash(), chain_id, private_key);
|
||||||
|
tr.v = sig.v;
|
||||||
|
tr.r = sig.r;
|
||||||
|
tr.s = sig.s;
|
||||||
|
|
||||||
|
return tr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string raw_transaction::serialize() const {
|
||||||
|
const std::string serialized = rlp_encoder::encode(remove_0x(nonce)) +
|
||||||
|
rlp_encoder::encode(remove_0x(gas_price)) +
|
||||||
|
rlp_encoder::encode(remove_0x(gas_limit)) +
|
||||||
|
rlp_encoder::encode(remove_0x(to)) +
|
||||||
|
rlp_encoder::encode(remove_0x(value)) +
|
||||||
|
rlp_encoder::encode(remove_0x(data)) +
|
||||||
|
rlp_encoder::encode(remove_0x(chain_id)) +
|
||||||
|
rlp_encoder::encode("") +
|
||||||
|
rlp_encoder::encode("");
|
||||||
|
|
||||||
|
return add_0x(bytes2hex(rlp_encoder::encode_length(serialized.size(), 192) + serialized));
|
||||||
|
}
|
||||||
|
|
||||||
|
void raw_transaction::deserialize(const std::string &raw_tx) {
|
||||||
|
const auto rlp_array = rlp_decoder::decode(remove_0x(raw_tx));
|
||||||
|
FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format");
|
||||||
|
|
||||||
|
nonce = !rlp_array.at(0).empty() ? add_0x(rlp_array.at(0)) : add_0x("0");
|
||||||
|
boost::algorithm::to_lower(nonce);
|
||||||
|
gas_price = add_0x(rlp_array.at(1));
|
||||||
|
boost::algorithm::to_lower(gas_price);
|
||||||
|
gas_limit = add_0x(rlp_array.at(2));
|
||||||
|
boost::algorithm::to_lower(gas_limit);
|
||||||
|
to = add_0x(rlp_array.at(3));
|
||||||
|
boost::algorithm::to_lower(to);
|
||||||
|
value = !rlp_array.at(4).empty() ? add_0x(rlp_array.at(4)) : add_0x("0");
|
||||||
|
boost::algorithm::to_lower(value);
|
||||||
|
data = !rlp_array.at(5).empty() ? add_0x(rlp_array.at(5)) : "";
|
||||||
|
boost::algorithm::to_lower(data);
|
||||||
|
chain_id = add_0x(rlp_array.at(6));
|
||||||
|
boost::algorithm::to_lower(chain_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! signed_transaction
|
||||||
|
|
||||||
|
signed_transaction::signed_transaction(const std::string &raw_tx) :
|
||||||
|
base_transaction{raw_tx} {
|
||||||
|
deserialize(raw_tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string signed_transaction::recover(const std::string &chain_id) const {
|
||||||
|
fc::ecc::compact_signature input64;
|
||||||
|
fc::from_hex(r, (char *)&input64.at(1), 32);
|
||||||
|
const int recid = from_hex<unsigned int>(v) - from_hex<unsigned int>(chain_id) * 2 - 35;
|
||||||
|
fc::from_hex(std::to_string(recid), (char *)&input64.at(0), 1);
|
||||||
|
fc::from_hex(s, (char *)&input64.at(33), 32);
|
||||||
|
|
||||||
|
secp256k1_ecdsa_recoverable_signature sig;
|
||||||
|
FC_ASSERT(secp256k1_ecdsa_recoverable_signature_parse_compact(eth_context(), &sig, (const unsigned char *)&input64.data[1], recid));
|
||||||
|
|
||||||
|
raw_transaction tr;
|
||||||
|
tr.nonce = nonce;
|
||||||
|
tr.gas_price = gas_price;
|
||||||
|
tr.gas_limit = gas_limit;
|
||||||
|
tr.to = to;
|
||||||
|
tr.value = value;
|
||||||
|
tr.data = data;
|
||||||
|
tr.chain_id = chain_id;
|
||||||
|
|
||||||
|
secp256k1_pubkey rawPubkey;
|
||||||
|
FC_ASSERT(secp256k1_ecdsa_recover(eth_context(), &rawPubkey, &sig, (const unsigned char *)tr.hash().data()));
|
||||||
|
|
||||||
|
std::array<uint8_t, 65> pubkey;
|
||||||
|
size_t biglen = 65;
|
||||||
|
FC_ASSERT(secp256k1_ec_pubkey_serialize(eth_context(), pubkey.data(), &biglen, &rawPubkey, SECP256K1_EC_UNCOMPRESSED));
|
||||||
|
|
||||||
|
const std::string out = std::string(pubkey.begin(), pubkey.end()).substr(1);
|
||||||
|
bytes hash;
|
||||||
|
hash.resize(32);
|
||||||
|
keccak_256((const unsigned char *)out.data(), out.size(), (unsigned char *)hash.data());
|
||||||
|
|
||||||
|
return add_0x(fc::to_hex((char *)&hash[0], hash.size()).substr(24));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string signed_transaction::serialize() const {
|
||||||
|
const std::string serialized = rlp_encoder::encode(remove_0x(nonce)) +
|
||||||
|
rlp_encoder::encode(remove_0x(gas_price)) +
|
||||||
|
rlp_encoder::encode(remove_0x(gas_limit)) +
|
||||||
|
rlp_encoder::encode(remove_0x(to)) +
|
||||||
|
rlp_encoder::encode(remove_0x(value)) +
|
||||||
|
rlp_encoder::encode(remove_0x(data)) +
|
||||||
|
rlp_encoder::encode(remove_0x(v)) +
|
||||||
|
rlp_encoder::encode(remove_leading_00(remove_0x(r))) +
|
||||||
|
rlp_encoder::encode(remove_leading_00(remove_0x(s)));
|
||||||
|
|
||||||
|
return add_0x(bytes2hex(rlp_encoder::encode_length(serialized.size(), 192) + serialized));
|
||||||
|
}
|
||||||
|
|
||||||
|
void signed_transaction::deserialize(const std::string &raw_tx) {
|
||||||
|
const auto rlp_array = rlp_decoder::decode(remove_0x(raw_tx));
|
||||||
|
FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format");
|
||||||
|
|
||||||
|
nonce = !rlp_array.at(0).empty() ? add_0x(rlp_array.at(0)) : add_0x("0");
|
||||||
|
boost::algorithm::to_lower(nonce);
|
||||||
|
gas_price = add_0x(rlp_array.at(1));
|
||||||
|
boost::algorithm::to_lower(gas_price);
|
||||||
|
gas_limit = add_0x(rlp_array.at(2));
|
||||||
|
boost::algorithm::to_lower(gas_limit);
|
||||||
|
to = add_0x(rlp_array.at(3));
|
||||||
|
boost::algorithm::to_lower(to);
|
||||||
|
value = !rlp_array.at(4).empty() ? add_0x(rlp_array.at(4)) : add_0x("0");
|
||||||
|
boost::algorithm::to_lower(value);
|
||||||
|
data = !rlp_array.at(5).empty() ? add_0x(rlp_array.at(5)) : "";
|
||||||
|
boost::algorithm::to_lower(data);
|
||||||
|
v = add_0x(rlp_array.at(6));
|
||||||
|
boost::algorithm::to_lower(v);
|
||||||
|
r = add_0x(add_leading_00(rlp_array.at(7)));
|
||||||
|
boost::algorithm::to_lower(r);
|
||||||
|
s = add_0x(add_leading_00(rlp_array.at(8)));
|
||||||
|
boost::algorithm::to_lower(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
36
libraries/plugins/peerplays_sidechain/ethereum/types.cpp
Normal file
36
libraries/plugins/peerplays_sidechain/ethereum/types.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
|
||||||
|
|
||||||
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
signature::signature(const std::string &sign) {
|
||||||
|
deserialize(sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string signature::serialize() const {
|
||||||
|
boost::property_tree::ptree pt;
|
||||||
|
pt.put("v", v);
|
||||||
|
pt.put("r", r);
|
||||||
|
pt.put("s", s);
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
boost::property_tree::json_parser::write_json(ss, pt);
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void signature::deserialize(const std::string &raw_tx) {
|
||||||
|
std::stringstream ss_tx(raw_tx);
|
||||||
|
boost::property_tree::ptree tx_json;
|
||||||
|
boost::property_tree::read_json(ss_tx, tx_json);
|
||||||
|
|
||||||
|
if (tx_json.count("v"))
|
||||||
|
v = tx_json.get<std::string>("v");
|
||||||
|
if (tx_json.count("r"))
|
||||||
|
r = tx_json.get<std::string>("r");
|
||||||
|
if (tx_json.count("s"))
|
||||||
|
s = tx_json.get<std::string>("s");
|
||||||
|
}
|
||||||
|
|
||||||
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
72
libraries/plugins/peerplays_sidechain/ethereum/utils.cpp
Normal file
72
libraries/plugins/peerplays_sidechain/ethereum/utils.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
|
||||||
|
|
||||||
|
#include <fc/crypto/hex.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
bytes parse_hex(const std::string &str) {
|
||||||
|
bytes vec(str.size() / 2);
|
||||||
|
fc::from_hex(str, vec.data(), vec.size());
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string bytes2hex(const std::string &s) {
|
||||||
|
std::string dest;
|
||||||
|
for (const auto &i : s)
|
||||||
|
dest += uchar2Hex((unsigned char)i);
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string uchar2Hex(unsigned char n) {
|
||||||
|
std::string dest;
|
||||||
|
dest.resize(2);
|
||||||
|
sprintf(&dest[0], "%X", n);
|
||||||
|
|
||||||
|
if (n < (unsigned char)16) {
|
||||||
|
dest[1] = dest[0];
|
||||||
|
dest[0] = '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string add_0x(const std::string &s) {
|
||||||
|
if (s.size() > 1) {
|
||||||
|
if (s.substr(0, 2) == "0x")
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "0x" + s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string remove_0x(const std::string &s) {
|
||||||
|
if (s.size() > 1) {
|
||||||
|
if (s.substr(0, 2) == "0x")
|
||||||
|
return s.substr(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string add_leading_00(const std::string &s) {
|
||||||
|
std::string result = s;
|
||||||
|
|
||||||
|
while (result.size() < 64) {
|
||||||
|
result = "00" + result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string remove_leading_00(const std::string &s) {
|
||||||
|
std::string result = s;
|
||||||
|
|
||||||
|
while (result.size() > 1 && result.substr(0, 2) == "00") {
|
||||||
|
result = result.substr(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
@ -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,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
typedef std::function<uint64_t()> get_fee_func_type;
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
|
class estimate_fee_external {
|
||||||
|
public:
|
||||||
|
estimate_fee_external();
|
||||||
|
~estimate_fee_external();
|
||||||
|
std::vector<std::pair<std::string, uint64_t>> get_fee_external(uint16_t target_block);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string get_response(std::string url);
|
||||||
|
// Here add your custom parser for external url. Take care of incremental name
|
||||||
|
// and populate the list of url_parsers bellow paired with the function
|
||||||
|
uint64_t parse_and_get_fee_1();
|
||||||
|
uint64_t parse_and_get_fee_2();
|
||||||
|
uint64_t parse_and_get_fee_3();
|
||||||
|
|
||||||
|
const std::map<std::string, get_fee_func_type> url_get_fee_parsers{
|
||||||
|
{"https://www.bitgo.com/api/v2/btc/tx/fee", std::bind(&estimate_fee_external::parse_and_get_fee_1, this)},
|
||||||
|
{"https://bitcoiner.live/api/fees/estimates/latest", std::bind(&estimate_fee_external::parse_and_get_fee_2, this)},
|
||||||
|
{"https://api.blockchain.info/mempool/fees", std::bind(&estimate_fee_external::parse_and_get_fee_3, this)}};
|
||||||
|
|
||||||
|
std::string response;
|
||||||
|
uint16_t target_block;
|
||||||
|
CURL *curl{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
@ -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
|
||||||
|
|
@ -8,23 +8,23 @@ namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
|
||||||
|
|
||||||
class bitcoin_transaction;
|
class bitcoin_transaction;
|
||||||
|
|
||||||
const secp256k1_context_t *btc_context();
|
const secp256k1_context *btc_context();
|
||||||
|
|
||||||
fc::sha256 get_signature_hash(const bitcoin_transaction &tx, const bytes &scriptPubKey, int64_t amount,
|
fc::sha256 get_signature_hash(const bitcoin_transaction &tx, const bytes &scriptPubKey, int64_t amount,
|
||||||
size_t in_index, int hash_type, bool is_witness);
|
size_t in_index, int hash_type, bool is_witness);
|
||||||
|
|
||||||
std::vector<char> privkey_sign(const bytes &privkey, const fc::sha256 &hash, const secp256k1_context_t *context_sign = nullptr);
|
std::vector<char> privkey_sign(const bytes &privkey, const fc::sha256 &hash, const secp256k1_context *context_sign = nullptr);
|
||||||
|
|
||||||
std::vector<bytes> sign_witness_transaction_part(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
|
std::vector<bytes> sign_witness_transaction_part(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
|
||||||
const std::vector<uint64_t> &amounts, const bytes &privkey,
|
const std::vector<uint64_t> &amounts, const bytes &privkey,
|
||||||
const secp256k1_context_t *context_sign = nullptr, int hash_type = 1);
|
const secp256k1_context *context_sign = nullptr, int hash_type = 1);
|
||||||
|
|
||||||
void sign_witness_transaction_finalize(bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts, bool use_mulisig_workaround = true);
|
void sign_witness_transaction_finalize(bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts, bool use_mulisig_workaround = true);
|
||||||
|
|
||||||
bool verify_sig(const bytes &sig, const bytes &pubkey, const bytes &msg, const secp256k1_context_t *context);
|
bool verify_sig(const bytes &sig, const bytes &pubkey, const bytes &msg, const secp256k1_context *context);
|
||||||
|
|
||||||
std::vector<std::vector<bytes>> sort_sigs(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
|
std::vector<std::vector<bytes>> sort_sigs(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
|
||||||
const std::vector<uint64_t> &amounts, const secp256k1_context_t *context);
|
const std::vector<uint64_t> &amounts, const secp256k1_context *context);
|
||||||
|
|
||||||
void add_signatures_to_transaction_multisig(bitcoin_transaction &tx, std::vector<std::vector<bytes>> &signature_set);
|
void add_signatures_to_transaction_multisig(bitcoin_transaction &tx, std::vector<std::vector<bytes>> &signature_set);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -3,134 +3,52 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <fc/thread/future.hpp>
|
||||||
#include <boost/asio/ssl.hpp>
|
#include <fc/thread/thread.hpp>
|
||||||
|
|
||||||
//#include <fc/network/http/connection.hpp>
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
|
#include <boost/beast/core.hpp>
|
||||||
|
|
||||||
|
#include <graphene/peerplays_sidechain/defs.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
enum class url_schema_type { unknown,
|
class rpc_connection;
|
||||||
http,
|
|
||||||
https,
|
struct rpc_credentials {
|
||||||
|
std::string url;
|
||||||
|
std::string user;
|
||||||
|
std::string password;
|
||||||
};
|
};
|
||||||
|
|
||||||
// utl
|
|
||||||
|
|
||||||
url_schema_type identify_url_schema_type(const std::string &schema_name);
|
|
||||||
|
|
||||||
struct url_data {
|
|
||||||
|
|
||||||
url_schema_type schema_type;
|
|
||||||
std::string schema;
|
|
||||||
std::string host;
|
|
||||||
uint16_t port;
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
url_data() :
|
|
||||||
schema_type(url_schema_type::unknown),
|
|
||||||
port(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
url_data(const std::string &url);
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
bool parse(const std::string &url);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct http_request {
|
|
||||||
|
|
||||||
std::string body;
|
|
||||||
std::string content_type;
|
|
||||||
|
|
||||||
http_request(const std::string &body_, const std::string &content_type_) :
|
|
||||||
body(body_),
|
|
||||||
content_type(content_type_) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct http_response {
|
|
||||||
|
|
||||||
uint16_t status_code;
|
|
||||||
std::string body;
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
status_code = 0;
|
|
||||||
body = decltype(body)();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template <class>
|
|
||||||
class http_call_impl;
|
|
||||||
class tcp_socket;
|
|
||||||
class ssl_socket;
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
class http_call {
|
|
||||||
public:
|
|
||||||
http_call(const url_data &url, const std::string &method = std::string(), const std::string &headers = std::string());
|
|
||||||
~http_call();
|
|
||||||
|
|
||||||
bool is_ssl() const;
|
|
||||||
|
|
||||||
const std::string &path() const;
|
|
||||||
void set_path(const std::string &path);
|
|
||||||
void set_method(const std::string &method);
|
|
||||||
void set_headers(const std::string &headers);
|
|
||||||
const std::string &host() const;
|
|
||||||
void set_host(const std::string &host);
|
|
||||||
|
|
||||||
uint16_t port() const;
|
|
||||||
void set_port(uint16_t port);
|
|
||||||
|
|
||||||
bool exec(const http_request &request, http_response *response);
|
|
||||||
|
|
||||||
const std::string &error_what() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <class>
|
|
||||||
friend class detail::http_call_impl;
|
|
||||||
friend detail::tcp_socket;
|
|
||||||
friend detail::ssl_socket;
|
|
||||||
static constexpr auto response_size_limit_bytes = 16 * 1024 * 1024;
|
|
||||||
static constexpr auto response_first_alloc_bytes = 32 * 1024;
|
|
||||||
static constexpr auto response_next_alloc_bytes = 256 * 1024;
|
|
||||||
std::string m_host;
|
|
||||||
uint16_t m_port_default;
|
|
||||||
uint16_t m_port;
|
|
||||||
std::string m_path;
|
|
||||||
std::string m_method;
|
|
||||||
std::string m_headers;
|
|
||||||
std::string m_error_what;
|
|
||||||
|
|
||||||
boost::asio::io_service m_service;
|
|
||||||
boost::asio::ssl::context *m_context;
|
|
||||||
boost::asio::ip::tcp::endpoint m_endpoint;
|
|
||||||
|
|
||||||
void ctor_priv();
|
|
||||||
};
|
|
||||||
|
|
||||||
}} // namespace graphene::peerplays_sidechain
|
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
|
||||||
|
|
||||||
class rpc_client {
|
class rpc_client {
|
||||||
public:
|
public:
|
||||||
rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug);
|
const sidechain_type sidechain;
|
||||||
|
|
||||||
|
rpc_client(sidechain_type _sidechain, const std::vector<rpc_credentials> &_credentials, bool _debug_rpc_calls, bool _simulate_connection_reselection);
|
||||||
|
~rpc_client();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx);
|
bool debug_rpc_calls;
|
||||||
std::string retrieve_value_from_reply(std::string reply_str, std::string value_path);
|
bool simulate_connection_reselection;
|
||||||
std::string send_post_request(std::string method, std::string params, bool show_log);
|
std::string send_post_request(std::string method, std::string params, bool show_log);
|
||||||
|
|
||||||
bool debug_rpc_calls;
|
static std::string send_post_request(rpc_connection &conn, std::string method, std::string params, bool show_log);
|
||||||
uint32_t request_id;
|
|
||||||
|
static std::string retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx);
|
||||||
|
static std::string retrieve_value_from_reply(std::string reply_str, std::string value_path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
http_call client;
|
std::vector<rpc_connection *> connections;
|
||||||
http_response send_post_request(const std::string &body, bool show_log);
|
int n_active_conn;
|
||||||
|
fc::future<void> connection_selection_task;
|
||||||
|
std::mutex conn_mutex;
|
||||||
|
|
||||||
|
rpc_connection &get_active_connection() const;
|
||||||
|
|
||||||
|
void select_connection();
|
||||||
|
void schedule_connection_selection();
|
||||||
|
virtual uint64_t ping(rpc_connection &conn) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,12 @@
|
||||||
|
|
||||||
#include <graphene/chain/protocol/asset.hpp>
|
#include <graphene/chain/protocol/asset.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
|
std::string base64_encode(const std::string &s);
|
||||||
|
std::string base64_decode(const std::string &s);
|
||||||
|
|
||||||
std::string object_id_to_string(graphene::chain::object_id_type id);
|
std::string object_id_to_string(graphene::chain::object_id_type id);
|
||||||
|
graphene::chain::object_id_type string_to_object_id(const std::string &id);
|
||||||
|
|
||||||
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,16 @@ struct info_for_vin {
|
||||||
bool resend = false;
|
bool resend = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class sidechain_event_type {
|
||||||
|
deposit,
|
||||||
|
withdrawal
|
||||||
|
};
|
||||||
|
|
||||||
struct sidechain_event_data {
|
struct sidechain_event_data {
|
||||||
fc::time_point_sec timestamp;
|
fc::time_point_sec timestamp;
|
||||||
uint32_t block_num;
|
uint32_t block_num;
|
||||||
sidechain_type sidechain;
|
sidechain_type sidechain;
|
||||||
|
sidechain_event_type type;
|
||||||
std::string sidechain_uid;
|
std::string sidechain_uid;
|
||||||
std::string sidechain_transaction_id;
|
std::string sidechain_transaction_id;
|
||||||
std::string sidechain_from;
|
std::string sidechain_from;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/multiprecision/cpp_int.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <fc/optional.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
class base_decoder {
|
||||||
|
public:
|
||||||
|
static boost::multiprecision::uint256_t decode_uint256(const std::string &value);
|
||||||
|
static std::string decode_address(const std::string &value);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct deposit_erc20_transaction {
|
||||||
|
std::string token;
|
||||||
|
boost::multiprecision::uint256_t amount;
|
||||||
|
};
|
||||||
|
|
||||||
|
class deposit_erc20_decoder {
|
||||||
|
public:
|
||||||
|
static const std::string function_signature;
|
||||||
|
|
||||||
|
static fc::optional<deposit_erc20_transaction> decode(const std::string &input);
|
||||||
|
};
|
||||||
|
|
||||||
|
class rlp_decoder {
|
||||||
|
private:
|
||||||
|
enum RLP_constants {
|
||||||
|
RLP_maxUintLen = 8,
|
||||||
|
RLP_bufferLenStart = 0x80,
|
||||||
|
RLP_listStart = 0xc0,
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::vector<std::string> decode(const std::string &str);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::vector<std::string> decode_rlp(const unsigned char *raw, size_t len, size_t &consumed);
|
||||||
|
static std::vector<std::string> decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen);
|
||||||
|
static uint64_t to_int(const unsigned char *raw, size_t len);
|
||||||
|
static std::vector<unsigned char> parse_hex(const std::string &str);
|
||||||
|
static std::vector<unsigned char> parse_hex(const char *psz);
|
||||||
|
static signed char hex_digit(char c);
|
||||||
|
};
|
||||||
|
|
||||||
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/multiprecision/cpp_int.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
struct encoded_sign_transaction {
|
||||||
|
std::string data;
|
||||||
|
signature sign;
|
||||||
|
};
|
||||||
|
|
||||||
|
class base_encoder {
|
||||||
|
public:
|
||||||
|
static std::string encode_uint256(boost::multiprecision::uint256_t value);
|
||||||
|
static std::string encode_address(const std::string &value);
|
||||||
|
static std::string encode_string(const std::string &value);
|
||||||
|
};
|
||||||
|
|
||||||
|
class update_owners_encoder {
|
||||||
|
public:
|
||||||
|
static const std::string function_signature;
|
||||||
|
|
||||||
|
static std::string encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
class withdrawal_encoder {
|
||||||
|
public:
|
||||||
|
static const std::string function_signature;
|
||||||
|
|
||||||
|
static std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
class withdrawal_erc20_encoder {
|
||||||
|
public:
|
||||||
|
static const std::string function_signature;
|
||||||
|
|
||||||
|
static std::string encode(const std::string &token, const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
class signature_encoder {
|
||||||
|
public:
|
||||||
|
const std::string function_signature;
|
||||||
|
|
||||||
|
signature_encoder(const std::string &function_hash);
|
||||||
|
|
||||||
|
static std::string get_function_signature_from_transaction(const std::string &transaction);
|
||||||
|
|
||||||
|
std::string encode(const std::vector<encoded_sign_transaction> &transactions) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class rlp_encoder {
|
||||||
|
public:
|
||||||
|
static std::string encode(const std::string &s);
|
||||||
|
static std::string encode_length(int len, int offset);
|
||||||
|
static std::string hex2bytes(const std::string &s);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string encode_rlp(const std::string &s);
|
||||||
|
static int char2int(char input);
|
||||||
|
static void hex2bin(const char *src, char *target);
|
||||||
|
};
|
||||||
|
|
||||||
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
bytes keccak_hash(const std::string &data);
|
||||||
|
signature sign_hash(const bytes &hash, const std::string &chain_id, const std::string &private_key);
|
||||||
|
|
||||||
|
class base_transaction {
|
||||||
|
public:
|
||||||
|
base_transaction() = default;
|
||||||
|
base_transaction(const std::string &raw_tx);
|
||||||
|
|
||||||
|
virtual std::string serialize() const = 0;
|
||||||
|
virtual void deserialize(const std::string &raw_tx) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class transaction : base_transaction {
|
||||||
|
public:
|
||||||
|
std::string from;
|
||||||
|
std::string to;
|
||||||
|
std::string data;
|
||||||
|
|
||||||
|
transaction() = default;
|
||||||
|
transaction(const std::string &raw_tx);
|
||||||
|
|
||||||
|
const transaction &sign(const std::string &private_key) const;
|
||||||
|
|
||||||
|
virtual std::string serialize() const override;
|
||||||
|
virtual void deserialize(const std::string &raw_tx) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class signed_transaction;
|
||||||
|
class raw_transaction : base_transaction {
|
||||||
|
public:
|
||||||
|
std::string nonce;
|
||||||
|
std::string gas_price;
|
||||||
|
std::string gas_limit;
|
||||||
|
std::string to;
|
||||||
|
std::string value;
|
||||||
|
std::string data;
|
||||||
|
std::string chain_id;
|
||||||
|
|
||||||
|
raw_transaction() = default;
|
||||||
|
raw_transaction(const std::string &raw_tx);
|
||||||
|
|
||||||
|
bytes hash() const;
|
||||||
|
signed_transaction sign(const std::string &private_key) const;
|
||||||
|
|
||||||
|
virtual std::string serialize() const override;
|
||||||
|
virtual void deserialize(const std::string &raw_tx) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class signed_transaction : base_transaction {
|
||||||
|
public:
|
||||||
|
std::string nonce;
|
||||||
|
std::string gas_price;
|
||||||
|
std::string gas_limit;
|
||||||
|
std::string to;
|
||||||
|
std::string value;
|
||||||
|
std::string data;
|
||||||
|
std::string v;
|
||||||
|
std::string r;
|
||||||
|
std::string s;
|
||||||
|
|
||||||
|
signed_transaction() = default;
|
||||||
|
signed_transaction(const std::string &raw_tx);
|
||||||
|
|
||||||
|
std::string recover(const std::string &chain_id) const;
|
||||||
|
|
||||||
|
virtual std::string serialize() const override;
|
||||||
|
virtual void deserialize(const std::string &raw_tx) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/multiprecision/cpp_int.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
typedef uint64_t chain_id_type;
|
||||||
|
typedef uint64_t network_id_type;
|
||||||
|
|
||||||
|
using bytes = std::vector<char>;
|
||||||
|
|
||||||
|
class signature {
|
||||||
|
public:
|
||||||
|
std::string v;
|
||||||
|
std::string r;
|
||||||
|
std::string s;
|
||||||
|
|
||||||
|
signature() = default;
|
||||||
|
signature(const std::string &sign);
|
||||||
|
|
||||||
|
std::string serialize() const;
|
||||||
|
void deserialize(const std::string &sign);
|
||||||
|
};
|
||||||
|
|
||||||
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
bytes parse_hex(const std::string &str);
|
||||||
|
|
||||||
|
std::string bytes2hex(const std::string &s);
|
||||||
|
|
||||||
|
std::string uchar2Hex(unsigned char n);
|
||||||
|
|
||||||
|
std::string add_0x(const std::string &s);
|
||||||
|
|
||||||
|
std::string remove_0x(const std::string &s);
|
||||||
|
|
||||||
|
std::string add_leading_00(const std::string &s);
|
||||||
|
|
||||||
|
std::string remove_leading_00(const std::string &s);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string to_hex(const T &val, bool add_front_zero = true) {
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << std::hex << val;
|
||||||
|
std::string result(stream.str());
|
||||||
|
if (add_front_zero) {
|
||||||
|
if (result.size() % 2)
|
||||||
|
result = "0" + result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T from_hex(const std::string &s) {
|
||||||
|
T val;
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << std::hex << s;
|
||||||
|
stream >> val;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
@ -22,15 +22,15 @@ typedef fc::ecc::private_key private_key_type;
|
||||||
typedef fc::sha256 chain_id_type;
|
typedef fc::sha256 chain_id_type;
|
||||||
typedef std::string account_name_type;
|
typedef std::string account_name_type;
|
||||||
typedef fc::ripemd160 block_id_type;
|
typedef fc::ripemd160 block_id_type;
|
||||||
//typedef fc::ripemd160 checksum_type;
|
// typedef fc::ripemd160 checksum_type;
|
||||||
typedef fc::ripemd160 transaction_id_type;
|
typedef fc::ripemd160 transaction_id_type;
|
||||||
typedef fc::sha256 digest_type;
|
typedef fc::sha256 digest_type;
|
||||||
typedef fc::ecc::compact_signature signature_type;
|
typedef fc::ecc::compact_signature signature_type;
|
||||||
typedef fc::safe<int64_t> share_type;
|
typedef fc::safe<int64_t> share_type;
|
||||||
//typedef safe<uint64_t> ushare_type;
|
// typedef safe<uint64_t> ushare_type;
|
||||||
//typedef uint16_t weight_type;
|
// typedef uint16_t weight_type;
|
||||||
//typedef uint32_t contribution_id_type;
|
// typedef uint32_t contribution_id_type;
|
||||||
//typedef fixed_string<32> custom_id_type;
|
// typedef fixed_string<32> custom_id_type;
|
||||||
|
|
||||||
struct public_key_type {
|
struct public_key_type {
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue