Compare commits
244 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| de588ce198 | |||
| c15f84507d | |||
| d65158aa00 | |||
| 0e53fc1b62 | |||
| ca8f031bae | |||
| 5b71d02dd2 | |||
| 11a58c587d | |||
| b357a163ce | |||
| c94218fdfe | |||
| 9efc569ae5 | |||
| bee268ca10 | |||
| 9a15597983 | |||
| 552aedc95c | |||
| 0c08b9ed28 | |||
| b641746863 | |||
| 8a0ed73c1a | |||
| 2d2f7880ca | |||
| 5d6dc09dd9 | |||
| 87359e262a | |||
| 9b948c0150 | |||
| ae0439ba8c | |||
| 4dcb8318a3 | |||
| b92b997c6b | |||
| 59ee6ed2ee | |||
| b52647b2c9 | |||
| 8d2637e6a5 | |||
| 216534d5e9 | |||
| 59ba45da4e | |||
| 905c5cc900 | |||
| fa94b49279 | |||
| 9497c0897a | |||
| 2fdb55e340 | |||
| 2d96bfe3b2 | |||
| e0ecbb649f | |||
| 20b0d9d60e | |||
| 47012ce342 | |||
| 2b03bff637 | |||
| b1c6847a75 | |||
| 1e9587826c | |||
| aa09279bab | |||
| a7ad638eb6 | |||
| bc5b1daaff | |||
| 7ddf820603 | |||
| 4c305088ac | |||
| e5bb8b2151 | |||
| 645c15b4c9 | |||
| 8af31a80c1 | |||
| 70fca6820e | |||
| 6ecf3db344 | |||
| aa7d8a6f17 | |||
| ec3b6fb901 | |||
| 090bb3b84a | |||
| 14e8744a16 | |||
| 3d3c6f3f83 | |||
| e512ae876f | |||
| 8ef7391c59 | |||
| 3fb64777d6 | |||
| d15b62c0c7 | |||
| 4f35faef9e | |||
| 1476c1fdc8 | |||
| b4b029d189 | |||
| 91edd31d9f | |||
| 153ad0d84b | |||
| efdbb176e5 | |||
| 9fc59835eb | |||
| 9d52949b37 | |||
| 6292407a59 | |||
| a72f980728 | |||
| 39a6347310 | |||
| 6015686b31 | |||
| 0f1b594a9d | |||
| 0e6b4e969d | |||
| 36ac6e0ed7 | |||
| ccb509fedd | |||
| 8edc3f1fc6 | |||
| 772392df5b | |||
| c9a2bfff94 | |||
| 13004af9e3 | |||
| d5edd70f99 | |||
| ae00005127 | |||
| cb3ccfc739 | |||
| c023d3a837 | |||
| 7caf43059a | |||
| 3c1079c812 | |||
| 69c3db06a9 | |||
| 2e9cffa2ff | |||
| f41cddc690 | |||
| c3d3a02be2 | |||
| 04e9472e30 | |||
| f313860ce1 | |||
| 455b6558f9 | |||
| ebb14d15d0 | |||
| 18ba34d98e | |||
| c4260e1cba | |||
| b0ccf805ae | |||
| 6ecc162e69 | |||
| be063ffe81 | |||
| 030b062fd7 | |||
| b6eee20fad | |||
| 0d0fa9bd9d | |||
| 71fa65ed21 | |||
| 30e66efc3a | |||
| 43e8d542fd | |||
| adeb2ebb40 | |||
| 1987bfb87b | |||
| bbc010d530 | |||
| 824f2e4c4f | |||
| 024c00c653 | |||
| 1b41777178 | |||
| 8676c48c79 | |||
| eff27476f2 | |||
| ffc4fed389 | |||
| 0b503d8af1 | |||
| 3ea1153568 | |||
| a6e466d12c | |||
| 0cf008b736 | |||
| 8ef4d9ae63 | |||
| 120b8a218f | |||
| 8ca4c2e797 | |||
| 0dc0bf04fa | |||
| 8add1de424 | |||
| cebdaeea38 | |||
| 1a7de9a784 | |||
| a53baae5e1 | |||
| f2a152b533 | |||
| 3d7b806b6e | |||
| f1d4e091c6 | |||
| 3d2a856422 | |||
| 6c4934d018 | |||
| 1fcc038f73 | |||
| 1568db3d04 | |||
| 7a3219c57f | |||
| 79e88acc60 | |||
| 17e5d327ff | |||
| 5f30678870 | |||
| a227fe76c8 | |||
| aa029c5849 | |||
| 316c0d5859 | |||
| 5dc6da40ea | |||
| 2ad4acf711 | |||
| c22ec81513 | |||
| 8c922dc690 | |||
| af52c2f891 | |||
| 1bb8e2b709 | |||
| 4899513084 | |||
| fef16099ce | |||
| bebd6a03fa | |||
| 6f5f2bcabc | |||
| abcbc7e927 | |||
| 4bc7fed862 | |||
| ebf9c8c168 | |||
| 28c9f25dd1 | |||
| 7b4349970e | |||
| a9e27cc641 | |||
| bc5ecd4b7d | |||
| 56e45f74c1 | |||
| 65f169a224 | |||
| f74dfa7d8c | |||
| 1d634e1c54 | |||
| bb55a758cc | |||
| 63857ce274 | |||
| fef8e5ae51 | |||
| 9ff810e580 | |||
| dc3d83988b | |||
| 0b3d134ea0 | |||
| 7aeaedd466 | |||
| a63c57aa35 | |||
| 57da493022 | |||
| 817cabb105 | |||
| 3ae4b7d434 | |||
| 6ddcfd6d45 | |||
| f4ea2f28f1 | |||
| d5a73f15b7 | |||
| 6a283dca85 | |||
| 62f37bc9f9 | |||
| 580ace4647 | |||
| c886c212a2 | |||
| b2943c1466 | |||
| d12d09dc8c | |||
| f28a665d72 | |||
| 79960fa885 | |||
| a568762735 | |||
| 4c44ce9d01 | |||
| 7feb2dfb1b | |||
| bd6f14b923 | |||
| cc18180eb5 | |||
| 5465066b77 | |||
| 7bdc7bba98 | |||
| a08fe0a427 | |||
| a6d26d638a | |||
| 03806436eb | |||
| 2069c845e6 | |||
| f155ed0011 | |||
| 41607c227a | |||
| b01fcdd233 | |||
| d6a6fb5c43 | |||
| 9fa0fe01b2 | |||
| e18d60dfed | |||
| 8ac8a255a1 | |||
| 36deb3b29d | |||
| 26cbf288fe | |||
| cbdea09fbc | |||
| 30d6eeb491 | |||
| 5f71755811 | |||
| d486d0a6f2 | |||
| 58a8cc5228 | |||
| 3d4e760e55 | |||
| b98792a84e | |||
| 0ddaae68e8 | |||
| 3a991b8419 | |||
| 11a8715bee | |||
| 4f91b67774 | |||
| 8a94b88d32 | |||
| a7bc33b939 | |||
| 97055bcc90 | |||
| 9da843f749 | |||
| fa5bcff358 | |||
| f27a3fdc44 | |||
| ff38254c95 | |||
| 2683386aa5 | |||
| ca93161f2f | |||
| fd1b3c81ad | |||
| a3ed3feb2c | |||
| 88812e5257 | |||
| 950834731b | |||
| 0172dc055f | |||
| 5100f44b46 | |||
| cd80859b12 | |||
| 50a662db4b | |||
| ddd135bf22 | |||
| fcfe827615 | |||
| 4f03913543 | |||
| 4cd534a148 | |||
| fce62ceff5 | |||
| 05fda58d33 | |||
| 9077f9bbe2 | |||
| c1f8889088 | |||
| b0c409a2f8 | |||
| dc13e7271d | |||
| 60cedbc26b | |||
| e11e7dddca | |||
| 0b64f879e3 | |||
| 7f017d5590 | |||
| 2b5140489c |
@@ -79,6 +79,8 @@ Testing/*
|
||||
build.tar.gz
|
||||
build/*
|
||||
build-debug/*
|
||||
deps/*
|
||||
dependencies/*
|
||||
|
||||
etc/eosio/node_*
|
||||
var/lib/node_*
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ set( CXX_STANDARD_REQUIRED ON)
|
||||
set(VERSION_MAJOR 3)
|
||||
set(VERSION_MINOR 2)
|
||||
set(VERSION_PATCH 0)
|
||||
set(VERSION_SUFFIX dev)
|
||||
#set(VERSION_SUFFIX rc2)
|
||||
|
||||
if(VERSION_SUFFIX)
|
||||
set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}")
|
||||
|
||||
@@ -51,7 +51,7 @@ find_package(Boost @Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@ EXACT REQUIRED CO
|
||||
|
||||
find_library(libtester eosio_testing @CMAKE_BINARY_DIR@/libraries/testing NO_DEFAULT_PATH)
|
||||
find_library(libchain eosio_chain @CMAKE_BINARY_DIR@/libraries/chain NO_DEFAULT_PATH)
|
||||
find_library(libfc fc @CMAKE_BINARY_DIR@/libraries/fc NO_DEFAULT_PATH)
|
||||
find_library(libfc fc @CMAKE_BINARY_DIR@/libraries/libfc NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1 @CMAKE_BINARY_DIR@/libraries/libfc/secp256k1 NO_DEFAULT_PATH)
|
||||
|
||||
find_library(libff ff @CMAKE_BINARY_DIR@/libraries/libfc/libraries/ff/libff NO_DEFAULT_PATH)
|
||||
|
||||
@@ -1,126 +1,257 @@
|
||||
# Leap
|
||||
Leap is a C++ implementation of the [Antelope](https://github.com/AntelopeIO) protocol. It contains blockchain node software and supporting tools for developers and node operators.
|
||||
|
||||
Leap is blockchain node software and supporting tools that implements the [Antelope](https://github.com/AntelopeIO) protocol.
|
||||
## Branches
|
||||
The `main` branch is the development branch; do not use it for production. Refer to the [release page](https://github.com/AntelopeIO/leap/releases) for current information on releases, pre-releases, and obsolete releases, as well as the corresponding tags for those releases.
|
||||
|
||||
## Repo Organization
|
||||
## Supported Operating Systems
|
||||
We currently support the following operating systems.
|
||||
- Ubuntu 22.04 Jammy
|
||||
- Ubuntu 20.04 Focal
|
||||
- Ubuntu 18.04 Bionic
|
||||
|
||||
`main` branch is the development branch: do not use this for production. Refer to the [release page](https://github.com/AntelopeIO/leap/releases) for current information on releases, pre-releases, and obsolete releases as well as the corresponding tags for those releases.
|
||||
Other Unix derivatives such as macOS are tended to on a best-effort basis and may not be full featured. If you aren't using Ubuntu, please visit the "[Build Unsupported OS](./docs/00_install/01_build-from-source/00_build-unsupported-os.md)" page to explore your options.
|
||||
|
||||
## Software Installation
|
||||
|
||||
Visit the [release page](https://github.com/AntelopeIO/leap/releases) for Ubuntu binaries. This is the fastest way to get started with the software.
|
||||
|
||||
### Building From Source
|
||||
|
||||
Recent Ubuntu LTS releases are the only Linux distributions that we fully support. Other Linux distros and other POSIX operating systems (such as macOS) are tended to on a best-effort basis and may not be full featured. Notable requirements to build are:
|
||||
* C++17 compiler and standard library
|
||||
* boost 1.67+
|
||||
* CMake 3.8+
|
||||
* (for Linux only) LLVM 7 - 11 (newer versions do not work)
|
||||
|
||||
A few other common libraries are tools also required such as openssl 1.1+, libcurl, curl, libusb, GMP, Python 3, and zlib.
|
||||
|
||||
**A Warning On Parallel Compilation Jobs (`-j` flag)**: When building C/C++ software often the build is performed in parallel via a command such as `make -j $(nproc)` which uses the number of CPU cores as the number of compilation jobs to perform simultaneously. However, be aware that some compilation units (.cpp files) in Leap are extremely complex and will consume nearly 4GB of memory to compile. You may need to reduce the level of parallelization depending on the amount of memory on your build host. e.g. instead of `make -j $(nproc)` run `make -j2`. Failures due to memory exhaustion will typically but not always manifest as compiler crashes.
|
||||
|
||||
Generally we recommend performing what we refer to as a "pinned build" which ensures the compiler and boost version remain the same between builds of different Leap versions (Leap requires these versions remain the same otherwise its state needs to be repopulated from a portable snapshot).
|
||||
|
||||
#### Building Pinned Build Binary Packages
|
||||
In the directory `<leap src>/scripts` you will find the two scripts `install_deps.sh` and `pinned_build.sh`. If you haven't installed build dependencies then run `install_deps.sh`. Then run `pinned_build.sh <dependencies directory> <leap build directory> <number of jobs>`.
|
||||
|
||||
The dependencies directory is where the script will pull the C++ dependencies that need to be built with the pinned compiler for building the pinned binaries for binary packaging.
|
||||
|
||||
The binary package will be produced in the Leap build directory that was supplied.
|
||||
|
||||
#### Manual (non "pinned") Build Instructions
|
||||
|
||||
<details>
|
||||
<summary>Ubuntu 20.04 & 22.04 Build Instructions</summary>
|
||||
|
||||
Install required dependencies:
|
||||
If you are running an unsupported Ubuntu derivative, such as Linux Mint, you can find the version of Ubuntu your distribution was based on by using this command:
|
||||
```bash
|
||||
cat /etc/upstream-release/lsb-release
|
||||
```
|
||||
apt-get update && apt-get install \
|
||||
build-essential \
|
||||
cmake \
|
||||
curl \
|
||||
git \
|
||||
libboost-all-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libgmp-dev \
|
||||
libssl-dev \
|
||||
libusb-1.0-0-dev \
|
||||
llvm-11-dev \
|
||||
Your best bet is to follow the instructions for your Ubuntu base, but we make no guarantees.
|
||||
|
||||
## Binary Installation
|
||||
This is the fastest way to get started. From the [latest release](https://github.com/AntelopeIO/leap/releases/latest) page, download a binary for one of our [supported operating systems](#supported-operating-systems), or visit the [release tags](https://github.com/AntelopeIO/leap/releases) page to download a binary for a specific version of Leap.
|
||||
|
||||
Once you have a `*.deb` file downloaded for your version of Ubuntu, you can install it as follows:
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ~/Downloads/leap*.deb
|
||||
```
|
||||
Your download path may vary. If you are in an Ubuntu docker container, omit `sudo` because you run as `root` by default.
|
||||
|
||||
Finally, verify Leap was installed correctly:
|
||||
```bash
|
||||
nodeos --full-version
|
||||
```
|
||||
You should see a [semantic version](https://semver.org) string followed by a `git` commit hash with no errors. For example:
|
||||
```
|
||||
v3.1.2-0b64f879e3ebe2e4df09d2e62f1fc164cc1125d1
|
||||
```
|
||||
|
||||
## Build and Install from Source
|
||||
You can also build and install Leap from source.
|
||||
|
||||
### Prerequisites
|
||||
You will need to build on a [supported operating system](#supported-operating-systems).
|
||||
|
||||
Requirements to build:
|
||||
- C++17 compiler and standard library
|
||||
- boost 1.67+
|
||||
- CMake 3.8+
|
||||
- LLVM 7 - 11 - for Linux only
|
||||
- newer versions do not work
|
||||
- openssl 1.1+
|
||||
- libcurl
|
||||
- curl
|
||||
- libusb
|
||||
- git
|
||||
- GMP
|
||||
- Python 3
|
||||
- zlib
|
||||
|
||||
### Step 1 - Clone
|
||||
If you don't have the Leap repo cloned to your computer yet, [open a terminal](https://itsfoss.com/open-terminal-ubuntu) and navigate to the folder where you want to clone the Leap repository:
|
||||
```bash
|
||||
cd ~/Downloads
|
||||
```
|
||||
Clone Leap using either HTTPS...
|
||||
```bash
|
||||
git clone --recursive https://github.com/AntelopeIO/leap.git
|
||||
```
|
||||
...or SSH:
|
||||
```bash
|
||||
git clone --recursive git@github.com:AntelopeIO/leap.git
|
||||
```
|
||||
|
||||
> ℹ️ **HTTPS vs. SSH Clone** ℹ️
|
||||
Both an HTTPS or SSH git clone will yield the same result - a folder named `leap` containing our source code. It doesn't matter which type you use.
|
||||
|
||||
Navigate into that folder:
|
||||
```bash
|
||||
cd leap
|
||||
```
|
||||
|
||||
### Step 2 - Checkout Release Tag or Branch
|
||||
Choose which [release](https://github.com/AntelopeIO/leap/releases) or [branch](#branches) you would like to build, then check it out. If you are not sure, use the [latest release](https://github.com/AntelopeIO/leap/releases/latest). For example, if you want to build release 3.1.2 then you would check it out using its tag, `v3.1.2`. In the example below, replace `v0.0.0` with your selected release tag accordingly:
|
||||
```bash
|
||||
git fetch --all --tags
|
||||
git checkout v0.0.0
|
||||
```
|
||||
|
||||
Once you are on the branch or release tag you want to build, make sure everything is up-to-date:
|
||||
```bash
|
||||
git pull
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
### Step 3 - Build
|
||||
Select build instructions below for a [pinned build](#pinned-build) (preferred) or an [unpinned build](#unpinned-build).
|
||||
|
||||
> ℹ️ **Pinned vs. Unpinned Build** ℹ️
|
||||
We have two types of builds for Leap: "pinned" and "unpinned." The only difference is that pinned builds use specific versions for some dependencies hand-picked by the Leap engineers - they are "pinned" to those versions. In contrast, unpinned builds use the default dependency versions available on the build system at the time. We recommend performing a "pinned" build to ensure the compiler and boost versions remain the same between builds of different Leap versions. Leap requires these versions to remain the same, otherwise its state might need to be recovered from a portable snapshot or the chain needs to be replayed.
|
||||
|
||||
> ⚠️ **A Warning On Parallel Compilation Jobs (`-j` flag)** ⚠️
|
||||
When building C/C++ software, often the build is performed in parallel via a command such as `make -j "$(nproc)"` which uses all available CPU threads. However, be aware that some compilation units (`*.cpp` files) in Leap will consume nearly 4GB of memory. Failures due to memory exhaustion will typically, but not always, manifest as compiler crashes. Using all available CPU threads may also prevent you from doing other things on your computer during compilation. For these reasons, consider reducing this value.
|
||||
|
||||
> 🐋 **Docker and `sudo`** 🐋
|
||||
If you are in an Ubuntu docker container, omit `sudo` from all commands because you run as `root` by default. Most other docker containers also exclude `sudo`, especially Debian-family containers. If your shell prompt is a hash tag (`#`), omit `sudo`.
|
||||
|
||||
#### Pinned Build
|
||||
Make sure you are in the root of the `leap` repo, then run the `install_depts.sh` script to install dependencies:
|
||||
```bash
|
||||
sudo scripts/install_deps.sh
|
||||
```
|
||||
|
||||
Next, run the pinned build script. You have to give it three arguments, in the following order:
|
||||
- A temporary folder, for all dependencies that need to be built from source.
|
||||
- A build folder, where the binaries you need to install will be built to.
|
||||
- The number of jobs or CPU cores/threads to use (note the [jobs flag](#step-3---build) warning above).
|
||||
|
||||
The following command runs the `pinned_build.sh` script, specifies a `deps` and `build` folder in the root of the Leap repo for the first two arguments, then builds the packages using all of your computer's CPU threads (Note: you don't need `sudo` for this command):
|
||||
```bash
|
||||
scripts/pinned_build.sh deps build "$(nproc)"
|
||||
```
|
||||
Now you can optionally [test](#step-4---test) your build, or [install](#step-5---install) the `*.deb` binary packages, which will be in the root of your build directory.
|
||||
|
||||
#### Unpinned Build
|
||||
The following instructions are valid for this branch. Other release branches may have different requirements, so ensure you follow the directions in the branch or release you intend to build. If you are in an Ubuntu docker container, omit `sudo` because you run as `root` by default.
|
||||
|
||||
<details> <summary>Ubuntu 22.04 Jammy & Ubuntu 20.04 Focal</summary>
|
||||
|
||||
Install dependencies:
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
curl \
|
||||
git \
|
||||
libboost-all-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libgmp-dev \
|
||||
libssl-dev \
|
||||
libusb-1.0-0-dev \
|
||||
llvm-11-dev \
|
||||
pkg-config
|
||||
```
|
||||
and perform the build:
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
mkdir build
|
||||
To build, make sure you are in the root of the `leap` repo, then run the following command:
|
||||
```bash
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=/usr/lib/llvm-11 ..
|
||||
make -j $(nproc) package
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Ubuntu 18.04 Build Instructions</summary>
|
||||
<details> <summary>Ubuntu 18.04 Bionic</summary>
|
||||
|
||||
Install required dependencies. You will need to build Boost from source on this distribution.
|
||||
```
|
||||
apt-get update && apt-get install \
|
||||
build-essential \
|
||||
cmake \
|
||||
curl \
|
||||
g++-8 \
|
||||
git \
|
||||
libcurl4-openssl-dev \
|
||||
libgmp-dev \
|
||||
libssl-dev \
|
||||
libusb-1.0-0-dev \
|
||||
llvm-7-dev \
|
||||
pkg-config \
|
||||
python3 \
|
||||
Install dependencies:
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
curl \
|
||||
g++-8 \
|
||||
git \
|
||||
libcurl4-openssl-dev \
|
||||
libgmp-dev \
|
||||
libssl-dev \
|
||||
libusb-1.0-0-dev \
|
||||
llvm-7-dev \
|
||||
pkg-config \
|
||||
python3 \
|
||||
zlib1g-dev
|
||||
|
||||
curl -L https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.bz2 | tar jx && \
|
||||
cd boost_1_79_0 && \
|
||||
./bootstrap.sh --prefix=$HOME/boost1.79 && \
|
||||
./b2 --with-iostreams --with-date_time --with-filesystem --with-system \
|
||||
--with-program_options --with-chrono --with-test -j$(nproc) install && \
|
||||
cd ..
|
||||
```
|
||||
and perform the build:
|
||||
You need to build Boost from source on this distribution:
|
||||
```bash
|
||||
curl -fL https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.bz2 -o ~/Downloads/boost_1_79_0.tar.bz2
|
||||
tar -jvxf ~/Downloads/boost_1_79_0.tar.bz2 -C ~/Downloads/
|
||||
pushd ~/Downloads/boost_1_79_0
|
||||
./bootstrap.sh --prefix="$HOME/boost1.79"
|
||||
./b2 --with-iostreams --with-date_time --with-filesystem --with-system --with-program_options --with-chrono --with-test -j "$(nproc)" install
|
||||
popd
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
mkdir build
|
||||
The Boost `*.tar.bz2` download and `boost_1_79_0` folder can be removed now if you want more space.
|
||||
```bash
|
||||
rm -r ~/Downloads/boost_1_79_0.tar.bz2 ~/Downloads/boost_1_79_0
|
||||
```
|
||||
From a terminal in the root of the `leap` repo, build.
|
||||
```bash
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 \
|
||||
-DCMAKE_PREFIX_PATH="$HOME/boost1.79;/usr/lib/llvm-7/" -DCMAKE_BUILD_TYPE=Release .. \
|
||||
make -j $(nproc) package
|
||||
cmake -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 -DCMAKE_PREFIX_PATH="$HOME/boost1.79;/usr/lib/llvm-7/" -DCMAKE_BUILD_TYPE=Release ..
|
||||
make -j "$(nproc)" package
|
||||
```
|
||||
After building you may remove the `$HOME/boost1.79` directory, or you may keep it around until next time building the software.
|
||||
After building, you may remove the `~/boost1.79` directory or you may keep it around for your next build.
|
||||
</details>
|
||||
|
||||
### Running Tests
|
||||
Now you can optionally [test](#step-4---test) your build, or [install](#step-5---install) the `*.deb` binary packages, which will be in the root of your build directory.
|
||||
|
||||
When building from source it's recommended to run at least what we refer to as the "parallelizable tests". Not included by default in the "parallelizable tests" are the WASM spec tests which can add additional coverage and can also be run in parallel.
|
||||
### Step 4 - Test
|
||||
Leap supports the following test suites:
|
||||
|
||||
```
|
||||
cd build
|
||||
Test Suite | Test Type | [Test Size](https://testing.googleblog.com/2010/12/test-sizes.html) | Notes
|
||||
---|:---:|:---:|---
|
||||
[Parallelizable tests](#parallelizable-tests) | Unit tests | Small
|
||||
[WASM spec tests](#wasm-spec-tests) | Unit tests | Small | Unit tests for our WASM runtime, each short but _very_ CPU-intensive
|
||||
[Serial tests](#serial-tests) | Component/Integration | Medium
|
||||
[Long-running tests](#long-running-tests) | Integration | Medium-to-Large | Tests which take an extraordinarily long amount of time to run
|
||||
|
||||
# "parallelizable tests": the minimum test set that should be run
|
||||
ctest -j $(nproc) -LE _tests
|
||||
When building from source, we recommended running at least the [parallelizable tests](#parallelizable-tests).
|
||||
|
||||
# Also consider running the WASM spec tests for more coverage
|
||||
ctest -j $(nproc) -L wasm_spec_tests
|
||||
#### Parallelizable Tests
|
||||
This test suite consists of any test that does not require shared resources, such as file descriptors, specific folders, or ports, and can therefore be run concurrently in different threads without side effects (hence, easily parallelized). These are mostly unit tests and [small tests](https://testing.googleblog.com/2010/12/test-sizes.html) which complete in a short amount of time.
|
||||
|
||||
You can invoke them by running `ctest` from a terminal in your Leap build directory and specifying the following arguments:
|
||||
```bash
|
||||
ctest -j "$(nproc)" -LE _tests
|
||||
```
|
||||
|
||||
Some other tests are available and recommended but be aware they can be sensitive to other software running on the same host and they may **SIGKILL** other nodeos instances running on the host.
|
||||
```
|
||||
cd build
|
||||
#### WASM Spec Tests
|
||||
The WASM spec tests verify that our WASM execution engine is compliant with the web assembly standard. These are very [small](https://testing.googleblog.com/2010/12/test-sizes.html), very fast unit tests. However, there are over a thousand of them so the suite can take a little time to run. These tests are extremely CPU-intensive.
|
||||
|
||||
# These tests can't run in parallel but are recommended.
|
||||
You can invoke them by running `ctest` from a terminal in your Leap build directory and specifying the following arguments:
|
||||
```bash
|
||||
ctest -j "$(nproc)" -L wasm_spec_tests
|
||||
```
|
||||
We have observed severe performance issues when multiple virtual machines are running this test suite on the same physical host at the same time, for example in a CICD system. This can be resolved by disabling hyperthreading on the host.
|
||||
|
||||
#### Serial Tests
|
||||
The serial test suite consists of [medium](https://testing.googleblog.com/2010/12/test-sizes.html) component or integration tests that use specific paths, ports, rely on process names, or similar, and cannot be run concurrently with other tests. Serial tests can be sensitive to other software running on the same host and they may `SIGKILL` other `nodeos` processes. These tests take a moderate amount of time to complete, but we recommend running them.
|
||||
|
||||
You can invoke them by running `ctest` from a terminal in your Leap build directory and specifying the following arguments:
|
||||
```bash
|
||||
ctest -L "nonparallelizable_tests"
|
||||
```
|
||||
|
||||
# These tests can't run in parallel. They also take a long time to run.
|
||||
#### Long-Running Tests
|
||||
The long-running tests are [medium-to-large](https://testing.googleblog.com/2010/12/test-sizes.html) integration tests that rely on shared resources and take a very long time to run.
|
||||
|
||||
You can invoke them by running `ctest` from a terminal in your Leap build directory and specifying the following arguments:
|
||||
```bash
|
||||
ctest -L "long_running_tests"
|
||||
```
|
||||
|
||||
### Step 5 - Install
|
||||
Once you have [built](#step-3---build-the-source-code) Leap and [tested](#step-4---test) your build, you can install Leap on your system. Don't forget to omit `sudo` if you are running in a docker container.
|
||||
|
||||
We recommend installing the binary package you just built. Navigate to your Leap build directory in a terminal and run this command:
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ./leap[-_][0-9]*.deb
|
||||
```
|
||||
|
||||
It is also possible to install using `make` instead:
|
||||
```bash
|
||||
sudo make install
|
||||
```
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
{
|
||||
"name": "eos",
|
||||
"generators": [
|
||||
{
|
||||
"name": "collate_markdown",
|
||||
"options": {
|
||||
"docs_dir": "docs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "swagger",
|
||||
"options": {
|
||||
"swagger_path": "plugins/chain_api_plugin/chain.swagger.yaml",
|
||||
"swagger_dest_path": "nodeos/plugins/chain_api_plugin/api-reference",
|
||||
"disable_filters": true,
|
||||
"disable_summary_gen": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "swagger",
|
||||
"options": {
|
||||
"swagger_path": "plugins/db_size_api_plugin/db_size.swagger.yaml",
|
||||
"swagger_dest_path": "nodeos/plugins/db_size_api_plugin/api-reference",
|
||||
"disable_filters": true,
|
||||
"disable_summary_gen": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "swagger",
|
||||
"options": {
|
||||
"swagger_path": "plugins/producer_api_plugin/producer.swagger.yaml",
|
||||
"swagger_dest_path": "nodeos/plugins/producer_api_plugin/api-reference",
|
||||
"disable_filters": true,
|
||||
"disable_summary_gen": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "swagger",
|
||||
"options": {
|
||||
"swagger_path": "plugins/net_api_plugin/net.swagger.yaml",
|
||||
"swagger_dest_path": "nodeos/plugins/net_api_plugin/api-reference",
|
||||
"disable_filters": true,
|
||||
"disable_summary_gen": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "swagger",
|
||||
"options": {
|
||||
"swagger_path": "plugins/test_control_api_plugin/test_control.swagger.yaml",
|
||||
"swagger_dest_path": "nodeos/plugins/test_control_api_plugin/api-reference",
|
||||
"disable_filters": true,
|
||||
"disable_summary_gen": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "swagger",
|
||||
"options": {
|
||||
"swagger_path": "plugins/trace_api_plugin/trace_api.swagger.yaml",
|
||||
"swagger_dest_path": "nodeos/plugins/trace_api_plugin/api-reference",
|
||||
"disable_filters": true,
|
||||
"disable_summary_gen": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,123 +2,19 @@
|
||||
content_title: Build Antelope from Source
|
||||
---
|
||||
|
||||
The shell scripts previously recommended for building the software have been removed in favor of a build process entirely driven by CMake. Those wishing to build from source are now responsible for installing the necessary dependencies. The list of dependencies and the recommended build procedure are in the README.md file. Instructions are also included for efficiently running the tests.
|
||||
The shell scripts previously recommended for building the software have been removed in favor of a build process entirely driven by CMake. Those wishing to build from source are now responsible for installing the necessary dependencies. The list of dependencies and the recommended build procedure are in the [`README.md`](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md) file. Instructions are also included for efficiently running the tests.
|
||||
|
||||
### Using DUNE
|
||||
|
||||
As an alternative to building from source try [Docker Utilities for Node Execution](https://github.com/AntelopeIO/DUNE) for the easiest way to get started, and for multi-platform support.
|
||||
As an alternative to building from source, try [Docker Utilities for Node Execution](https://github.com/AntelopeIO/DUNE) for the easiest way to get started and for multi-platform support.
|
||||
|
||||
### Building From Source
|
||||
|
||||
Recent Ubuntu LTS releases are the only Linux distributions that we fully support. Other Linux distros and other POSIX operating systems (such as macOS) are tended to on a best-effort basis and may not be full featured. Notable requirements to build are:
|
||||
* C++17 compiler and standard library
|
||||
* boost 1.67+
|
||||
* CMake 3.8+
|
||||
* (for Linux only) LLVM 7 - 11 (newer versions do not work)
|
||||
|
||||
A few other common libraries are tools also required such as openssl 1.1+, libcurl, curl, libusb, GMP, Python 3, and zlib.
|
||||
|
||||
**A Warning On Parallel Compilation Jobs (`-j` flag)**: When building C/C++ software often the build is performed in parallel via a command such as `make -j $(nproc)` which uses the number of CPU cores as the number of compilation jobs to perform simultaneously. However, be aware that some compilation units (.cpp files) in mandel are extremely complex and will consume nearly 4GB of memory to compile. You may need to reduce the level of parallelization depending on the amount of memory on your build host. e.g. instead of `make -j $(nproc)` run `make -j2`. Failures due to memory exhaustion will typically but not always manifest as compiler crashes.
|
||||
|
||||
Generally we recommend performing what we refer to as a "pinned build" which ensures the compiler and boost version remain the same between builds of different mandel versions (mandel requires these versions remain the same otherwise its state needs to be repopulated from a portable snapshot).
|
||||
You can also build and install Leap from source. Instructions for that currently live [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#build-and-install-from-source).
|
||||
|
||||
#### Building Pinned Build Binary Packages
|
||||
In the directory `<mandel src>/scripts` you will find the two scripts `install_deps.sh` and `pinned_build.sh`. If you haven't installed build dependencies then run `install_deps.sh`. Then run `pinned_build.sh <dependencies directory> <mandel build directory> <number of jobs>`.
|
||||
|
||||
The dependencies directory is where the script will pull the C++ dependencies that need to be built with the pinned compiler for building the pinned binaries for binary packaging.
|
||||
|
||||
The binary package will be produced in the mandel build directory that was supplied.
|
||||
The pinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#pinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#step-3---build) before you build.
|
||||
|
||||
#### Manual (non "pinned") Build Instructions
|
||||
|
||||
<details>
|
||||
<summary>Ubuntu 20.04 & 22.04 Build Instructions</summary>
|
||||
|
||||
Install required dependencies:
|
||||
```
|
||||
apt-get update && apt-get install \
|
||||
build-essential \
|
||||
cmake \
|
||||
curl \
|
||||
git \
|
||||
libboost-all-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libgmp-dev \
|
||||
libssl-dev \
|
||||
libusb-1.0-0-dev \
|
||||
llvm-11-dev \
|
||||
pkg-config
|
||||
```
|
||||
and perform the build:
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
make -j $(nproc) package
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Ubuntu 18.04 Build Instructions</summary>
|
||||
|
||||
Install required dependencies. You will need to build Boost from source on this distribution.
|
||||
```
|
||||
apt-get update && apt-get install \
|
||||
build-essential \
|
||||
cmake \
|
||||
curl \
|
||||
g++-8 \
|
||||
git \
|
||||
libcurl4-openssl-dev \
|
||||
libgmp-dev \
|
||||
libssl-dev \
|
||||
libusb-1.0-0-dev \
|
||||
llvm-7-dev \
|
||||
pkg-config \
|
||||
python3 \
|
||||
zlib1g-dev
|
||||
|
||||
curl -L https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.bz2 | tar jx && \
|
||||
cd boost_1_79_0 && \
|
||||
./bootstrap.sh --prefix=$HOME/boost1.79 && \
|
||||
./b2 --with-iostreams --with-date_time --with-filesystem --with-system \
|
||||
--with-program_options --with-chrono --with-test -j$(nproc) install && \
|
||||
cd ..
|
||||
```
|
||||
and perform the build:
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 \
|
||||
-DCMAKE_PREFIX_PATH="$HOME/boost1.79;/usr/lib/llvm-7/" -DCMAKE_BUILD_TYPE=Release .. \
|
||||
make -j $(nproc) package
|
||||
```
|
||||
After building you may remove the `$HOME/boost1.79` directory, or you may keep it around until next time building the software.
|
||||
</details>
|
||||
The unpinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#unpinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#step-3---build) before you build.
|
||||
|
||||
### Running Tests
|
||||
|
||||
When building from source it's recommended to run at least what we refer to as the "parallelizable tests". Not included by default in the "parallelizable tests" are the WASM spec tests which can add additional coverage and can also be run in parallel.
|
||||
|
||||
```
|
||||
cd build
|
||||
|
||||
# "parallelizable tests": the minimum test set that should be run
|
||||
ctest -j $(nproc) -LE _tests
|
||||
|
||||
# Also consider running the WASM spec tests for more coverage
|
||||
ctest -j $(nproc) -L wasm_spec_tests
|
||||
```
|
||||
|
||||
Some other tests are available and recommended but be aware they can be sensitive to other software running on the same host and they may **SIGKILL** other nodeos instances running on the host.
|
||||
```
|
||||
cd build
|
||||
|
||||
# These tests can't run in parallel but are recommended.
|
||||
ctest -L "nonparallelizable_tests"
|
||||
|
||||
# These tests can't run in parallel. They also take a long time to run.
|
||||
ctest -L "long_running_tests"
|
||||
```
|
||||
Documentation on available test suites and how to run them has moved [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#test).
|
||||
|
||||
@@ -10,9 +10,9 @@ The best way to install and use the Antelope software is to build it from source
|
||||
|
||||
Antelope currently supports the following operating systems:
|
||||
|
||||
1. Ubuntu 18.04
|
||||
2. Ubuntu 20.04
|
||||
3. Ubuntu 22.04
|
||||
1. Ubuntu 22.04 Jammy
|
||||
2. Ubuntu 20.04 Focal
|
||||
3. Ubuntu 18.04 Bionic
|
||||
|
||||
[[info | Note]]
|
||||
| It may be possible to build and install Antelope on other Unix-based operating systems. We gathered helpful information on the following page but please keep in mind that it is experimental and not officially supported.
|
||||
|
||||
+7
-7
@@ -4,8 +4,8 @@
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = "EOS.IO"
|
||||
PROJECT_NUMBER = "EOSIO ${DOXY_EOS_VERSION}"
|
||||
PROJECT_NAME = "LEAP"
|
||||
PROJECT_NUMBER = "${DOXY_EOS_VERSION}"
|
||||
PROJECT_BRIEF =
|
||||
PROJECT_LOGO = eos-logo.png
|
||||
OUTPUT_DIRECTORY =
|
||||
@@ -209,9 +209,9 @@ HTML_DYNAMIC_SECTIONS = NO
|
||||
HTML_INDEX_NUM_ENTRIES = 100
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = io.eos
|
||||
DOCSET_PUBLISHER_ID = one.block
|
||||
DOCSET_PUBLISHER_NAME = block.one
|
||||
DOCSET_BUNDLE_ID = io.antelope
|
||||
DOCSET_PUBLISHER_ID = com.eosnetwork
|
||||
DOCSET_PUBLISHER_NAME = eosnetwork.com
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
@@ -221,14 +221,14 @@ BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
GENERATE_QHP = NO
|
||||
QCH_FILE =
|
||||
QHP_NAMESPACE = io.eos
|
||||
QHP_NAMESPACE = io.antelope
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
QHP_CUST_FILTER_NAME =
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
QHG_LOCATION =
|
||||
GENERATE_ECLIPSEHELP = NO
|
||||
ECLIPSE_DOC_ID = io.eos
|
||||
ECLIPSE_DOC_ID = io.antelope
|
||||
DISABLE_INDEX = NO
|
||||
GENERATE_TREEVIEW = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
|
||||
@@ -157,6 +157,7 @@ struct pending_state {
|
||||
block_stage_type _block_stage;
|
||||
controller::block_status _block_status = controller::block_status::incomplete;
|
||||
std::optional<block_id_type> _producer_block_id;
|
||||
controller::block_report _block_report{};
|
||||
|
||||
/** @pre _block_stage cannot hold completed_block alternative */
|
||||
const pending_block_header_state& get_pending_block_header_state()const {
|
||||
@@ -229,7 +230,7 @@ struct controller_impl {
|
||||
protocol_feature_manager protocol_features;
|
||||
controller::config conf;
|
||||
const chain_id_type chain_id; // read by thread_pool threads, value will not be changed
|
||||
std::optional<fc::time_point> replay_head_time;
|
||||
bool replaying = false;
|
||||
db_read_mode read_mode = db_read_mode::SPECULATIVE;
|
||||
bool in_trx_requiring_checks = false; ///< if true, checks that are normally skipped on replay (e.g. auth checks) cannot be skipped
|
||||
std::optional<fc::microseconds> subjective_cpu_leeway;
|
||||
@@ -482,8 +483,7 @@ struct controller_impl {
|
||||
}
|
||||
|
||||
auto blog_head = blog.head();
|
||||
auto blog_head_time = blog_head ? blog_head->timestamp.to_time_point() : fork_db.root()->header.timestamp.to_time_point();
|
||||
replay_head_time = blog_head_time;
|
||||
replaying = true;
|
||||
auto start_block_num = head->block_num + 1;
|
||||
auto start = fc::time_point::now();
|
||||
|
||||
@@ -551,7 +551,7 @@ struct controller_impl {
|
||||
ilog( "replayed ${n} blocks in ${duration} seconds, ${mspb} ms/block",
|
||||
("n", head->block_num + 1 - start_block_num)("duration", (end-start).count()/1000000)
|
||||
("mspb", ((end-start).count()/1000.0)/(head->block_num-start_block_num)) );
|
||||
replay_head_time.reset();
|
||||
replaying = false;
|
||||
|
||||
if( except_ptr ) {
|
||||
std::rethrow_exception( except_ptr );
|
||||
@@ -820,7 +820,10 @@ struct controller_impl {
|
||||
});
|
||||
}
|
||||
|
||||
void add_to_snapshot( const snapshot_writer_ptr& snapshot ) const {
|
||||
void add_to_snapshot( const snapshot_writer_ptr& snapshot ) {
|
||||
// clear in case the previous call to clear did not finish in time of deadline
|
||||
clear_expired_input_transactions( fc::time_point::maximum() );
|
||||
|
||||
snapshot->write_section<chain_snapshot_header>([this]( auto §ion ){
|
||||
section.add_row(chain_snapshot_header(), db);
|
||||
});
|
||||
@@ -993,7 +996,7 @@ struct controller_impl {
|
||||
);
|
||||
}
|
||||
|
||||
sha256 calculate_integrity_hash() const {
|
||||
sha256 calculate_integrity_hash() {
|
||||
sha256::encoder enc;
|
||||
auto hash_writer = std::make_shared<integrity_hash_snapshot_writer>(enc);
|
||||
add_to_snapshot(hash_writer);
|
||||
@@ -1252,6 +1255,7 @@ struct controller_impl {
|
||||
uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time = false )
|
||||
{ try {
|
||||
|
||||
auto start = fc::time_point::now();
|
||||
const bool validating = !self.is_producing_block();
|
||||
EOS_ASSERT( !validating || explicit_billed_cpu_time, transaction_exception, "validating requires explicit billing" );
|
||||
|
||||
@@ -1291,6 +1295,10 @@ struct controller_impl {
|
||||
trace->scheduled = true;
|
||||
trace->receipt = push_receipt( gtrx.trx_id, transaction_receipt::expired, billed_cpu_time_us, 0 ); // expire the transaction
|
||||
trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
pending->_block_report.total_cpu_usage_us += billed_cpu_time_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += trace->elapsed;
|
||||
emit( self.accepted_transaction, trx );
|
||||
dmlog_applied_transaction(trace);
|
||||
emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
|
||||
@@ -1321,7 +1329,7 @@ struct controller_impl {
|
||||
trace->error_code = controller::convert_exception_to_error_code( e );
|
||||
trace->except = e;
|
||||
trace->except_ptr = std::current_exception();
|
||||
trace->elapsed = fc::time_point::now() - trx_context.start;
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_fail_deferred();
|
||||
@@ -1365,6 +1373,11 @@ struct controller_impl {
|
||||
|
||||
restore.cancel();
|
||||
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += fc::time_point::now() - start;
|
||||
|
||||
return trace;
|
||||
} catch( const disallowed_transaction_extensions_bad_block_exception& ) {
|
||||
throw;
|
||||
@@ -1395,13 +1408,18 @@ struct controller_impl {
|
||||
trace = error_trace;
|
||||
if( !trace->except_ptr ) {
|
||||
trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
emit( self.accepted_transaction, trx );
|
||||
dmlog_applied_transaction(trace);
|
||||
emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
|
||||
undo_session.squash();
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
if( trace->receipt ) pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += trace->elapsed;
|
||||
return trace;
|
||||
}
|
||||
trace->elapsed = fc::time_point::now() - trx_context.start;
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
}
|
||||
|
||||
// Only subjective OR hard failure logic below:
|
||||
@@ -1448,6 +1466,11 @@ struct controller_impl {
|
||||
emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
|
||||
}
|
||||
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
if( trace->receipt ) pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += fc::time_point::now() - start;
|
||||
|
||||
return trace;
|
||||
} FC_CAPTURE_AND_RETHROW() } /// push_scheduled_transaction
|
||||
|
||||
@@ -1528,10 +1551,8 @@ struct controller_impl {
|
||||
trx_context.init_for_implicit_trx();
|
||||
trx_context.enforce_whiteblacklist = false;
|
||||
} else {
|
||||
bool skip_recording = replay_head_time && (time_point(trn.expiration) < *replay_head_time);
|
||||
trx_context.init_for_input_trx( trx->packed_trx()->get_unprunable_size(),
|
||||
trx->packed_trx()->get_prunable_size(),
|
||||
skip_recording);
|
||||
trx->packed_trx()->get_prunable_size() );
|
||||
}
|
||||
|
||||
trx_context.delay = fc::seconds(trn.delay_sec);
|
||||
@@ -1590,6 +1611,13 @@ struct controller_impl {
|
||||
trx_context.squash();
|
||||
}
|
||||
|
||||
if( !trx->read_only ) {
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += fc::time_point::now() - start;
|
||||
}
|
||||
|
||||
return trace;
|
||||
} catch( const disallowed_transaction_extensions_bad_block_exception& ) {
|
||||
throw;
|
||||
@@ -1607,9 +1635,14 @@ struct controller_impl {
|
||||
}
|
||||
|
||||
if (!trx->read_only) {
|
||||
emit(self.accepted_transaction, trx);
|
||||
dmlog_applied_transaction(trace);
|
||||
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
|
||||
emit(self.accepted_transaction, trx);
|
||||
dmlog_applied_transaction(trace);
|
||||
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
|
||||
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
if( trace->receipt ) pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += fc::time_point::now() - start;
|
||||
}
|
||||
|
||||
return trace;
|
||||
@@ -1729,7 +1762,7 @@ struct controller_impl {
|
||||
)
|
||||
{
|
||||
// Promote proposed schedule to pending schedule.
|
||||
if( !replay_head_time ) {
|
||||
if( !replaying ) {
|
||||
ilog( "promoting proposed schedule (set in block ${proposed_num}) to pending; current block: ${n} lib: ${lib} schedule: ${schedule} ",
|
||||
("proposed_num", *gpo.proposed_schedule_block_num)("n", pbhs.block_num)
|
||||
("lib", pbhs.dpos_irreversible_blocknum)
|
||||
@@ -2063,12 +2096,6 @@ struct controller_impl {
|
||||
EOS_ASSERT( r == static_cast<const transaction_receipt_header&>(receipt),
|
||||
block_validate_exception, "receipt does not match, ${lhs} != ${rhs}",
|
||||
("lhs", r)("rhs", static_cast<const transaction_receipt_header&>(receipt)) );
|
||||
|
||||
if( trace ) {
|
||||
br.total_net_usage += trace->net_usage;
|
||||
if( trace->receipt ) br.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
br.total_elapsed_time += trace->elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
finalize_block();
|
||||
@@ -2089,6 +2116,7 @@ struct controller_impl {
|
||||
// create completed_block with the existing block_state as we just verified it is the same as assembled_block
|
||||
pending->_block_stage = completed_block{ bsp };
|
||||
|
||||
br = pending->_block_report; // copy before commit block destroys pending
|
||||
commit_block(false);
|
||||
br.total_time = fc::time_point::now() - start;
|
||||
return;
|
||||
@@ -2394,7 +2422,7 @@ struct controller_impl {
|
||||
//Look for expired transactions in the deduplication list, and remove them.
|
||||
auto& transaction_idx = db.get_mutable_index<transaction_multi_index>();
|
||||
const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
|
||||
auto now = self.pending_block_time();
|
||||
auto now = self.is_building_block() ? self.pending_block_time() : self.head_block_time();
|
||||
const auto total = dedupe_index.size();
|
||||
uint32_t num_removed = 0;
|
||||
while( (!dedupe_index.empty()) && ( now > fc::time_point(dedupe_index.begin()->expiration) ) ) {
|
||||
@@ -2829,7 +2857,7 @@ void controller::start_block( block_timestamp_type when,
|
||||
block_status::incomplete, std::optional<block_id_type>(), deadline );
|
||||
}
|
||||
|
||||
block_state_ptr controller::finalize_block( const signer_callback_type& signer_callback ) {
|
||||
block_state_ptr controller::finalize_block( block_report& br, const signer_callback_type& signer_callback ) {
|
||||
validate_db_available_size();
|
||||
|
||||
my->finalize_block();
|
||||
@@ -2850,6 +2878,8 @@ block_state_ptr controller::finalize_block( const signer_callback_type& signer_c
|
||||
|
||||
my->pending->_block_stage = completed_block{ bsp };
|
||||
|
||||
br = my->pending->_block_report;
|
||||
|
||||
return bsp;
|
||||
}
|
||||
|
||||
@@ -3104,11 +3134,11 @@ block_id_type controller::get_block_id_for_num( uint32_t block_num )const { try
|
||||
return id;
|
||||
} FC_CAPTURE_AND_RETHROW( (block_num) ) }
|
||||
|
||||
sha256 controller::calculate_integrity_hash()const { try {
|
||||
sha256 controller::calculate_integrity_hash() { try {
|
||||
return my->calculate_integrity_hash();
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
|
||||
void controller::write_snapshot( const snapshot_writer_ptr& snapshot ) const {
|
||||
void controller::write_snapshot( const snapshot_writer_ptr& snapshot ) {
|
||||
EOS_ASSERT( !my->pending, block_validate_exception, "cannot take a consistent snapshot with a pending block" );
|
||||
return my->add_to_snapshot(snapshot);
|
||||
}
|
||||
|
||||
@@ -164,18 +164,19 @@ namespace eosio { namespace chain {
|
||||
fc::time_point block_deadline, fc::microseconds max_transaction_time,
|
||||
uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time );
|
||||
|
||||
block_state_ptr finalize_block( const signer_callback_type& signer_callback );
|
||||
void sign_block( const signer_callback_type& signer_callback );
|
||||
void commit_block();
|
||||
|
||||
std::future<block_state_ptr> create_block_state_future( const block_id_type& id, const signed_block_ptr& b );
|
||||
|
||||
struct block_report {
|
||||
size_t total_net_usage = 0;
|
||||
size_t total_cpu_usage_us = 0;
|
||||
fc::microseconds total_elapsed_time{};
|
||||
fc::microseconds total_time{};
|
||||
};
|
||||
|
||||
block_state_ptr finalize_block( block_report& br, const signer_callback_type& signer_callback );
|
||||
void sign_block( const signer_callback_type& signer_callback );
|
||||
void commit_block();
|
||||
|
||||
std::future<block_state_ptr> create_block_state_future( const block_id_type& id, const signed_block_ptr& b );
|
||||
|
||||
/**
|
||||
* @param br returns statistics for block
|
||||
* @param block_state_future provide from call to create_block_state_future
|
||||
@@ -256,8 +257,8 @@ namespace eosio { namespace chain {
|
||||
|
||||
block_id_type get_block_id_for_num( uint32_t block_num )const;
|
||||
|
||||
sha256 calculate_integrity_hash()const;
|
||||
void write_snapshot( const snapshot_writer_ptr& snapshot )const;
|
||||
sha256 calculate_integrity_hash();
|
||||
void write_snapshot( const snapshot_writer_ptr& snapshot );
|
||||
|
||||
bool sender_avoids_whitelist_blacklist_enforcement( account_name sender )const;
|
||||
void check_actor_list( const flat_set<account_name>& actors )const;
|
||||
|
||||
@@ -45,8 +45,7 @@ namespace eosio { namespace chain {
|
||||
void init_for_implicit_trx( uint64_t initial_net_usage = 0 );
|
||||
|
||||
void init_for_input_trx( uint64_t packed_trx_unprunable_size,
|
||||
uint64_t packed_trx_prunable_size,
|
||||
bool skip_recording);
|
||||
uint64_t packed_trx_prunable_size );
|
||||
|
||||
void init_for_deferred_trx( fc::time_point published );
|
||||
|
||||
|
||||
@@ -234,8 +234,7 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
void transaction_context::init_for_input_trx( uint64_t packed_trx_unprunable_size,
|
||||
uint64_t packed_trx_prunable_size,
|
||||
bool skip_recording )
|
||||
uint64_t packed_trx_prunable_size )
|
||||
{
|
||||
const transaction& trx = packed_trx.get_transaction();
|
||||
if( trx.transaction_extensions.size() > 0 ) {
|
||||
@@ -272,8 +271,7 @@ namespace eosio { namespace chain {
|
||||
validate_referenced_accounts( trx, enforce_whiteblacklist && control.is_producing_block() );
|
||||
}
|
||||
init( initial_net_usage);
|
||||
if (!skip_recording)
|
||||
record_transaction( packed_trx.id(), trx.expiration ); /// checks for dupes
|
||||
record_transaction( packed_trx.id(), trx.expiration ); /// checks for dupes
|
||||
}
|
||||
|
||||
void transaction_context::init_for_deferred_trx( fc::time_point p )
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// https://github.com/CLIUtils/CLI11
|
||||
//
|
||||
// This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts
|
||||
// from: 1d3b0a7
|
||||
// from: b19d133
|
||||
//
|
||||
// CLI11 2.2.0 Copyright (c) 2017-2022 University of Cincinnati, developed by Henry
|
||||
// Schreiner under NSF AWARD 1414736. All rights reserved.
|
||||
@@ -34,28 +34,28 @@
|
||||
#pragma once
|
||||
|
||||
// Standard combined includes:
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
#include <tuple>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <set>
|
||||
#include <iomanip>
|
||||
#include <locale>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <locale>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <iomanip>
|
||||
#include <utility>
|
||||
|
||||
|
||||
#define CLI11_VERSION_MAJOR 2
|
||||
@@ -9420,4 +9420,134 @@ inline std::string Formatter::make_option_usage(const Option *opt) const {
|
||||
|
||||
|
||||
|
||||
|
||||
class LeapFormatter : public Formatter {
|
||||
// pseudographics - to draw subcommand tree
|
||||
const char* tree_line = u8"\u2502";
|
||||
const char* tree_angle = u8"\u2514";
|
||||
const char* tree_fork = u8"\u251C";
|
||||
|
||||
public:
|
||||
LeapFormatter() : Formatter() {
|
||||
// this gives better, more compact display
|
||||
column_width(25);
|
||||
}
|
||||
LeapFormatter(const LeapFormatter&) = default;
|
||||
LeapFormatter(LeapFormatter&&) = default;
|
||||
|
||||
/// This prints out all the subcommands
|
||||
virtual std::string make_subcommands(const App* app, AppFormatMode mode) const {
|
||||
std::stringstream out;
|
||||
|
||||
std::vector<const App*> subcommands = app->get_subcommands({});
|
||||
|
||||
// Make a list in definition order of the groups seen
|
||||
std::vector<std::string> subcmd_groups_seen;
|
||||
for(const App* com: subcommands) {
|
||||
if(com->get_name().empty()) {
|
||||
if(!com->get_group().empty()) {
|
||||
out << make_expanded(com);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
std::string group_key = com->get_group();
|
||||
if(!group_key.empty() &&
|
||||
std::find_if(subcmd_groups_seen.begin(), subcmd_groups_seen.end(), [&group_key](std::string a) {
|
||||
return detail::to_lower(a) == detail::to_lower(group_key);
|
||||
}) == subcmd_groups_seen.end())
|
||||
subcmd_groups_seen.push_back(group_key);
|
||||
}
|
||||
|
||||
// For each group, filter out and print subcommands
|
||||
for(const std::string& group: subcmd_groups_seen) {
|
||||
if(mode != AppFormatMode::SubCompact) {// do not show "Subcommands" header for nested tems in compact mode
|
||||
out << "\n"
|
||||
<< group << ":\n";
|
||||
}
|
||||
std::vector<const App*> subcommands_group = app->get_subcommands([&group](const App* sub_app) {
|
||||
return detail::to_lower(sub_app->get_group()) == detail::to_lower(group);
|
||||
});
|
||||
for(const App* new_com: subcommands_group) {
|
||||
if(new_com->get_name().empty())
|
||||
continue;
|
||||
|
||||
std::string tree_symbol = (subcommands_group.back() == new_com ? tree_angle : tree_fork);
|
||||
std::string line_symbol = (subcommands_group.back() == new_com ? "" : tree_line);
|
||||
std::string subc_symbol = "";
|
||||
|
||||
const App* parent = app->get_parent();
|
||||
if(parent != nullptr) {
|
||||
std::vector<const App*> sc_group = parent->get_subcommands([&group](const App* sub_app) {
|
||||
return detail::to_lower(sub_app->get_group()) == detail::to_lower(group);
|
||||
});
|
||||
if(sc_group.back() != app) {
|
||||
subc_symbol = tree_line;
|
||||
}
|
||||
}
|
||||
|
||||
switch(mode) {
|
||||
case AppFormatMode::All:
|
||||
out << tree_symbol << new_com->help(new_com->get_name(), AppFormatMode::Sub);
|
||||
out << "\n";
|
||||
break;
|
||||
case AppFormatMode::AllCompact:
|
||||
|
||||
out << tree_symbol << new_com->help(new_com->get_name(), AppFormatMode::SubCompact);
|
||||
out << line_symbol;
|
||||
out << "\n";
|
||||
break;
|
||||
case AppFormatMode::Normal:
|
||||
case AppFormatMode::Sub:
|
||||
out << make_subcommand(new_com);
|
||||
break;
|
||||
case AppFormatMode::SubCompact:
|
||||
out << tree_symbol << make_expanded(new_com, mode);
|
||||
break;
|
||||
default:
|
||||
throw HorribleError("Internal error: unknown help type requested");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
/// This prints out a subcommand in help-all
|
||||
virtual std::string make_expanded(const App* sub, AppFormatMode mode = AppFormatMode::Sub) const {
|
||||
std::stringstream out;
|
||||
std::string tmp;
|
||||
std::string subc_symbol = " ";
|
||||
if(mode == AppFormatMode::SubCompact) {
|
||||
detail::format_help(out, sub->get_display_name(true), sub->get_description(), column_width_);
|
||||
out << make_subcommands(sub, mode);
|
||||
} else {
|
||||
out << sub->get_display_name(true) << "\n";
|
||||
out << make_description(sub);
|
||||
if(sub->get_name().empty() && !sub->get_aliases().empty()) {
|
||||
detail::format_aliases(out, sub->get_aliases(), column_width_ + 2);
|
||||
}
|
||||
out << make_positionals(sub);
|
||||
out << make_groups(sub, mode);
|
||||
out << make_subcommands(sub, mode);
|
||||
}
|
||||
|
||||
// Drop blank spaces
|
||||
tmp = detail::find_and_replace(out.str(), "\n\n", "\n");
|
||||
tmp = tmp.substr(0, tmp.size() - 1);// Remove the final '\n'
|
||||
|
||||
//
|
||||
auto group = sub->get_parent()->get_group();
|
||||
std::vector<const App*> sc_group = sub->get_parent()->get_subcommands(
|
||||
[&group](const App* sub_app) { return detail::to_lower(sub_app->get_group()) == detail::to_lower(group); });
|
||||
|
||||
if(sc_group.back() != sub) {
|
||||
subc_symbol = tree_line;
|
||||
}
|
||||
|
||||
// Indent all but the first line (the name)
|
||||
return detail::find_and_replace(tmp, "\n", "\n" + subc_symbol + " ") + "\n";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace CLI
|
||||
|
||||
@@ -29,9 +29,9 @@ target_include_directories(secp256k1
|
||||
target_link_libraries(secp256k1 PRIVATE secp256k1-internal)
|
||||
|
||||
install( TARGETS secp256k1
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} ${INSTALL_COMPONENT_ARGS}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} ${INSTALL_COMPONENT_ARGS}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} ${INSTALL_COMPONENT_ARGS}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} COMPONENT dev EXCLUDE_FROM_ALL
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL
|
||||
)
|
||||
|
||||
add_executable(secp256k1-bench secp256k1/src/bench.c)
|
||||
|
||||
@@ -439,7 +439,7 @@ class state_history_log {
|
||||
index.skip(-sizeof(uint64_t));
|
||||
|
||||
if (!(remaining % 10000))
|
||||
ilog("${remaining} blocks remaining, log pos = ${pos}", ("num_found", remaining)("pos", pos));
|
||||
ilog("${r} blocks remaining, log pos = ${pos}", ("r", remaining)("pos", pos));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -428,7 +428,8 @@ namespace eosio { namespace testing {
|
||||
}
|
||||
});
|
||||
|
||||
control->finalize_block( [&]( digest_type d ) {
|
||||
controller::block_report br;
|
||||
control->finalize_block( br, [&]( digest_type d ) {
|
||||
std::vector<signature_type> result;
|
||||
result.reserve(signing_keys.size());
|
||||
for (const auto& k: signing_keys)
|
||||
|
||||
+2
-2
@@ -61,13 +61,13 @@ set(CPACK_DEBIAN_BASE_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}.deb")
|
||||
string(REGEX REPLACE "^(${CMAKE_PROJECT_NAME})" "\\1-dev" CPACK_DEBIAN_DEV_FILE_NAME "${CPACK_DEBIAN_BASE_FILE_NAME}")
|
||||
|
||||
#deb package tooling will be unable to detect deps for the dev package. llvm is tricky since we don't know what package could have been used; try to figure it out
|
||||
set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "libboost-all-dev;libssl-dev;libgmp-dev")
|
||||
set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "libboost-all-dev, libssl-dev, libgmp-dev")
|
||||
find_program(DPKG_QUERY "dpkg-query")
|
||||
if(DPKG_QUERY AND OS_RELEASE MATCHES "\n?ID=\"?ubuntu" AND LLVM_CMAKE_DIR)
|
||||
execute_process(COMMAND "${DPKG_QUERY}" -S "${LLVM_CMAKE_DIR}" COMMAND cut -d: -f1 RESULT_VARIABLE LLVM_PKG_FIND_RESULT OUTPUT_VARIABLE LLVM_PKG_FIND_OUTPUT)
|
||||
if(LLVM_PKG_FIND_OUTPUT)
|
||||
string(STRIP "${LLVM_PKG_FIND_OUTPUT}" LLVM_PKG_FIND_OUTPUT)
|
||||
list(APPEND CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "${LLVM_PKG_FIND_OUTPUT}")
|
||||
string(APPEND CPACK_DEBIAN_DEV_PACKAGE_DEPENDS ", ${LLVM_PKG_FIND_OUTPUT}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Chain API
|
||||
description: "OAS 3.0 Nodeos Chain API Specification\r"
|
||||
description: Nodeos Chain API Specification. See developer documentation at https://docs.eosnetwork.com for information on enabling this plugin.
|
||||
version: 1.0.0
|
||||
license:
|
||||
name: MIT
|
||||
url: https://opensource.org/licenses/MIT
|
||||
contact:
|
||||
url: https://eos.io
|
||||
url: https://eosnetwork.com
|
||||
servers:
|
||||
- url: "{protocol}://{host}:{port}/v1/chain"
|
||||
variables:
|
||||
|
||||
@@ -105,7 +105,7 @@ void chain_api_plugin::plugin_startup() {
|
||||
auto rw_api = chain.get_read_write_api(max_response_time);
|
||||
|
||||
auto& _http_plugin = app().get_plugin<http_plugin>();
|
||||
ro_api.set_shorten_abi_errors( !_http_plugin.verbose_errors() );
|
||||
ro_api.set_shorten_abi_errors( !http_plugin::verbose_errors() );
|
||||
|
||||
_http_plugin.add_api( {
|
||||
CHAIN_RO_CALL(get_info, 200, http_params_types::no_params)}, appbase::priority::medium_high);
|
||||
|
||||
@@ -1138,6 +1138,13 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
|
||||
// For the time being, when `deep-mind = true` is activated, we set `stdout` here to
|
||||
// be an unbuffered I/O stream.
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
//verify configuration is correct
|
||||
EOS_ASSERT( options.at("api-accept-transactions").as<bool>() == false, plugin_config_exception,
|
||||
"api-accept-transactions must be set to false in order to enable deep-mind logging.");
|
||||
|
||||
EOS_ASSERT( options.at("p2p-accept-transactions").as<bool>() == false, plugin_config_exception,
|
||||
"p2p-accept-transactions must be set to false in order to enable deep-mind logging.");
|
||||
|
||||
my->chain->enable_deep_mind( &_deep_mind_log );
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: DB Size API
|
||||
description: Nodeos DB Size API Specification. See developer documentation at https://docs.eosnetwork.com for information on enabling this plugin.
|
||||
version: 1.0.0
|
||||
license:
|
||||
name: MIT
|
||||
url: https://opensource.org/licenses/MIT
|
||||
contact:
|
||||
url: https://eos.io
|
||||
url: https://eosnetwork.com
|
||||
servers:
|
||||
- url: '{protocol}://{host}:{port}/v1/'
|
||||
variables:
|
||||
|
||||
@@ -359,6 +359,8 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
|
||||
}
|
||||
}
|
||||
|
||||
my->plugin_state->server_header = current_http_plugin_defaults.server_header;
|
||||
|
||||
|
||||
//watch out for the returns above when adding new code here
|
||||
} FC_LOG_AND_RETHROW()
|
||||
@@ -537,7 +539,7 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
|
||||
return (!my->listen_endpoint || my->listen_endpoint->address().is_loopback());
|
||||
}
|
||||
|
||||
bool http_plugin::verbose_errors()const {
|
||||
bool http_plugin::verbose_errors() {
|
||||
return verbose_http_errors;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <eosio/http_plugin/common.hpp>
|
||||
#include <fc/io/json.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -105,27 +106,16 @@ protected:
|
||||
res_->version(req.version());
|
||||
res_->set(http::field::content_type, "application/json");
|
||||
res_->keep_alive(req.keep_alive());
|
||||
res_->set(http::field::server, BOOST_BEAST_VERSION_STRING);
|
||||
|
||||
// Returns a bad request response
|
||||
auto const bad_request =
|
||||
[](const beast::string_view& why, detail::abstract_conn& conn) {
|
||||
conn.send_response(std::string(why),
|
||||
static_cast<int>(http::status::bad_request));
|
||||
};
|
||||
|
||||
// Returns a not found response
|
||||
auto const not_found =
|
||||
[](const std::string& target, detail::abstract_conn& conn) {
|
||||
conn.send_response("The resource '" + target + "' was not found.",
|
||||
static_cast<int>(http::status::not_found));
|
||||
};
|
||||
if(plugin_state_->server_header.size())
|
||||
res_->set(http::field::server, plugin_state_->server_header);
|
||||
|
||||
// Request path must be absolute and not contain "..".
|
||||
if(req.target().empty() ||
|
||||
req.target()[0] != '/' ||
|
||||
req.target().find("..") != beast::string_view::npos)
|
||||
return bad_request("Illegal request-target", *this);
|
||||
if(req.target().empty() || req.target()[0] != '/' || req.target().find("..") != beast::string_view::npos) {
|
||||
error_results results{static_cast<uint16_t>(http::status::bad_request), "Illegal request-target"};
|
||||
send_response( fc::json::to_string( results, fc::time_point::maximum() ),
|
||||
static_cast<unsigned int>(http::status::bad_request) );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if(!derived().allow_host(req))
|
||||
@@ -146,7 +136,7 @@ protected:
|
||||
|
||||
// Respond to options request
|
||||
if(req.method() == http::verb::options) {
|
||||
send_response("", static_cast<int>(http::status::ok));
|
||||
send_response("{}", static_cast<unsigned int>(http::status::ok));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,7 +144,7 @@ protected:
|
||||
if(!verify_max_bytes_in_flight()) return;
|
||||
|
||||
std::string resource = std::string(req.target());
|
||||
// look for the URL handler to handle this reosouce
|
||||
// look for the URL handler to handle this resource
|
||||
auto handler_itr = plugin_state_->url_handlers.find(resource);
|
||||
if(handler_itr != plugin_state_->url_handlers.end()) {
|
||||
if(plugin_state_->logger.is_enabled(fc::log_level::all))
|
||||
@@ -165,27 +155,29 @@ protected:
|
||||
std::move(body),
|
||||
make_http_response_handler(plugin_state_, derived().shared_from_this()));
|
||||
} else {
|
||||
fc_dlog(plugin_state_->logger, "404 - not found: ${ep}", ("ep", resource));
|
||||
not_found(resource, *this);
|
||||
fc_dlog( plugin_state_->logger, "404 - not found: ${ep}", ("ep", resource) );
|
||||
error_results results{static_cast<uint16_t>(http::status::not_found), "Not Found",
|
||||
error_results::error_info( fc::exception( FC_LOG_MESSAGE( error, "Unknown Endpoint" ) ),
|
||||
http_plugin::verbose_errors() )};
|
||||
send_response( fc::json::to_string( results, fc::time_point::now() + plugin_state_->max_response_time ),
|
||||
static_cast<unsigned int>(http::status::not_found) );
|
||||
}
|
||||
} catch(...) {
|
||||
handle_exception();
|
||||
}
|
||||
}
|
||||
|
||||
void report_429_error(std::string what) {
|
||||
send_response(std::move(what),
|
||||
static_cast<int>(http::status::too_many_requests));
|
||||
}
|
||||
|
||||
public:
|
||||
virtual bool verify_max_bytes_in_flight() override {
|
||||
auto bytes_in_flight_size = plugin_state_->bytes_in_flight.load();
|
||||
if(bytes_in_flight_size > plugin_state_->max_bytes_in_flight) {
|
||||
fc_dlog(plugin_state_->logger, "429 - too many bytes in flight: ${bytes}", ("bytes", bytes_in_flight_size));
|
||||
std::string what = "Too many bytes in flight: " + std::to_string(bytes_in_flight_size) + ". Try again later.";
|
||||
;
|
||||
report_429_error(std::move(what));
|
||||
error_results::error_info ei;
|
||||
ei.code = static_cast<int64_t>(http::status::too_many_requests);
|
||||
ei.name = "Busy";
|
||||
ei.what = "Too many bytes in flight: " + std::to_string( bytes_in_flight_size );
|
||||
error_results results{static_cast<uint16_t>(http::status::too_many_requests), "Busy", ei};
|
||||
send_response( fc::json::to_string( results, fc::time_point::maximum() ), static_cast<unsigned int>(http::status::too_many_requests) );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -198,8 +190,12 @@ public:
|
||||
auto requests_in_flight_num = plugin_state_->requests_in_flight.load();
|
||||
if(requests_in_flight_num > plugin_state_->max_requests_in_flight) {
|
||||
fc_dlog(plugin_state_->logger, "429 - too many requests in flight: ${requests}", ("requests", requests_in_flight_num));
|
||||
std::string what = "Too many requests in flight: " + std::to_string(requests_in_flight_num) + ". Try again later.";
|
||||
report_429_error(std::move(what));
|
||||
error_results::error_info ei;
|
||||
ei.code = static_cast<int64_t>(http::status::too_many_requests);
|
||||
ei.name = "Busy";
|
||||
ei.what = "Too many requests in flight: " + std::to_string( requests_in_flight_num );
|
||||
error_results results{static_cast<uint16_t>(http::status::too_many_requests), "Busy", ei};
|
||||
send_response( fc::json::to_string( results, fc::time_point::maximum() ), static_cast<unsigned int>(http::status::too_many_requests) );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -310,38 +306,57 @@ public:
|
||||
virtual void handle_exception() override {
|
||||
std::string err_str;
|
||||
try {
|
||||
throw;
|
||||
} catch(const fc::exception& e) {
|
||||
err_str = e.to_detail_string();
|
||||
fc_elog(plugin_state_->logger, "fc::exception: ${w}", ("w", err_str));
|
||||
} catch(std::exception& e) {
|
||||
err_str = e.what();
|
||||
fc_elog(plugin_state_->logger, "std::exception: ${w}", ("w", err_str));
|
||||
} catch(...) {
|
||||
err_str = "unknown";
|
||||
fc_elog(plugin_state_->logger, "unkonwn exception");
|
||||
try {
|
||||
throw;
|
||||
} catch(const fc::exception& e) {
|
||||
err_str = e.to_detail_string();
|
||||
fc_elog(plugin_state_->logger, "fc::exception: ${w}", ("w", err_str));
|
||||
error_results results{static_cast<uint16_t>(http::status::internal_server_error),
|
||||
"Internal Service Error",
|
||||
error_results::error_info( e, http_plugin::verbose_errors() )};
|
||||
err_str = fc::json::to_string( results, fc::time_point::now() + plugin_state_->max_response_time );
|
||||
} catch(std::exception& e) {
|
||||
err_str = e.what();
|
||||
fc_elog(plugin_state_->logger, "std::exception: ${w}", ("w", err_str));
|
||||
error_results results{static_cast<uint16_t>(http::status::internal_server_error),
|
||||
"Internal Service Error",
|
||||
error_results::error_info( fc::exception( FC_LOG_MESSAGE( error, err_str )),
|
||||
http_plugin::verbose_errors() )};
|
||||
err_str = fc::json::to_string( results, fc::time_point::now() + plugin_state_->max_response_time );
|
||||
} catch(...) {
|
||||
err_str = "Unknown exception";
|
||||
fc_elog(plugin_state_->logger, err_str);
|
||||
error_results results{static_cast<uint16_t>(http::status::internal_server_error),
|
||||
"Internal Service Error",
|
||||
error_results::error_info(
|
||||
fc::exception( FC_LOG_MESSAGE( error, err_str )),
|
||||
http_plugin::verbose_errors() )};
|
||||
err_str = fc::json::to_string( results, fc::time_point::now() + plugin_state_->max_response_time );
|
||||
}
|
||||
} catch (fc::timeout_exception& e) {
|
||||
fc_elog( plugin_state_->logger, "Timeout exception ${te} attempting to handle exception: ${e}", ("te", e.to_detail_string())("e", err_str) );
|
||||
err_str = R"xxx({"message": "Internal Server Error"})xxx";
|
||||
} catch (...) {
|
||||
fc_elog( plugin_state_->logger, "Exception attempting to handle exception: ${e}", ("e", err_str) );
|
||||
err_str = R"xxx({"message": "Internal Server Error"})xxx";
|
||||
}
|
||||
|
||||
if(is_send_exception_response_) {
|
||||
res_->set(http::field::content_type, "text/plain");
|
||||
res_->keep_alive(false);
|
||||
res_->set(http::field::server, BOOST_BEAST_VERSION_STRING);
|
||||
|
||||
http::status stat = http::status::internal_server_error;
|
||||
auto resp_str = "Internal Server Error\n\nUnhandled Exception: " + err_str;
|
||||
send_response(resp_str, static_cast<int>(stat));
|
||||
if(is_send_exception_response_) {
|
||||
res_->keep_alive(false);
|
||||
|
||||
send_response(std::move(err_str), static_cast<unsigned int>(http::status::internal_server_error));
|
||||
derived().do_eof();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void send_response(std::optional<std::string> body, int code) override {
|
||||
virtual void send_response(std::string json_body, unsigned int code) override {
|
||||
write_begin_ = steady_clock::now();
|
||||
auto dt = write_begin_ - handle_begin_;
|
||||
handle_time_us_ += std::chrono::duration_cast<std::chrono::microseconds>(dt).count();
|
||||
|
||||
res_->result(code);
|
||||
if(body.has_value())
|
||||
res_->body() = *body;
|
||||
res_->body() = std::move(json_body);
|
||||
|
||||
res_->prepare_payload();
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ struct abstract_conn {
|
||||
virtual bool verify_max_requests_in_flight() = 0;
|
||||
virtual void handle_exception() = 0;
|
||||
|
||||
virtual void send_response(std::optional<std::string> body, int code) = 0;
|
||||
virtual void send_response(std::string json_body, unsigned int code) = 0;
|
||||
};
|
||||
|
||||
using abstract_conn_ptr = std::shared_ptr<abstract_conn>;
|
||||
@@ -130,6 +130,8 @@ struct http_plugin_state {
|
||||
bool validate_host = true;
|
||||
set<string> valid_hosts;
|
||||
|
||||
string server_header;
|
||||
|
||||
url_handlers_type url_handlers;
|
||||
bool keep_alive = false;
|
||||
|
||||
@@ -233,7 +235,7 @@ auto make_http_response_handler(std::shared_ptr<http_plugin_state> plugin_state,
|
||||
auto tracked_json = make_in_flight(std::move(json), plugin_state);
|
||||
session_ptr->send_response(std::move(tracked_json->obj()), code);
|
||||
} else {
|
||||
session_ptr->send_response({}, code);
|
||||
session_ptr->send_response("{}", code);
|
||||
}
|
||||
} catch(...) {
|
||||
session_ptr->handle_exception();
|
||||
|
||||
@@ -45,6 +45,8 @@ namespace eosio {
|
||||
//If non 0, HTTP will be enabled by default on the given port number. If
|
||||
// 0, HTTP will not be enabled by default
|
||||
uint16_t default_http_port{0};
|
||||
//If set, a Server header will be added to the HTTP reply with this value
|
||||
string server_header;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -96,7 +98,7 @@ namespace eosio {
|
||||
bool is_on_loopback() const;
|
||||
bool is_secure() const;
|
||||
|
||||
bool verbose_errors()const;
|
||||
static bool verbose_errors();
|
||||
|
||||
struct get_supported_apis_result {
|
||||
vector<string> apis;
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Net API
|
||||
description: Nodeos Net API Specification. See developer documentation at https://docs.eosnetwork.com for information on enabling this plugin.
|
||||
version: 1.0.0
|
||||
license:
|
||||
name: MIT
|
||||
url: https://opensource.org/licenses/MIT
|
||||
contact:
|
||||
url: https://eos.io
|
||||
url: https://eosnetwork.com
|
||||
servers:
|
||||
- url: '{protocol}://{host}:{port}/v1/'
|
||||
variables:
|
||||
|
||||
@@ -634,6 +634,7 @@ namespace eosio {
|
||||
string local_endpoint_port;
|
||||
|
||||
std::atomic<uint32_t> trx_in_progress_size{0};
|
||||
fc::time_point last_dropped_trx_msg_time;
|
||||
const uint32_t connection_id;
|
||||
int16_t sent_handshake_count = 0;
|
||||
std::atomic<bool> connecting{true};
|
||||
@@ -2683,6 +2684,10 @@ namespace eosio {
|
||||
char reason[72];
|
||||
snprintf(reason, 72, "Dropping trx, too many trx in progress %lu bytes", trx_in_progress_sz);
|
||||
my_impl->producer_plug->log_failed_transaction(ptr->id(), ptr, reason);
|
||||
if (fc::time_point::now() - fc::seconds(1) >= last_dropped_trx_msg_time) {
|
||||
last_dropped_trx_msg_time = fc::time_point::now();
|
||||
peer_wlog(this, reason);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool have_trx = my_impl->dispatcher->have_txn( ptr->id() );
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Producer API
|
||||
description: Nodeos Producer API Specification. See developer documentation at https://docs.eosnetwork.com for information on enabling this plugin.
|
||||
version: 1.0.0
|
||||
license:
|
||||
name: MIT
|
||||
|
||||
@@ -494,7 +494,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
|
||||
|
||||
if( now - block->timestamp < fc::minutes(5) || (blk_num % 1000 == 0) ) {
|
||||
ilog("Received block ${id}... #${n} @ ${t} signed by ${p} "
|
||||
"[trxs: ${count}, lib: ${lib}, conf: ${confs}, net: ${net}, cpu: ${cpu}, elapsed: ${elapsed}, time: ${time}, latency: ${latency} ms]",
|
||||
"[trxs: ${count}, lib: ${lib}, confirmed: ${confs}, net: ${net}, cpu: ${cpu}, elapsed: ${elapsed}, time: ${time}, latency: ${latency} ms]",
|
||||
("p",block->producer)("id",id.str().substr(8,16))("n",blk_num)("t",block->timestamp)
|
||||
("count",block->transactions.size())("lib",chain.last_irreversible_block_num())
|
||||
("confs", block->confirmed)("net", br.total_net_usage)("cpu", br.total_cpu_usage_us)
|
||||
@@ -502,7 +502,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
|
||||
("latency", (now - block->timestamp).count()/1000 ) );
|
||||
if( chain.get_read_mode() != db_read_mode::IRREVERSIBLE && hbs->id != id && hbs->block != nullptr ) { // not applied to head
|
||||
ilog("Block not applied to head ${id}... #${n} @ ${t} signed by ${p} "
|
||||
"[trxs: ${count}, dpos: ${dpos}, conf: ${confs}, net: ${net}, cpu: ${cpu}, elapsed: ${elapsed}, time: ${time}, latency: ${latency} ms]",
|
||||
"[trxs: ${count}, dpos: ${dpos}, confirmed: ${confs}, net: ${net}, cpu: ${cpu}, elapsed: ${elapsed}, time: ${time}, latency: ${latency} ms]",
|
||||
("p",hbs->block->producer)("id",hbs->id.str().substr(8,16))("n",hbs->block_num)("t",hbs->block->timestamp)
|
||||
("count",hbs->block->transactions.size())("dpos", hbs->dpos_irreversible_blocknum)
|
||||
("confs", hbs->block->confirmed)("net", br.total_net_usage)("cpu", br.total_cpu_usage_us)
|
||||
@@ -2475,6 +2475,7 @@ static auto maybe_make_debug_time_logger() -> std::optional<decltype(make_debug_
|
||||
|
||||
void producer_plugin_impl::produce_block() {
|
||||
//ilog("produce_block ${t}", ("t", fc::time_point::now())); // for testing _produce_time_offset_us
|
||||
auto start = fc::time_point::now();
|
||||
EOS_ASSERT(_pending_block_mode == pending_block_mode::producing, producer_exception, "called produce_block while not actually producing");
|
||||
chain::controller& chain = chain_plug->chain();
|
||||
EOS_ASSERT(chain.is_building_block(), missing_pending_block_state, "pending_block_state does not exist but it should, another plugin may have corrupted it");
|
||||
@@ -2499,7 +2500,8 @@ void producer_plugin_impl::produce_block() {
|
||||
}
|
||||
|
||||
//idump( (fc::time_point::now() - chain.pending_block_time()) );
|
||||
chain.finalize_block( [&]( const digest_type& d ) {
|
||||
controller::block_report br;
|
||||
chain.finalize_block( br, [&]( const digest_type& d ) {
|
||||
auto debug_logger = maybe_make_debug_time_logger();
|
||||
vector<signature_type> sigs;
|
||||
sigs.reserve(relevant_providers.size());
|
||||
@@ -2518,17 +2520,14 @@ void producer_plugin_impl::produce_block() {
|
||||
_account_fails.report(_idle_trx_time);
|
||||
_account_fails.clear();
|
||||
|
||||
controller::block_report br;
|
||||
for( const auto& r : new_bs->block->transactions ) {
|
||||
br.total_cpu_usage_us += r.cpu_usage_us;
|
||||
br.total_net_usage += r.net_usage_words * 8;
|
||||
}
|
||||
br.total_time += fc::time_point::now() - start;
|
||||
|
||||
ilog("Produced block ${id}... #${n} @ ${t} signed by ${p} "
|
||||
"[trxs: ${count}, lib: ${lib}, confirmed: ${confs}, net: ${net}, cpu: ${cpu}]",
|
||||
"[trxs: ${count}, lib: ${lib}, confirmed: ${confs}, net: ${net}, cpu: ${cpu}, elapsed: ${et}, time: ${tt}]",
|
||||
("p",new_bs->header.producer)("id",new_bs->id.str().substr(8,16))
|
||||
("n",new_bs->block_num)("t",new_bs->header.timestamp)
|
||||
("count",new_bs->block->transactions.size())("lib",chain.last_irreversible_block_num())
|
||||
("net", br.total_net_usage)("cpu", br.total_cpu_usage_us)
|
||||
("net", br.total_net_usage)("cpu", br.total_cpu_usage_us)("et", br.total_elapsed_time)("tt", br.total_time)
|
||||
("confs", new_bs->header.confirmed));
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -59,7 +59,8 @@ namespace eosio::resource_monitor {
|
||||
|
||||
if ( info.available < fs.shutdown_available ) {
|
||||
if (output_threshold_warning) {
|
||||
wlog("Space usage warning: ${path}'s file system exceeded threshold ${threshold}%, available: ${available}, Capacity: ${capacity}, shutdown_available: ${shutdown_available}", ("path", fs.path_name.string()) ("threshold", shutdown_threshold) ("available", info.available) ("capacity", info.capacity) ("shutdown_available", fs.shutdown_available));
|
||||
elog("Space usage warning: ${path}'s file system exceeded threshold ${threshold}%, available: ${available}, Capacity: ${capacity}, shutdown_available: ${shutdown_available}",
|
||||
("path", fs.path_name.string())("threshold", shutdown_threshold)("available", info.available)("capacity", info.capacity)("shutdown_available", fs.shutdown_available));
|
||||
}
|
||||
return true;
|
||||
} else if ( info.available < fs.warning_available && output_threshold_warning ) {
|
||||
@@ -114,7 +115,7 @@ namespace eosio::resource_monitor {
|
||||
|
||||
void space_monitor_loop() {
|
||||
if ( is_threshold_exceeded() && shutdown_on_exceeded ) {
|
||||
wlog("Shutting down");
|
||||
elog("Shutting down, file system exceeded threshold");
|
||||
appbase::app().quit(); // This will gracefully stop Nodeos
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -704,7 +704,6 @@ void state_history_plugin::plugin_shutdown() {
|
||||
my->applied_transaction_connection.reset();
|
||||
my->accepted_block_connection.reset();
|
||||
my->block_start_connection.reset();
|
||||
my->sessions.for_each([](auto& s) { s->close(); });
|
||||
my->stopping = true;
|
||||
my->trace_log->stop();
|
||||
my->chain_state_log->stop();
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Test Control API
|
||||
description: Nodeos Test Control API Specification. See developer documentation at https://docs.eosnetwork.com for information on enabling this plugin.
|
||||
version: 1.0.0
|
||||
license:
|
||||
name: MIT
|
||||
url: https://opensource.org/licenses/MIT
|
||||
contact:
|
||||
url: https://eos.io
|
||||
url: https://eosnetwork.com
|
||||
tags:
|
||||
- name: eosio
|
||||
servers:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <eosio/test_control_plugin/test_control_plugin.hpp>
|
||||
#include <atomic>
|
||||
|
||||
namespace fc { class variant; }
|
||||
|
||||
@@ -9,7 +8,7 @@ static appbase::abstract_plugin& _test_control_plugin = app().register_plugin<te
|
||||
|
||||
class test_control_plugin_impl {
|
||||
public:
|
||||
test_control_plugin_impl(chain::controller& c) : _chain(c) {}
|
||||
explicit test_control_plugin_impl(chain::controller& c) : _chain(c) {}
|
||||
void connect();
|
||||
void disconnect();
|
||||
void kill_on_lib(account_name prod, uint32_t where_in_seq);
|
||||
@@ -24,12 +23,11 @@ private:
|
||||
std::optional<boost::signals2::scoped_connection> _irreversible_block_connection;
|
||||
chain::controller& _chain;
|
||||
account_name _producer;
|
||||
int32_t _where_in_sequence{-1};
|
||||
int32_t _producer_sequence{-1};
|
||||
uint32_t _first_sequence_timeslot{0};
|
||||
uint32_t _where_in_sequence{};
|
||||
bool _clean_producer_sequence{false};
|
||||
std::atomic_bool _track_lib;
|
||||
std::atomic_bool _track_head;
|
||||
bool _started_production_round{false};
|
||||
bool _track_lib{false};
|
||||
bool _track_head{false};
|
||||
};
|
||||
|
||||
void test_control_plugin_impl::connect() {
|
||||
@@ -59,68 +57,54 @@ void test_control_plugin_impl::accepted_block(const chain::block_state_ptr& bsp)
|
||||
}
|
||||
|
||||
void test_control_plugin_impl::process_next_block_state(const chain::block_state_ptr& bsp) {
|
||||
// Tests expect the shutdown only after signaling a producer shutdown and seeing a full production cycle
|
||||
const auto block_time = _chain.head_block_time() + fc::microseconds(chain::config::block_interval_us);
|
||||
const auto& producer_authority = bsp->get_scheduled_producer(block_time);
|
||||
const auto producer_name = producer_authority.producer_name;
|
||||
if (_producer != account_name())
|
||||
ilog("producer ${cprod}, looking for ${lprod}", ("cprod", producer_name.to_string())("lprod", _producer.to_string()));
|
||||
|
||||
// start counting sequences for this producer (once we have a sequence that we saw the initial block for that producer)
|
||||
if (producer_name == _producer && _clean_producer_sequence) {
|
||||
auto slot = bsp->block->timestamp.slot;
|
||||
_producer_sequence += 1;
|
||||
ilog("producer ${prod} seq: ${seq} slot: ${slot}",
|
||||
("prod", producer_name.to_string())
|
||||
("seq", _producer_sequence+1) // _producer_sequence is index, aligning it with slot number
|
||||
("slot", slot - _first_sequence_timeslot));
|
||||
|
||||
bool last_slot = false;
|
||||
if (_where_in_sequence + 1 == chain::config::producer_repetitions){
|
||||
auto last_slot_time = _first_sequence_timeslot + chain::config::producer_repetitions;
|
||||
last_slot = slot == last_slot_time;
|
||||
const auto slot = bsp->block->timestamp.slot % chain::config::producer_repetitions;
|
||||
if (_producer != account_name()) {
|
||||
if( _producer != producer_name ) _clean_producer_sequence = true;
|
||||
if( _clean_producer_sequence ) {
|
||||
ilog( "producer ${cprod} slot ${pslot}, looking for ${lprod} slot ${slot}",
|
||||
("cprod", producer_name)("pslot", slot)("lprod", _producer)("slot", _where_in_sequence) );
|
||||
} else {
|
||||
ilog( "producer ${cprod} slot ${pslot}, looking for start of ${lprod} production round",
|
||||
("cprod", producer_name)("pslot", slot)("lprod", _producer) );
|
||||
}
|
||||
}
|
||||
|
||||
if (_producer_sequence >= _where_in_sequence || last_slot) {
|
||||
int32_t slot_index = slot - _first_sequence_timeslot;
|
||||
if (last_slot && slot_index > _producer_sequence + 1){
|
||||
wlog("Producer produced less than ${n} blocks, ${l}th block is last in sequence. Likely performance issue, check timing",
|
||||
("n", chain::config::producer_repetitions)("l", _producer_sequence + 1));
|
||||
}
|
||||
// check started_production_round in case where producer does not produce a full round, still want to shut down
|
||||
if( _clean_producer_sequence && (producer_name == _producer || _started_production_round) ) {
|
||||
_started_production_round = true;
|
||||
const auto current_slot = chain::block_timestamp_type( block_time ).slot % chain::config::producer_repetitions;
|
||||
ilog( "producer ${prod} slot: ${slot}", ("prod", producer_name)("slot", slot) );
|
||||
|
||||
if( current_slot >= _where_in_sequence || producer_name != _producer ) {
|
||||
ilog("shutting down");
|
||||
app().quit();
|
||||
}
|
||||
} else if (producer_name != _producer) {
|
||||
if (_producer_sequence != -1)
|
||||
ilog("producer changed, restarting");
|
||||
_producer_sequence = -1;
|
||||
// can now guarantee we are at the start of the producer
|
||||
_clean_producer_sequence = true;
|
||||
|
||||
_first_sequence_timeslot = bsp->block->timestamp.slot;
|
||||
}
|
||||
}
|
||||
|
||||
void test_control_plugin_impl::kill_on_lib(account_name prod, uint32_t where_in_seq) {
|
||||
_track_head = false;
|
||||
_producer = prod;
|
||||
_where_in_sequence = static_cast<uint32_t>(where_in_seq);
|
||||
_producer_sequence = -1;
|
||||
_where_in_sequence = where_in_seq;
|
||||
_clean_producer_sequence = false;
|
||||
_started_production_round = false;
|
||||
_track_lib = true;
|
||||
}
|
||||
|
||||
void test_control_plugin_impl::kill_on_head(account_name prod, uint32_t where_in_seq) {
|
||||
_track_lib = false;
|
||||
_producer = prod;
|
||||
_where_in_sequence = static_cast<uint32_t>(where_in_seq);
|
||||
_producer_sequence = -1;
|
||||
_where_in_sequence = where_in_seq;
|
||||
_clean_producer_sequence = false;
|
||||
_started_production_round = false;
|
||||
_track_head = true;
|
||||
}
|
||||
|
||||
test_control_plugin::test_control_plugin()
|
||||
{
|
||||
}
|
||||
test_control_plugin::test_control_plugin() = default;
|
||||
|
||||
void test_control_plugin::set_program_options(options_description& cli, options_description& cfg) {
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Trace API
|
||||
description: See developer documentation at https://docs.eosnetwork.com for information on enabling this plugin.
|
||||
description: Nodeos Trace API Specification. See developer documentation at https://docs.eosnetwork.com for information on enabling this plugin.
|
||||
version: 1.0.0
|
||||
license:
|
||||
name: MIT
|
||||
|
||||
+27
-5
@@ -173,6 +173,7 @@ bool tx_skip_sign = false;
|
||||
bool tx_print_json = false;
|
||||
bool tx_rtn_failure_trace = true;
|
||||
bool tx_read_only = false;
|
||||
bool tx_dry_run = false;
|
||||
bool tx_retry_lib = false;
|
||||
uint16_t tx_retry_num_blocks = 0;
|
||||
bool tx_use_old_rpc = false;
|
||||
@@ -441,7 +442,7 @@ fc::variant push_transaction( signed_transaction& trx, const std::vector<public_
|
||||
trx.delay_sec = delaysec;
|
||||
}
|
||||
|
||||
if (!tx_skip_sign) {
|
||||
auto sign_trx = [&] () {
|
||||
fc::variant required_keys;
|
||||
if (signing_keys.size() > 0) {
|
||||
required_keys = fc::variant(signing_keys);
|
||||
@@ -450,6 +451,16 @@ fc::variant push_transaction( signed_transaction& trx, const std::vector<public_
|
||||
required_keys = determine_required_keys(trx);
|
||||
}
|
||||
sign_transaction(trx, required_keys, info.chain_id);
|
||||
};
|
||||
if (!tx_skip_sign) {
|
||||
// sign dry-run transactions only when explcitly requested
|
||||
if ( tx_dry_run ) {
|
||||
if ( signing_keys.size() > 0 ) {
|
||||
sign_trx();
|
||||
}
|
||||
} else {
|
||||
sign_trx();
|
||||
}
|
||||
}
|
||||
|
||||
packed_transaction::compression_type compression = to_compression_type( tx_compression );
|
||||
@@ -458,12 +469,14 @@ fc::variant push_transaction( signed_transaction& trx, const std::vector<public_
|
||||
EOSC_ASSERT( !(tx_retry_lib && tx_retry_num_blocks > 0), "ERROR: --retry-irreversible and --retry-num-blocks are mutually exclusive" );
|
||||
if (tx_use_old_rpc) {
|
||||
EOSC_ASSERT( !tx_read_only, "ERROR: --read-only can not be used with --use-old-rpc" );
|
||||
EOSC_ASSERT( !tx_dry_run, "ERROR: --dry-run can not be used with --use-old-rpc" );
|
||||
EOSC_ASSERT( !tx_rtn_failure_trace, "ERROR: --return-failure-trace can not be used with --use-old-rpc" );
|
||||
EOSC_ASSERT( !tx_retry_lib, "ERROR: --retry-irreversible can not be used with --use-old-rpc" );
|
||||
EOSC_ASSERT( !tx_retry_num_blocks, "ERROR: --retry-num-blocks can not be used with --use-old-rpc" );
|
||||
return call( push_txn_func, packed_transaction( trx, compression ) );
|
||||
} else if (tx_use_old_send_rpc) {
|
||||
EOSC_ASSERT( !tx_read_only, "ERROR: --read-only can not be used with --use-old-send-rpc" );
|
||||
EOSC_ASSERT( !tx_dry_run, "ERROR: --dry-run can not be used with --use-old-send-rpc" );
|
||||
EOSC_ASSERT( !tx_rtn_failure_trace, "ERROR: --return-failure-trace can not be used with --use-old-send-rpc" );
|
||||
EOSC_ASSERT( !tx_retry_lib, "ERROR: --retry-irreversible can not be used with --use-old-send-rpc" );
|
||||
EOSC_ASSERT( !tx_retry_num_blocks, "ERROR: --retry-num-blocks can not be used with --use-old-send-rpc" );
|
||||
@@ -474,9 +487,9 @@ fc::variant push_transaction( signed_transaction& trx, const std::vector<public_
|
||||
throw;
|
||||
}
|
||||
} else {
|
||||
if( tx_read_only ) {
|
||||
EOSC_ASSERT( !tx_retry_lib, "ERROR: --retry-irreversible can not be used with --read-only" );
|
||||
EOSC_ASSERT( !tx_retry_num_blocks, "ERROR: --retry-num-blocks can not be used with --read-only" );
|
||||
if( tx_dry_run || tx_read_only ) {
|
||||
EOSC_ASSERT( !tx_retry_lib, "ERROR: --retry-irreversible can not be used with --dry-run or --read-only" );
|
||||
EOSC_ASSERT( !tx_retry_num_blocks, "ERROR: --retry-num-blocks can not be used with --dry-run or --read-only" );
|
||||
try {
|
||||
auto compute_txn_arg = fc::mutable_variant_object ("transaction",
|
||||
packed_transaction(trx,compression));
|
||||
@@ -2759,8 +2772,16 @@ int main( int argc, char** argv ) {
|
||||
wallet_url = default_wallet_url;
|
||||
|
||||
CLI::App app{"Command Line Interface to EOSIO Client"};
|
||||
|
||||
// custom leap formatter
|
||||
auto fmt = std::make_shared<CLI::LeapFormatter>();
|
||||
app.formatter(fmt);
|
||||
|
||||
// enable help-all, display help on error
|
||||
app.set_help_all_flag("--help-all", "Show all help");
|
||||
app.failure_message(CLI::FailureMessage::help);
|
||||
app.require_subcommand();
|
||||
|
||||
// Hide obsolete options by putting them into a group with an empty name.
|
||||
app.add_option( "-H,--host", obsoleted_option_host_port, localized("The host where ${n} is running", ("n", node_executable_name)) )->group("");
|
||||
app.add_option( "-p,--port", obsoleted_option_host_port, localized("The port where ${n} is running", ("n", node_executable_name)) )->group("");
|
||||
@@ -3904,7 +3925,8 @@ int main( int argc, char** argv ) {
|
||||
trxSubcommand->add_option("transaction", trx_to_push, localized("The JSON string or filename defining the transaction to push"))->required();
|
||||
trxSubcommand->add_option("--signature", extra_sig_opt_callback, localized("append a signature to the transaction; repeat this option to append multiple signatures"))->type_size(0, 1000);
|
||||
add_standard_transaction_options_plus_signing(trxSubcommand);
|
||||
trxSubcommand->add_flag("-o,--read-only", tx_read_only, localized("Specify a transaction is read-only"));
|
||||
trxSubcommand->add_flag("-o,--read-only", tx_read_only, localized("Deprecated, use --dry-run instead"));
|
||||
trxSubcommand->add_flag("--dry-run", tx_dry_run, localized("Specify a transaction is dry-run"));
|
||||
|
||||
trxSubcommand->callback([&] {
|
||||
fc::variant trx_var = json_from_file_or_string(trx_to_push);
|
||||
|
||||
@@ -81,7 +81,8 @@ int main(int argc, char** argv)
|
||||
app().set_default_config_dir(home / "eosio-wallet");
|
||||
http_plugin::set_defaults({
|
||||
.default_unix_socket_path = keosd::config::key_store_executable_name + ".sock",
|
||||
.default_http_port = 0
|
||||
.default_http_port = 0,
|
||||
.server_header = keosd::config::key_store_executable_name + "/" + app().version_string()
|
||||
});
|
||||
app().register_plugin<wallet_api_plugin>();
|
||||
if(!app().initialize<wallet_plugin, wallet_api_plugin, http_plugin>(argc, argv)) {
|
||||
|
||||
@@ -47,142 +47,77 @@ struct report_time {
|
||||
|
||||
|
||||
void blocklog_actions::setup(CLI::App& app) {
|
||||
// callback helper with error code handling
|
||||
auto err_guard = [this](int (blocklog_actions::*fun)()) {
|
||||
try {
|
||||
initialize();
|
||||
int rc = (this->*fun)();
|
||||
if(rc) throw(CLI::RuntimeError(rc));
|
||||
} catch(...) {
|
||||
print_exception();
|
||||
throw(CLI::RuntimeError(-1));
|
||||
}
|
||||
};
|
||||
|
||||
// main command
|
||||
auto* sub = app.add_subcommand("block-log", "Blocklog utility");
|
||||
sub->require_subcommand(1);
|
||||
|
||||
// callback with error code handling
|
||||
auto cb = [this]() {
|
||||
int rc = run_subcommand();
|
||||
// properly return err code in main
|
||||
if(rc) throw(CLI::RuntimeError(rc));
|
||||
};
|
||||
// subcommand - print log
|
||||
auto* print_log = sub->add_subcommand("print-log", "Print blocks.log as JSON")->callback([err_guard]() { err_guard(&blocklog_actions::read_log); });
|
||||
print_log->add_option("--blocks-dir", opt->blocks_dir, "The location of the blocks directory (absolute path or relative to the current directory).");
|
||||
print_log->add_option("--output-file,-o", opt->output_file, "The file to write the output to (absolute or relative path). If not specified then output is to stdout.");
|
||||
print_log->add_option("--first,-f", opt->first_block, "The first block number to log or the first to keep if trim-blocklog.");
|
||||
print_log->add_option("--last,-l", opt->last_block, "The last block number to log or the last to keep if trim-blocklog.");
|
||||
print_log->add_flag("--no-pretty-print", opt->no_pretty_print, "Do not pretty print the output. Useful if piping to jq to improve performance.");
|
||||
print_log->add_flag("--as-json-array", opt->as_json_array, "Print out json blocks wrapped in json array (otherwise the output is free-standing json objects).");
|
||||
|
||||
// options
|
||||
sub->add_option("--blocks-dir", opt->blocks_dir, "The location of the blocks directory (absolute path or relative to the current directory).");
|
||||
sub->add_option("--output-file,-o", opt->output_file, "The file to write the output to (absolute or relative path). If not specified then output is to stdout.");
|
||||
sub->add_option("--first,-f", opt->first_block, "The first block number to log or the first to keep if trim-blocklog.");
|
||||
sub->add_option("--last,-l", opt->last_block, "The last block number to log or the last to keep if trim-blocklog.");
|
||||
sub->add_option("--output-dir", opt->output_dir, "The output directory for the block log extracted from blocks-dir.");
|
||||
// subcommand - make index
|
||||
auto* make_index = sub->add_subcommand("make-index", "Create blocks.index from blocks.log. Must give 'blocks-dir'. Give 'output-file' relative to current directory or absolute path (default is <blocks-dir>/blocks.index).")->callback([err_guard]() { err_guard(&blocklog_actions::make_index); });
|
||||
make_index->add_option("--blocks-dir", opt->blocks_dir, "The location of the blocks directory (absolute path or relative to the current directory).");
|
||||
make_index->add_option("--output-file,-o", opt->output_file, "The file to write the output to (absolute or relative path). If not specified then output is to stdout.");
|
||||
|
||||
// flags
|
||||
sub->add_flag("--no-pretty-print", opt->no_pretty_print, "Do not pretty print the output. Useful if piping to jq to improve performance.");
|
||||
sub->add_flag("--as-json-array", opt->as_json_array, "Print out json blocks wrapped in json array (otherwise the output is free-standing json objects).");
|
||||
// subcommand - trim blocklog
|
||||
auto* trim_blocklog = sub->add_subcommand("trim-blocklog", "Trim blocks.log and blocks.index. Must give 'blocks-dir' and 'first' and/or 'last'.")->callback([err_guard]() { err_guard(&blocklog_actions::trim_blocklog); });
|
||||
trim_blocklog->add_option("--blocks-dir", opt->blocks_dir, "The location of the blocks directory (absolute path or relative to the current directory).");
|
||||
trim_blocklog->add_option("--first,-f", opt->first_block, "The first block number to keep.")->required();
|
||||
trim_blocklog->add_option("--last,-l", opt->last_block, "The last block number to keep.")->required();
|
||||
|
||||
// subcommands
|
||||
sub->add_subcommand("make-index", "Create blocks.index from blocks.log. Must give 'blocks-dir'. Give 'output-file' relative to current directory or absolute path (default is <blocks-dir>/blocks.index).")->callback([this, cb]() {opt->make_index=true; cb(); });
|
||||
sub->add_subcommand("trim-blocklog", "Trim blocks.log and blocks.index. Must give 'blocks-dir' and 'first' and/or 'last'.")->callback([this, cb]() {opt->trim_blocklog=true; cb(); });
|
||||
sub->add_subcommand("extract-blocks", "Extract range of blocks from blocks.log and write to output-dir. Must give 'first' and/or 'last'.")->callback([this, cb]() {opt->extract_blocks=true; cb(); });
|
||||
sub->add_subcommand("smoke-test", "Quick test that blocks.log and blocks.index are well formed and agree with each other.")->callback([this, cb]() {opt->smoke_test=true; cb(); });
|
||||
sub->add_subcommand("vacuum", "Vacuum a pruned blocks.log in to an un-pruned blocks.log")->callback([this, cb]() {opt->vacuum=true; cb(); });
|
||||
sub->add_subcommand("genesis", "Extract genesis_state from blocks.log as JSON")->callback([this, cb]() {opt->genesis=true; cb(); });
|
||||
// subcommand - extract blocks
|
||||
auto* extract_blocks = sub->add_subcommand("extract-blocks", "Extract range of blocks from blocks.log and write to output-dir. Must give 'first' and/or 'last'.")->callback([err_guard]() { err_guard(&blocklog_actions::extract_blocks); });
|
||||
extract_blocks->add_option("--blocks-dir", opt->blocks_dir, "The location of the blocks directory (absolute path or relative to the current directory).");
|
||||
extract_blocks->add_option("--first,-f", opt->first_block, "The first block number to keep.")->required();
|
||||
extract_blocks->add_option("--last,-l", opt->last_block, "The last block number to keep.")->required();
|
||||
extract_blocks->add_option("--output-dir", opt->output_dir, "The output directory for the block log extracted from blocks-dir.");
|
||||
|
||||
sub->callback([cb]() { cb(); });
|
||||
// subcommand - smoke test
|
||||
auto* smoke_test = sub->add_subcommand("smoke-test", "Quick test that blocks.log and blocks.index are well formed and agree with each other.")->callback([err_guard]() { err_guard(&blocklog_actions::smoke_test); });
|
||||
smoke_test->add_option("--blocks-dir", opt->blocks_dir, "The location of the blocks directory (absolute path or relative to the current directory).");
|
||||
|
||||
// subcommand - vacuum
|
||||
auto* vacuum = sub->add_subcommand("vacuum", "Vacuum a pruned blocks.log in to an un-pruned blocks.log")->callback([err_guard]() { err_guard(&blocklog_actions::do_vacuum); });
|
||||
vacuum->add_option("--blocks-dir", opt->blocks_dir, "The location of the blocks directory (absolute path or relative to the current directory).");
|
||||
|
||||
// subcommand - genesis
|
||||
auto* genesis = sub->add_subcommand("genesis", "Extract genesis_state from blocks.log as JSON")->callback([err_guard]() { err_guard(&blocklog_actions::do_genesis); });
|
||||
genesis->add_option("--blocks-dir", opt->blocks_dir, "The location of the blocks directory (absolute path or relative to the current directory).");
|
||||
genesis->add_option("--output-file,-o", opt->output_file, "The file to write the output to (absolute or relative path). If not specified then output is to stdout.");
|
||||
}
|
||||
|
||||
int blocklog_actions::run_subcommand() {
|
||||
std::ios::sync_with_stdio(false);// for potential performance boost for large block log files
|
||||
void blocklog_actions::print_exception() noexcept {
|
||||
try {
|
||||
if(opt->trim_blocklog) {
|
||||
if(opt->first_block == 0 && opt->last_block == std::numeric_limits<uint32_t>::max()) {
|
||||
std::cerr << "trim-blocklog does nothing unless first and/or last block are specified.";
|
||||
return -1;
|
||||
}
|
||||
if(opt->last_block != std::numeric_limits<uint32_t>::max()) {
|
||||
if(trim_blocklog_end(opt->blocks_dir, opt->last_block) != 0)
|
||||
return -1;
|
||||
}
|
||||
if(opt->first_block != 0) {
|
||||
if(!trim_blocklog_front(opt->blocks_dir, opt->first_block))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if(opt->extract_blocks) {
|
||||
if(opt->first_block == 0 && opt->last_block == std::numeric_limits<uint32_t>::max()) {
|
||||
std::cerr << "extract-blocklog does nothing unless first and/or last block are specified.";
|
||||
return -1;
|
||||
}
|
||||
if(!extract_block_range(opt->blocks_dir, opt->output_dir, opt->first_block, opt->last_block))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
if(opt->vacuum) {
|
||||
initialize();
|
||||
return do_vacuum();
|
||||
}
|
||||
if(opt->genesis) {
|
||||
initialize();
|
||||
return do_genesis();
|
||||
}
|
||||
if(opt->make_index) {
|
||||
const bfs::path blocks_dir = opt->blocks_dir;
|
||||
bfs::path out_file = blocks_dir / "blocks.index";
|
||||
const bfs::path block_file = blocks_dir / "blocks.log";
|
||||
|
||||
if(!opt->output_file.empty())
|
||||
out_file = opt->output_file;
|
||||
|
||||
report_time rt("making index");
|
||||
const auto log_level = fc::logger::get(DEFAULT_LOGGER).get_log_level();
|
||||
fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::debug);
|
||||
block_log::construct_index(block_file.generic_string(), out_file.generic_string());
|
||||
fc::logger::get(DEFAULT_LOGGER).set_log_level(log_level);
|
||||
rt.report();
|
||||
return 0;
|
||||
}
|
||||
//else print blocks.log as JSON
|
||||
initialize();
|
||||
read_log();
|
||||
throw;
|
||||
} catch(const fc::exception& e) {
|
||||
elog("${e}", ("e", e.to_detail_string()));
|
||||
return -1;
|
||||
} catch(const boost::exception& e) {
|
||||
elog("${e}", ("e", boost::diagnostic_information(e)));
|
||||
return -1;
|
||||
} catch(const CLI::RuntimeError& e) {
|
||||
// avoid reporting it twice, RuntimeError is only for cli11
|
||||
} catch(const std::exception& e) {
|
||||
elog("${e}", ("e", e.what()));
|
||||
return -1;
|
||||
} catch(...) {
|
||||
elog("unknown exception");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blocklog_actions::do_genesis() {
|
||||
std::optional<genesis_state> gs;
|
||||
bfs::path bld = opt->blocks_dir;
|
||||
auto full_path = (bld / "blocks.log").generic_string();
|
||||
|
||||
if(fc::exists(bld / "blocks.log")) {
|
||||
gs = block_log::extract_genesis_state(opt->blocks_dir);
|
||||
if (!gs) {
|
||||
std::cerr << "Block log at '" << full_path
|
||||
<< "' does not contain a genesis state, it only has the chain-id." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "No blocks.log found at '" << full_path << "'." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// just print if output not set
|
||||
if(opt->output_file.empty()) {
|
||||
std::cout << json::to_pretty_string(*gs) << std::endl;
|
||||
} else {
|
||||
bfs::path p = opt->output_file;
|
||||
if(p.is_relative()) {
|
||||
p = bfs::current_path() / p;
|
||||
}
|
||||
|
||||
if (!fc::json::save_to_file(*gs, p, true)) {
|
||||
std::cerr << "Error occurred while writing genesis JSON to '" << p.generic_string() << "'" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "Saved genesis JSON to '" << p.generic_string() << "'" << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void blocklog_actions::initialize() {
|
||||
@@ -211,6 +146,74 @@ void blocklog_actions::initialize() {
|
||||
FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
int blocklog_actions::make_index() {
|
||||
const bfs::path blocks_dir = opt->blocks_dir;
|
||||
bfs::path out_file = blocks_dir / "blocks.index";
|
||||
const bfs::path block_file = blocks_dir / "blocks.log";
|
||||
if(!opt->output_file.empty()) out_file = opt->output_file;
|
||||
|
||||
report_time rt("making index");
|
||||
const auto log_level = fc::logger::get(DEFAULT_LOGGER).get_log_level();
|
||||
fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::debug);
|
||||
block_log::construct_index(block_file.generic_string(), out_file.generic_string());
|
||||
fc::logger::get(DEFAULT_LOGGER).set_log_level(log_level);
|
||||
rt.report();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blocklog_actions::trim_blocklog() {
|
||||
if(opt->last_block != std::numeric_limits<uint32_t>::max()) {
|
||||
if(trim_blocklog_end(opt->blocks_dir, opt->last_block) != 0) return -1;
|
||||
}
|
||||
if(opt->first_block != 0) {
|
||||
if(!trim_blocklog_front(opt->blocks_dir, opt->first_block)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blocklog_actions::extract_blocks() {
|
||||
if(!extract_block_range(opt->blocks_dir, opt->output_dir, opt->first_block, opt->last_block))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blocklog_actions::do_genesis() {
|
||||
std::optional<genesis_state> gs;
|
||||
bfs::path bld = opt->blocks_dir;
|
||||
auto full_path = (bld / "blocks.log").generic_string();
|
||||
|
||||
if(fc::exists(bld / "blocks.log")) {
|
||||
gs = block_log::extract_genesis_state(opt->blocks_dir);
|
||||
if(!gs) {
|
||||
std::cerr << "Block log at '" << full_path
|
||||
<< "' does not contain a genesis state, it only has the chain-id." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "No blocks.log found at '" << full_path << "'." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// just print if output not set
|
||||
if(opt->output_file.empty()) {
|
||||
std::cout << json::to_pretty_string(*gs) << std::endl;
|
||||
} else {
|
||||
bfs::path p = opt->output_file;
|
||||
if(p.is_relative()) {
|
||||
p = bfs::current_path() / p;
|
||||
}
|
||||
|
||||
if(!fc::json::save_to_file(*gs, p, true)) {
|
||||
std::cerr << "Error occurred while writing genesis JSON to '" << p.generic_string() << "'" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "Saved genesis JSON to '" << p.generic_string() << "'" << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blocklog_actions::trim_blocklog_end(bfs::path block_dir, uint32_t n) {//n is last block to keep (remove later blocks)
|
||||
report_time rt("trimming blocklog end");
|
||||
using namespace std;
|
||||
@@ -250,9 +253,9 @@ bool blocklog_actions::extract_block_range(bfs::path block_dir, bfs::path output
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void blocklog_actions::smoke_test(bfs::path block_dir) {
|
||||
int blocklog_actions::smoke_test() {
|
||||
using namespace std;
|
||||
bfs::path block_dir = opt->blocks_dir;
|
||||
cout << "\nSmoke test of blocks.log and blocks.index in directory " << block_dir << '\n';
|
||||
trim_data td(block_dir);
|
||||
auto status = fseek(td.blk_in, -sizeof(uint64_t), SEEK_END);//get last_block from blocks.log, compare to from blocks.index
|
||||
@@ -279,10 +282,19 @@ void blocklog_actions::smoke_test(bfs::path block_dir) {
|
||||
break;
|
||||
}
|
||||
cout << "\nno problems found\n";//if get here there were no exceptions
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blocklog_actions::do_vacuum() {
|
||||
if (!opt->blog_keep_prune_conf) {
|
||||
bfs::path bld = opt->blocks_dir;
|
||||
auto full_path = (bld / "blocks.log").generic_string();
|
||||
|
||||
if(!fc::exists(bld / "blocks.log")) {
|
||||
std::cerr << "No blocks.log found at '" << full_path << "'." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!opt->blog_keep_prune_conf) {
|
||||
std::cerr << "blocks.log is not a pruned log; nothing to vacuum" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
@@ -291,7 +303,8 @@ int blocklog_actions::do_vacuum() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void blocklog_actions::read_log() {
|
||||
int blocklog_actions::read_log() {
|
||||
initialize();
|
||||
report_time rt("reading log");
|
||||
block_log block_logger(opt->blocks_dir, opt->blog_keep_prune_conf);
|
||||
const auto end = block_logger.read_head();
|
||||
@@ -385,4 +398,6 @@ void blocklog_actions::read_log() {
|
||||
if(opt->as_json_array)
|
||||
*out << "]";
|
||||
rt.report();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -12,20 +12,12 @@ struct blocklog_options {
|
||||
std::string output_file = "";
|
||||
uint32_t first_block = 0;
|
||||
uint32_t last_block = std::numeric_limits<uint32_t>::max();
|
||||
std::string output_dir;
|
||||
std::string output_dir = "";
|
||||
|
||||
// flags
|
||||
bool no_pretty_print = false;
|
||||
bool as_json_array = false;
|
||||
|
||||
// subcommands
|
||||
bool make_index = false;
|
||||
bool trim_blocklog = false;
|
||||
bool extract_blocks = false;
|
||||
bool smoke_test = false;
|
||||
bool vacuum = false;
|
||||
bool genesis = false;
|
||||
|
||||
std::optional<block_log_prune_config> blog_keep_prune_conf;
|
||||
};
|
||||
|
||||
@@ -34,16 +26,19 @@ public:
|
||||
blocklog_actions() : sub_command() {}
|
||||
void setup(CLI::App& app);
|
||||
|
||||
// callbacks
|
||||
int run_subcommand();
|
||||
|
||||
protected:
|
||||
void print_exception() noexcept;
|
||||
|
||||
void initialize();
|
||||
int trim_blocklog_end(bfs::path block_dir, uint32_t n);
|
||||
bool trim_blocklog_front(bfs::path block_dir, uint32_t n);
|
||||
bool extract_block_range(bfs::path block_dir, bfs::path output_dir, uint32_t start, uint32_t end);
|
||||
void smoke_test(bfs::path block_dir);
|
||||
int do_vacuum();
|
||||
int do_genesis();
|
||||
void read_log();
|
||||
|
||||
int make_index();
|
||||
int trim_blocklog();
|
||||
int extract_blocks();
|
||||
int smoke_test();
|
||||
int do_vacuum();
|
||||
int do_genesis();
|
||||
int read_log();
|
||||
};
|
||||
@@ -37,8 +37,8 @@ void chain_actions::setup(CLI::App& app) {
|
||||
sub->require_subcommand(1);
|
||||
|
||||
auto* build = sub->add_subcommand("build-info", "extract build environment information as JSON");
|
||||
auto opt1 = build->add_option("--output-file,-o", opt->build_output_file, "write into specified file")->capture_default_str();
|
||||
auto opt2 = build->add_flag("--print,-p", opt->build_just_print, "print to console");
|
||||
build->add_option("--output-file,-o", opt->build_output_file, "write into specified file")->capture_default_str();
|
||||
build->add_flag("--print,-p", opt->build_just_print, "print to console");
|
||||
build->require_option(1);
|
||||
|
||||
build->callback([&]() {
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
#include <cli11/CLI11.hpp>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
class leap_formatter : public CLI::Formatter {
|
||||
public:
|
||||
leap_formatter() : Formatter() {
|
||||
// 30 is default for CLI11, but seems like overkill
|
||||
column_width(25);
|
||||
}
|
||||
};
|
||||
@@ -12,18 +12,17 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "leap_formatter.hpp"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::debug);
|
||||
|
||||
CLI::App app{"Leap Command Line Utility"};
|
||||
|
||||
// custom leap formatter
|
||||
auto fmt = std::make_shared<leap_formatter>();
|
||||
auto fmt = std::make_shared<CLI::LeapFormatter>();
|
||||
app.formatter(fmt);
|
||||
|
||||
app.set_help_all_flag("--help-all", "Show all help");
|
||||
app.failure_message(CLI::FailureMessage::help);
|
||||
app.require_subcommand(1, 2);
|
||||
|
||||
// generics sc tree
|
||||
|
||||
@@ -120,7 +120,8 @@ int main(int argc, char** argv)
|
||||
app().set_default_config_dir(root / "eosio" / nodeos::config::node_executable_name / "config" );
|
||||
http_plugin::set_defaults({
|
||||
.default_unix_socket_path = "",
|
||||
.default_http_port = 8888
|
||||
.default_http_port = 8888,
|
||||
.server_header = nodeos::config::node_executable_name + "/" + app().version_string()
|
||||
});
|
||||
if(!app().initialize<chain_plugin, net_plugin, producer_plugin, resource_monitor_plugin>(argc, argv)) {
|
||||
const auto& opts = app().get_options();
|
||||
|
||||
@@ -783,7 +783,7 @@ class Cluster(object):
|
||||
#Utils.Print("nextEosIdx: %d, count: %d" % (nextEosIdx, count))
|
||||
node=self.nodes[nextEosIdx]
|
||||
if Utils.Debug: Utils.Print("Wait for transaction id %s on node port %d" % (transId, node.port))
|
||||
if node.waitForTransInBlock(transId) is False:
|
||||
if node.waitForTransactionInBlock(transId) is False:
|
||||
Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, node.port))
|
||||
return False
|
||||
|
||||
@@ -804,7 +804,7 @@ class Cluster(object):
|
||||
# As an extra step wait for last transaction on the root node
|
||||
node=self.nodes[0]
|
||||
if Utils.Debug: Utils.Print("Wait for transaction id %s on node port %d" % (transId, node.port))
|
||||
if node.waitForTransInBlock(transId) is False:
|
||||
if node.waitForTransactionInBlock(transId) is False:
|
||||
Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, node.port))
|
||||
return False
|
||||
|
||||
@@ -1062,7 +1062,7 @@ class Cluster(object):
|
||||
|
||||
Utils.Print("Wait for last transfer transaction to become finalized.")
|
||||
transId=Node.getTransId(trans[1])
|
||||
if not biosNode.waitForTransInBlock(transId):
|
||||
if not biosNode.waitForTransactionInBlock(transId):
|
||||
Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port))
|
||||
return None
|
||||
|
||||
@@ -1146,7 +1146,7 @@ class Cluster(object):
|
||||
accounts.append(initx)
|
||||
|
||||
transId=Node.getTransId(trans)
|
||||
if not biosNode.waitForTransInBlock(transId):
|
||||
if not biosNode.waitForTransactionInBlock(transId):
|
||||
Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port))
|
||||
return None
|
||||
|
||||
@@ -1195,7 +1195,7 @@ class Cluster(object):
|
||||
|
||||
trans=trans[1]
|
||||
transId=Node.getTransId(trans)
|
||||
if not biosNode.waitForTransInBlock(transId):
|
||||
if not biosNode.waitForTransactionInBlock(transId):
|
||||
Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port))
|
||||
return None
|
||||
|
||||
@@ -1238,7 +1238,7 @@ class Cluster(object):
|
||||
|
||||
Node.validateTransaction(trans)
|
||||
transId=Node.getTransId(trans)
|
||||
if not biosNode.waitForTransInBlock(transId):
|
||||
if not biosNode.waitForTransactionInBlock(transId):
|
||||
Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port))
|
||||
return None
|
||||
|
||||
@@ -1265,7 +1265,7 @@ class Cluster(object):
|
||||
|
||||
Node.validateTransaction(trans[1])
|
||||
transId=Node.getTransId(trans[1])
|
||||
if not biosNode.waitForTransInBlock(transId):
|
||||
if not biosNode.waitForTransactionInBlock(transId):
|
||||
Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port))
|
||||
return None
|
||||
|
||||
@@ -1282,7 +1282,7 @@ class Cluster(object):
|
||||
Node.validateTransaction(trans[1])
|
||||
Utils.Print("Wait for issue action transaction to become finalized.")
|
||||
transId=Node.getTransId(trans[1])
|
||||
# biosNode.waitForTransInBlock(transId)
|
||||
# biosNode.waitForTransactionInBlock(transId)
|
||||
# guesstimating block finalization timeout. Two production rounds of 12 blocks per node, plus 60 seconds buffer
|
||||
timeout = .5 * 12 * 2 * len(producerKeys) + 60
|
||||
if not biosNode.waitForTransFinalization(transId, timeout=timeout):
|
||||
@@ -1327,7 +1327,7 @@ class Cluster(object):
|
||||
|
||||
Utils.Print("Wait for last transfer transaction to become finalized.")
|
||||
transId=Node.getTransId(trans[1])
|
||||
if not biosNode.waitForTransInBlock(transId):
|
||||
if not biosNode.waitForTransactionInBlock(transId):
|
||||
Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port))
|
||||
return None
|
||||
|
||||
@@ -1339,7 +1339,7 @@ class Cluster(object):
|
||||
trans=biosNode.pushMessage(eosioAccount.name, action, data, opts)
|
||||
transId=Node.getTransId(trans[1])
|
||||
Utils.Print("Wait for system init transaction to be in a block.")
|
||||
if not biosNode.waitForTransInBlock(transId):
|
||||
if not biosNode.waitForTransactionInBlock(transId):
|
||||
Utils.Print("ERROR: Failed to validate transaction %s in block on server port %d." % (transId, biosNode.port))
|
||||
return None
|
||||
|
||||
@@ -1566,7 +1566,7 @@ class Cluster(object):
|
||||
if waitForTransBlock and transId is not None:
|
||||
node=self.nodes[0]
|
||||
if Utils.Debug: Utils.Print("Wait for transaction id %s on server port %d." % ( transId, node.port))
|
||||
if node.waitForTransInBlock(transId) is False:
|
||||
if node.waitForTransactionInBlock(transId) is False:
|
||||
Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, node.port))
|
||||
return False
|
||||
|
||||
|
||||
@@ -384,7 +384,7 @@ class Node(object):
|
||||
transId=Node.getTransId(trans)
|
||||
|
||||
if stakedDeposit > 0:
|
||||
self.waitForTransInBlock(transId) # seems like account creation needs to be finalized before transfer can happen
|
||||
self.waitForTransactionInBlock(transId) # seems like account creation needs to be finalized before transfer can happen
|
||||
trans = self.transferFunds(creatorAccount, account, Node.currencyIntToStr(stakedDeposit, CORE_SYMBOL), "init")
|
||||
transId=Node.getTransId(trans)
|
||||
|
||||
@@ -403,7 +403,7 @@ class Node(object):
|
||||
transId=Node.getTransId(trans)
|
||||
|
||||
if stakedDeposit > 0:
|
||||
self.waitForTransInBlock(transId) # seems like account creation needs to be finlized before transfer can happen
|
||||
self.waitForTransactionInBlock(transId) # seems like account creation needs to be finlized before transfer can happen
|
||||
trans = self.transferFunds(creatorAccount, account, "%0.04f %s" % (stakedDeposit/10000, CORE_SYMBOL), "init")
|
||||
self.trackCmdTransaction(trans)
|
||||
transId=Node.getTransId(trans)
|
||||
@@ -482,13 +482,17 @@ class Node(object):
|
||||
|
||||
return None
|
||||
|
||||
def waitForTransInBlock(self, transId, timeout=None):
|
||||
def waitForTransactionInBlock(self, transId, timeout=None):
|
||||
"""Wait for trans id to be finalized."""
|
||||
assert(isinstance(transId, str))
|
||||
lam = lambda: self.isTransInAnyBlock(transId)
|
||||
ret=Utils.waitForBool(lam, timeout)
|
||||
return ret
|
||||
|
||||
def waitForTransactionsInBlock(self, transIds, timeout=None):
|
||||
for transId in transIds:
|
||||
self.waitForTransactionInBlock(transId, timeout)
|
||||
|
||||
def waitForTransFinalization(self, transId, timeout=None):
|
||||
"""Wait for trans id to be finalized."""
|
||||
assert(isinstance(transId, str))
|
||||
@@ -1079,7 +1083,7 @@ class Node(object):
|
||||
return trans
|
||||
|
||||
transId=Node.getTransId(trans)
|
||||
if not self.waitForTransInBlock(transId):
|
||||
if not self.waitForTransactionInBlock(transId):
|
||||
if exitOnError:
|
||||
Utils.cmdError("transaction with id %s never made it to a block" % (transId))
|
||||
Utils.errorExit("Failed to find transaction with id %s in a block before timeout" % (transId))
|
||||
|
||||
@@ -115,6 +115,8 @@ try:
|
||||
|
||||
results = node.pushTransaction(trx, opts='--read-only', permissions=account1.name)
|
||||
assert(results[0])
|
||||
results = node.pushTransaction(trx, opts='--dry-run', permissions=account1.name)
|
||||
assert(results[0])
|
||||
node.waitForLibToAdvance(30)
|
||||
|
||||
postBalances = node.getEosBalances([account1, account2])
|
||||
@@ -122,6 +124,8 @@ try:
|
||||
|
||||
results = node.pushTransaction(trx, opts='--read-only --skip-sign')
|
||||
assert(results[0])
|
||||
results = node.pushTransaction(trx, opts='--dry-run --skip-sign')
|
||||
assert(results[0])
|
||||
node.waitForLibToAdvance(30)
|
||||
|
||||
postBalances = node.getEosBalances([account1, account2])
|
||||
@@ -141,6 +145,8 @@ try:
|
||||
|
||||
results = npnode.pushTransaction(trx2, opts="--read-only")
|
||||
assert(not results[0])
|
||||
results = npnode.pushTransaction(trx2, opts="--dry-run")
|
||||
assert(not results[0])
|
||||
|
||||
# Verify that no subjective billing was charged
|
||||
acct2 = npnode.getAccountSubjectiveInfo("account2")
|
||||
@@ -174,10 +180,12 @@ try:
|
||||
}
|
||||
results = npnode.pushTransaction(trx3, opts="--read-only")
|
||||
assert(results[0])
|
||||
results = npnode.pushTransaction(trx3, opts="--dry-run")
|
||||
assert(results[0])
|
||||
|
||||
testSuccessful = True
|
||||
finally:
|
||||
TestHelper.shutdown(cluster, walletMgr, testSuccessful, killEosInstances, killWallet, keepLogs, killAll, dumpErrorDetails)
|
||||
|
||||
errorCode = 0 if testSuccessful else 1
|
||||
exit(errorCode)
|
||||
exit(errorCode)
|
||||
|
||||
@@ -180,7 +180,7 @@ try:
|
||||
cmdError("FAILURE - transfer failed")
|
||||
errorExit("Transfer verification failed. Excepted %s, actual: %s" % (expectedAmount, actualAmount))
|
||||
|
||||
node.waitForTransInBlock(transId)
|
||||
node.waitForTransactionInBlock(transId)
|
||||
|
||||
transaction=node.getTransaction(transId, exitOnError=True, delayedRetry=False)
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ try:
|
||||
transferAmount="100000000.0000 {0}".format(CORE_SYMBOL)
|
||||
Print("Transfer funds %s from account %s to %s" % (transferAmount, cluster.eosioAccount.name, account.name))
|
||||
node.transferFunds(cluster.eosioAccount, account, transferAmount, "test transfer", waitForTransBlock=True)
|
||||
trans=node.delegatebw(account, 20000000.0000, 20000000.0000, waitForTransBlock=True, exitOnError=True)
|
||||
trans=node.delegatebw(account, 20000000.0000, 20000000.0000, waitForTransBlock=False, exitOnError=True)
|
||||
|
||||
|
||||
# *** vote using accounts ***
|
||||
@@ -240,7 +240,7 @@ try:
|
||||
index=0
|
||||
for account in accounts:
|
||||
Print("Vote for producers=%s" % (producers))
|
||||
trans=prodNodes[index % len(prodNodes)].vote(account, producers, waitForTransBlock=True)
|
||||
trans=prodNodes[index % len(prodNodes)].vote(account, producers, waitForTransBlock=False)
|
||||
index+=1
|
||||
|
||||
|
||||
@@ -372,6 +372,9 @@ try:
|
||||
# block number to start expecting node killed after
|
||||
preKillBlockNum=nonProdNode.getBlockNum()
|
||||
preKillBlockProducer=nonProdNode.getBlockProducerByNum(preKillBlockNum)
|
||||
if preKillBlockProducer == "defproducerj" or preKillBlockProducer == "defproducerk":
|
||||
# wait for defproduceri so there is plenty of time to send kill before defproducerk
|
||||
nonProdNode.waitForProducer("defproduceri")
|
||||
Print("preKillBlockProducer = {}".format(preKillBlockProducer))
|
||||
# kill at last block before defproducerl, since the block it is killed on will get propagated
|
||||
killAtProducer="defproducerk"
|
||||
|
||||
@@ -171,7 +171,7 @@ try:
|
||||
Print("Transaction not found for trans id: %s. Will wait %d seconds to see if it arrives in a block." %
|
||||
(transId, args.transaction_time_delta))
|
||||
transTimeDelayed = True
|
||||
node.waitForTransInBlock(transId, timeout = args.transaction_time_delta)
|
||||
node.waitForTransactionInBlock(transId, timeout = args.transaction_time_delta)
|
||||
continue
|
||||
|
||||
lastIrreversibleBlockNum = node.getIrreversibleBlockNum()
|
||||
|
||||
@@ -192,7 +192,7 @@ try:
|
||||
Print("Transaction not found for trans id: %s. Will wait %d seconds to see if it arrives in a block." %
|
||||
(transId, args.transaction_time_delta))
|
||||
transTimeDelayed = True
|
||||
node.waitForTransInBlock(transId, timeout = args.transaction_time_delta)
|
||||
node.waitForTransactionInBlock(transId, timeout = args.transaction_time_delta)
|
||||
continue
|
||||
|
||||
lastIrreversibleBlockNum = node.getIrreversibleBlockNum()
|
||||
|
||||
@@ -277,7 +277,7 @@ try:
|
||||
cmdError("FAILURE - transfer failed")
|
||||
errorExit("Transfer verification failed. Excepted %s, actual: %s" % (expectedAmount, actualAmount))
|
||||
|
||||
node.waitForTransInBlock(transId)
|
||||
node.waitForTransactionInBlock(transId)
|
||||
|
||||
transaction=node.getTransaction(transId, exitOnError=True, delayedRetry=False)
|
||||
|
||||
@@ -417,7 +417,7 @@ try:
|
||||
errorExit("Failed to reject duplicate message for currency1111 contract")
|
||||
|
||||
Print("verify transaction exists")
|
||||
if not node.waitForTransInBlock(transId):
|
||||
if not node.waitForTransactionInBlock(transId):
|
||||
cmdError("%s get transaction trans_id" % (ClientName))
|
||||
errorExit("Failed to verify push message transaction id.")
|
||||
|
||||
|
||||
+2
-2
@@ -59,7 +59,7 @@ class StressNetwork:
|
||||
if trid is None:
|
||||
return ([], "", 0.0, "failed to issue currency0000")
|
||||
print("transaction id %s" % (trid))
|
||||
node.waitForTransInBlock(trid)
|
||||
node.waitForTransactionInBlock(trid)
|
||||
|
||||
self.trList = []
|
||||
expBal = 0
|
||||
@@ -97,7 +97,7 @@ class StressNetwork:
|
||||
for tr in self.trList:
|
||||
trid = node.getTransId(tr)
|
||||
transIdlist.append(trid)
|
||||
node.waitForTransInBlock(trid)
|
||||
node.waitForTransactionInBlock(trid)
|
||||
return (transIdlist, acc2.name, expBal, "")
|
||||
|
||||
def on_exit(self):
|
||||
|
||||
@@ -86,10 +86,10 @@ try:
|
||||
nonProdNode=None
|
||||
prodNodes=[]
|
||||
producers=[]
|
||||
for node in cluster.getNodes():
|
||||
for i, node in enumerate(cluster.getNodes()):
|
||||
node.producers=Cluster.parseProducers(node.nodeId)
|
||||
numProducers=len(node.producers)
|
||||
Print(f"node has producers={node.producers}")
|
||||
Print(f"node {i} has producers={node.producers}")
|
||||
if numProducers==0:
|
||||
if nonProdNode is None:
|
||||
nonProdNode=node
|
||||
@@ -99,9 +99,8 @@ try:
|
||||
prodNodes.append(node)
|
||||
producers.extend(node.producers)
|
||||
|
||||
|
||||
node=prodNodes[0]
|
||||
node1=prodNodes[1]
|
||||
prodAB=prodNodes[0] # defproducera, defproducerb
|
||||
prodC=prodNodes[1] # defproducerc
|
||||
|
||||
# *** Identify a block where production is stable ***
|
||||
|
||||
@@ -115,24 +114,15 @@ try:
|
||||
account1.activePublicKey = EOSIO_ACCT_PUBLIC_DEFAULT_KEY
|
||||
cluster.createAccountAndVerify(account1, cluster.eosioAccount, stakedDeposit=1000)
|
||||
|
||||
Print("Creating account2")
|
||||
account2 = Account('account2')
|
||||
account2.ownerPublicKey = EOSIO_ACCT_PUBLIC_DEFAULT_KEY
|
||||
account2.activePublicKey = EOSIO_ACCT_PUBLIC_DEFAULT_KEY
|
||||
cluster.createAccountAndVerify(account2, cluster.eosioAccount, stakedDeposit=1000)
|
||||
|
||||
Print("Validating accounts after bootstrap")
|
||||
cluster.validateAccounts([account1, account2])
|
||||
cluster.validateAccounts([account1])
|
||||
|
||||
# *** Killing the "bridge" node ***
|
||||
Print("Sending command to kill \"bridge\" node to separate the 2 producer groups.")
|
||||
# block number to start expecting node killed after
|
||||
preKillBlockNum=nonProdNode.getBlockNum()
|
||||
preKillBlockProducer=nonProdNode.getBlockProducerByNum(preKillBlockNum)
|
||||
# kill at the end of the production window for defproducera, so there is still time for the fork for
|
||||
# kill at the beginning of the production window for defproducera, so there is time for the fork for
|
||||
# defproducerc to grow before it would overtake the fork for defproducera and defproducerb
|
||||
killAtProducer="defproducerc"
|
||||
nonProdNode.killNodeOnProducer(producer=killAtProducer, whereInSequence=11)
|
||||
killAtProducer="defproducera"
|
||||
nonProdNode.killNodeOnProducer(producer=killAtProducer, whereInSequence=1)
|
||||
|
||||
#verify that the non producing node is not alive (and populate the producer nodes with current getInfo data to report if
|
||||
#an error occurs)
|
||||
@@ -143,7 +133,7 @@ try:
|
||||
while nonProdNode.verifyAlive() and count > 0:
|
||||
# wait on prodNode 0 since it will continue to advance, since defproducera and defproducerb are its producers
|
||||
Print("Wait for next block")
|
||||
assert prodNodes[0].waitForNextBlock(timeout=6), "Production node 0 should continue to advance, even after bridge node is killed"
|
||||
assert prodAB.waitForNextBlock(timeout=6), "Production node AB should continue to advance, even after bridge node is killed"
|
||||
count -= 1
|
||||
|
||||
assert not nonProdNode.verifyAlive(), "Bridge node should have been killed if test was functioning correctly."
|
||||
@@ -155,9 +145,9 @@ try:
|
||||
return status["state"]
|
||||
|
||||
transferAmount = 10
|
||||
prodNodes[1].transferFunds(cluster.eosioAccount, account1, f"{transferAmount}.0000 {CORE_SYMBOL}", "fund account")
|
||||
transId = prodNodes[1].getLastTrackedTransactionId()
|
||||
retStatus = prodNodes[1].getTransactionStatus(transId)
|
||||
prodC.transferFunds(cluster.eosioAccount, account1, f"{transferAmount}.0000 {CORE_SYMBOL}", "fund account")
|
||||
transId = prodC.getLastTrackedTransactionId()
|
||||
retStatus = prodC.getTransactionStatus(transId)
|
||||
state = getState(retStatus)
|
||||
|
||||
localState = "LOCALLY_APPLIED"
|
||||
@@ -169,21 +159,21 @@ try:
|
||||
assert state == localState, \
|
||||
f"ERROR: getTransactionStatus didn't return \"{localState}\" state.\n\nstatus: {json.dumps(retStatus, indent=1)}"
|
||||
|
||||
assert prodNodes[1].waitForNextBlock(), "Production node 1 should continue to advance, even after bridge node is killed"
|
||||
assert prodC.waitForNextBlock(), "Production node C should continue to advance, even after bridge node is killed"
|
||||
|
||||
# since the Bridge node is killed when this producer is producing its last block in its window, there is plenty of time for the transfer to be
|
||||
# sent before the first block is created, but adding this to ensure it is in one of these blocks
|
||||
numTries = 2
|
||||
preInfo = prodNodes[1].getInfo()
|
||||
preInfo = prodC.getInfo()
|
||||
while numTries > 0:
|
||||
retStatus = prodNodes[1].getTransactionStatus(transId)
|
||||
retStatus = prodC.getTransactionStatus(transId)
|
||||
state = getState(retStatus)
|
||||
if state == inBlockState:
|
||||
break
|
||||
numTries -= 1
|
||||
assert prodNodes[1].waitForNextBlock(), "Production node 1 should continue to advance, even after bridge node is killed"
|
||||
assert prodC.waitForNextBlock(), "Production node C should continue to advance, even after bridge node is killed"
|
||||
|
||||
postInfo = prodNodes[1].getInfo()
|
||||
postInfo = prodC.getInfo()
|
||||
|
||||
Print(f"getTransactionStatus returned status: {json.dumps(retStatus, indent=1)}")
|
||||
assert state == inBlockState, \
|
||||
@@ -195,42 +185,31 @@ try:
|
||||
if not nonProdNode.relaunch():
|
||||
errorExit(f"Failure - (non-production) node {nonProdNode.nodeNum} should have restarted")
|
||||
|
||||
Print("Wait for LIB to move, which indicates prodNode[1] has forked out the branch")
|
||||
assert prodNodes[1].waitForLibToAdvance(), \
|
||||
"ERROR: Network did not reach concensus after bridge node was restarted."
|
||||
Print("Wait for LIB to move, which indicates prodC has forked out the branch")
|
||||
assert prodC.waitForLibToAdvance(), \
|
||||
"ERROR: Network did not reach consensus after bridge node was restarted."
|
||||
|
||||
Print("Wait till prodNodes[1] is reporting at least the same head block number as the forked out block")
|
||||
assert prodNodes[1].waitForBlock(originalInBlockState["block_number"]), \
|
||||
f"Production node 1 should continue to advance after LIB starts advancing. \n\originalInBlockState: {json.dumps(originalInBlockState, indent=1)}"
|
||||
|
||||
retStatus = prodNodes[1].getTransactionStatus(transId)
|
||||
retStatus = prodC.getTransactionStatus(transId)
|
||||
state = getState(retStatus)
|
||||
|
||||
assert state == forkedOutState, \
|
||||
f"ERROR: getTransactionStatus didn't return \"{forkedOutState}\" state.\n\nstatus: {json.dumps(retStatus, indent=1)}" + \
|
||||
f"\n\nprod 0 info: {json.dumps(prodNodes[0].getInfo(), indent=1)}\n\nprod 1 info: {json.dumps(prodNodes[1].getInfo(), indent=1)}"
|
||||
f"\n\nprod AB info: {json.dumps(prodAB.getInfo(), indent=1)}\n\nprod C info: {json.dumps(prodC.getInfo(), indent=1)}"
|
||||
|
||||
for prodNode in prodNodes:
|
||||
info=prodNode.getInfo()
|
||||
Print(f"node info: {json.dumps(info, indent=1)}")
|
||||
|
||||
retStatus = prodNodes[1].getTransactionStatus(transId)
|
||||
state = getState(retStatus)
|
||||
assert prodC.waitForProducer("defproducerc"), \
|
||||
f"Waiting for prodC to produce, but it never happened" + \
|
||||
f"\n\nprod AB info: {json.dumps(prodAB.getInfo(), indent=1)}\n\nprod C info: {json.dumps(prodC.getInfo(), indent=1)}"
|
||||
|
||||
assert state == forkedOutState, \
|
||||
f"ERROR: getTransactionStatus didn't return \"{forkedOutState}\" state.\n\nstatus: {json.dumps(retStatus, indent=1)}" + \
|
||||
f"\n\nprod 0 info: {json.dumps(prodNodes[0].getInfo(), indent=1)}\n\nprod 1 info: {json.dumps(prodNodes[1].getInfo(), indent=1)}"
|
||||
|
||||
assert prodNodes[1].waitForProducer("defproducerc"), \
|
||||
f"Waiting for prodNode 1 to produce, but it never happened" + \
|
||||
f"\n\nprod 0 info: {json.dumps(prodNodes[0].getInfo(), indent=1)}\n\nprod 1 info: {json.dumps(prodNodes[1].getInfo(), indent=1)}"
|
||||
|
||||
retStatus = prodNodes[1].getTransactionStatus(transId)
|
||||
retStatus = prodC.getTransactionStatus(transId)
|
||||
state = getState(retStatus)
|
||||
|
||||
assert state == inBlockState, \
|
||||
f"ERROR: getTransactionStatus didn't return \"{inBlockState}\" state.\n\nstatus: {json.dumps(retStatus, indent=1)}" + \
|
||||
f"\n\nprod 0 info: {json.dumps(prodNodes[0].getInfo(), indent=1)}\n\nprod 1 info: {json.dumps(prodNodes[1].getInfo(), indent=1)}"
|
||||
f"\n\nprod AB info: {json.dumps(prodAB.getInfo(), indent=1)}\n\nprod C info: {json.dumps(prodC.getInfo(), indent=1)}"
|
||||
|
||||
afterForkInBlockState = retStatus
|
||||
afterForkBlockId = retStatus["block_id"]
|
||||
@@ -238,22 +217,22 @@ try:
|
||||
"ERROR: The way the test is designed, the transaction should be added to a block that has a higher number than it was in originally before it was forked out." + \
|
||||
f"\n\noriginal in block state: {json.dumps(originalInBlockState, indent=1)}\n\nafter fork in block state: {json.dumps(afterForkInBlockState, indent=1)}"
|
||||
|
||||
assert prodNodes[1].waitForBlock(afterForkInBlockState["block_number"], timeout=120, blockType=BlockType.lib), \
|
||||
f"ERROR: Block never finalized.\n\nprod 0 info: {json.dumps(prodNodes[0].getInfo(), indent=1)}\n\nprod 1 info: {json.dumps(prodNodes[1].getInfo(), indent=1)}" + \
|
||||
assert prodC.waitForBlock(afterForkInBlockState["block_number"], timeout=120, blockType=BlockType.lib), \
|
||||
f"ERROR: Block never finalized.\n\nprod AB info: {json.dumps(prodAB.getInfo(), indent=1)}\n\nprod C info: {json.dumps(prodC.getInfo(), indent=1)}" + \
|
||||
f"\n\nafter fork in block state: {json.dumps(afterForkInBlockState, indent=1)}"
|
||||
|
||||
retStatus = prodNodes[1].getTransactionStatus(transId)
|
||||
retStatus = prodC.getTransactionStatus(transId)
|
||||
if afterForkBlockId != retStatus["block_id"]: # might have been forked out, if so wait for new block to become LIB
|
||||
assert prodNodes[1].waitForBlock(retStatus["block_number"], timeout=120, blockType=BlockType.lib), \
|
||||
f"ERROR: Block never finalized.\n\nprod 0 info: {json.dumps(prodNodes[0].getInfo(), indent=1)}\n\nprod 1 info: {json.dumps(prodNodes[1].getInfo(), indent=1)}" + \
|
||||
assert prodC.waitForBlock(retStatus["block_number"], timeout=120, blockType=BlockType.lib), \
|
||||
f"ERROR: Block never finalized.\n\nprod AB info: {json.dumps(prodAB.getInfo(), indent=1)}\n\nprod C info: {json.dumps(prodC.getInfo(), indent=1)}" + \
|
||||
f"\n\nafter fork in block state: {json.dumps(afterForkInBlockState, indent=1)}"
|
||||
|
||||
retStatus = prodNodes[1].getTransactionStatus(transId)
|
||||
retStatus = prodC.getTransactionStatus(transId)
|
||||
state = getState(retStatus)
|
||||
|
||||
assert state == irreversibleState, \
|
||||
f"ERROR: getTransactionStatus didn't return \"{irreversibleState}\" state.\n\nstatus: {json.dumps(retStatus, indent=1)}" + \
|
||||
f"\n\nprod 0 info: {json.dumps(prodNodes[0].getInfo(), indent=1)}\n\nprod 1 info: {json.dumps(prodNodes[1].getInfo(), indent=1)}"
|
||||
f"\n\nprod AB info: {json.dumps(prodAB.getInfo(), indent=1)}\n\nprod C info: {json.dumps(prodC.getInfo(), indent=1)}"
|
||||
|
||||
testSuccessful=True
|
||||
finally:
|
||||
|
||||
@@ -142,7 +142,7 @@ try:
|
||||
state = getState(retStatus)
|
||||
|
||||
assert (state == localState or state == inBlockState), \
|
||||
f"ERROR: getTransactionStatus didn't return \"{localState}\" state.\n\nstatus: {json.dumps(retStatus, indent=1)}"
|
||||
f"ERROR: getTransactionStatus didn't return \"{localState}\" or \"{inBlockState}\" state.\n\nstatus: {json.dumps(retStatus, indent=1)}"
|
||||
status.append(copy.copy(retStatus))
|
||||
startingBlockNum=testNode.getInfo()["head_block_num"]
|
||||
|
||||
@@ -150,12 +150,13 @@ try:
|
||||
bnPresent = "block_number" in status
|
||||
biPresent = "block_id" in status
|
||||
btPresent = "block_timestamp" in status
|
||||
desc = "" if present else "not "
|
||||
desc = "" if present else " not"
|
||||
group = bnPresent and biPresent and btPresent if present else not bnPresent and not biPresent and not btPresent
|
||||
assert group, \
|
||||
f"ERROR: getTransactionStatus should{desc} contain \"block_number\", \"block_id\", or \"block_timestamp\" since state was \"{getState(status)}\".\nstatus: {json.dumps(status, indent=1)}"
|
||||
|
||||
validateTrxState(status[0], present=False)
|
||||
present = True if state == inBlockState else False
|
||||
validateTrxState(status[0], present)
|
||||
|
||||
def validate(status, knownTrx=True):
|
||||
assert "head_number" in status and "head_id" in status and "head_timestamp" in status, \
|
||||
|
||||
@@ -1152,8 +1152,8 @@ BOOST_AUTO_TEST_CASE(checktime_pause_block_deadline_not_extended_test) { try {
|
||||
dlog("elapsed ${e}us", ("e", dur) );
|
||||
BOOST_CHECK( dur >= 75'000 ); // should never fail
|
||||
// If this check fails but duration is >= 75'000 (previous check did not fail), then the check here is likely
|
||||
// because it took longer than 2 ms for checktime to trigger, trace to be created, and to get to the now() call.
|
||||
BOOST_CHECK_MESSAGE( dur < 77'000, "elapsed " << dur << "us" );
|
||||
// because it took longer than 10 ms for checktime to trigger, trace to be created, and to get to the now() call.
|
||||
BOOST_CHECK_MESSAGE( dur < 85'000, "elapsed " << dur << "us" );
|
||||
|
||||
BOOST_REQUIRE_EQUAL( t.validate(), true );
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace {
|
||||
}
|
||||
|
||||
template <typename SNAPSHOT_SUITE>
|
||||
void verify_integrity_hash(const controller& lhs, const controller& rhs) {
|
||||
void verify_integrity_hash(controller& lhs, controller& rhs) {
|
||||
const auto lhs_integrity_hash = lhs.calculate_integrity_hash();
|
||||
const auto rhs_integrity_hash = rhs.calculate_integrity_hash();
|
||||
if (std::is_same_v<SNAPSHOT_SUITE, variant_snapshot_suite> && lhs_integrity_hash.str() != rhs_integrity_hash.str()) {
|
||||
|
||||
Reference in New Issue
Block a user