Compare commits

...

102 Commits

Author SHA1 Message Date
Lin Huang 95077ed429 Bump Leap to release/3.1.5 2023-07-12 09:25:47 -04:00
Lin Huang 05e6cc8c18 Update eos-vm to release/3.x 2023-07-12 09:25:10 -04:00
Lin Huang 5caf5833ad A companion Leap changes for fixing WASM memory exhaustion 2023-07-12 09:18:25 -04:00
Peter Oschwald ed854f2bbd Merge pull request #1291 from AntelopeIO/pinned-builds-workflow-in-ci
[3.1] Pinned Builds manual dispatch workflow in CI
2023-06-22 11:38:59 -05:00
Peter Oschwald e3976b8dc1 Merge pull request #1310 from AntelopeIO/pinned_build_install_prefix_knob
[3.1] `CMAKE_INSTALL_PREFIX=/usr` for pinned builds in CI
2023-06-22 10:59:43 -05:00
Peter Oschwald 02c43ca656 Use enf-x86-beefy-long runner 2023-06-22 09:30:09 -05:00
Peter Oschwald 1ec98976b1 Try newly added self hosted runner for pinned builds. 2023-06-16 14:42:43 -05:00
Peter Oschwald 93833b8e03 Simplify naming and path matching for artifact. 2023-06-16 14:14:55 -05:00
Matt Witherspoon d6cd2c9a7d LEAP_PINNED_INSTALL_PREFIX knob to set pinned_build.sh CMAKE_INSTALL_PREFIX 2023-06-15 22:37:09 -04:00
Peter Oschwald ae2679e164 Cleanup. 2023-06-15 16:13:03 -05:00
Peter Oschwald 0f25eaa33a Remove quotes from path for upload. 2023-06-15 14:13:06 -05:00
Peter Oschwald b7b4554a18 Fix spelling causing issue with GITHUB_ENV. And trying again to get artifact name correctly. 2023-06-15 12:35:43 -05:00
Peter Oschwald 20e59a92bc Not finding deb packages. check dir structure some more. 2023-06-15 10:49:04 -05:00
Peter Oschwald 31fd1361aa Something is not matching up with expected dir or file structure. 2023-06-15 08:00:00 -05:00
Peter Oschwald 449f37133b Skip wildcards in upload-artifact and capture artifact name with regex grep and store in env variable. 2023-06-14 16:44:42 -05:00
Peter Oschwald feeee5eb8f Say yes. 2023-06-14 15:37:38 -05:00
Peter Oschwald 32de87b185 Update package lists first. 2023-06-14 15:35:28 -05:00
Peter Oschwald 78dd785035 Need software-properties-common and a apt-get update to get add-apt-repository to work. 2023-06-14 15:34:06 -05:00
Peter Oschwald f4b39ea29e Use single quotes. 2023-06-14 15:30:35 -05:00
Peter Oschwald 20f45e5923 Add conditional step to add updated apt repository for git.
Ubuntu 18.04 installs  git 2.17.1, but need 2.18+ for git submodules to work.
2023-06-14 15:27:18 -05:00
Peter Oschwald fc2166a46d Merge branch 'init-pinned-builds-workflow-in-ci' into pinned-builds-workflow-in-ci 2023-06-14 13:58:18 -05:00
Peter Oschwald 39a5ba846a Have to have a job for github. Add temp job. 2023-06-14 13:57:00 -05:00
Peter Oschwald e4b28a7854 Remove empty jobs section. 2023-06-14 13:54:13 -05:00
Peter Oschwald e4819c35e1 Merge branch 'init-pinned-builds-workflow-in-ci' into pinned-builds-workflow-in-ci 2023-06-14 13:51:11 -05:00
Peter Oschwald 7b7027cbee Not using cached build environments so removing this job. 2023-06-14 13:49:33 -05:00
Peter Oschwald 74fb1615d8 Add pinned to artifact name and don't upload dev artifact by filtering out in regex. 2023-06-14 13:02:32 -05:00
Peter Oschwald 5523010cfd Fix syntax and forgotten run command. 2023-06-14 13:00:00 -05:00
Peter Oschwald 7c106605cc Not using cached build environments so removing this job. 2023-06-14 12:16:11 -05:00
Peter Oschwald 9047d1175b For now run on github runner. 2023-06-14 12:05:12 -05:00
Peter Oschwald da6a068639 Script already runs cpack, remove. Break artifact check into own step for easier removal in future. 2023-06-14 12:03:27 -05:00
Peter Oschwald a886743005 Initial work to run pinned_build script on base images.
Build package and upload artifacts.
2023-06-14 11:44:53 -05:00
Peter Oschwald 0dbfb1a6ed Creating a shell of the initial pinned_build.yaml workflow to be merged quickly allowing development of actual workflow in follow on branch.
Need to have workflow file merged before github will allow triggering it in a development branch.
2023-06-14 11:26:08 -05:00
Huang-Ming Huang 9d1ea27ed7 Merge pull request #777 from AntelopeIO/huangminghuang/strike-rule
[3.1] subjective-account-max-failures-window-size
2023-03-07 08:19:34 -06:00
Huang-Ming Huang 71548a6425 Merge branch 'release/3.1' into huangminghuang/strike-rule 2023-03-06 09:37:22 -06:00
Huang-Ming Huang 72c5d299fe add reset time until back 2023-03-06 09:12:30 -06:00
Huang-Ming Huang 5cf31c9929 address PR comment 2023-03-06 08:21:26 -06:00
Kevin Heifner 941b525093 Merge pull request #773 from AntelopeIO/GH-768-logging-3.1
[3.1] Move subjective bill log to `all` level of `producer_plugin` logger.
2023-03-04 13:42:53 -06:00
Kevin Heifner e377339f04 GH-768 Move subjective bill log to all level of producer_plugin logger. 2023-03-03 07:10:23 -06:00
Huang-Ming Huang fcbdb0ae98 subjective-account-max-failures-window-size 2023-03-01 06:13:02 -06:00
Gregory Popovitch ecc5c4ec11 Merge pull request #754 from AntelopeIO/gh-513_rel3.1
[3.1] keosd - Exit program if keosd fails to aquire wallet lock (GH #513)
2023-02-27 10:39:15 -05:00
greg7mdp caa01ca443 main() should return if appbase initialization fails. 2023-02-25 14:39:25 -05:00
Alexander Molchevsky 3e585d0f8a Merge pull request #747 from AntelopeIO/update_bios_boot_tutorial3.1
Backport to 3.1 of bootstrap new protocol features activation
2023-02-24 12:38:21 +02:00
Alexander Molchevsky 967ab869e0 Backport to 3.1 of bootstrap new protocol features activation 2023-02-24 00:42:48 +02:00
Kevin Heifner 0d977585ce Merge pull request #700 from AntelopeIO/GH-695-dirty-db-3.1
[3.1] Fix reporting of dirty db
2023-02-10 08:15:54 -06:00
Kevin Heifner a357765c73 GH-695 Report dirty-db correctly 2023-02-08 08:07:14 -06:00
766C6164 280d799958 Added comment on why non-propagating system_error 2023-02-08 08:03:43 -06:00
766C6164 f694588f9f Propagate all exceptions minus system_error 2023-02-08 08:03:38 -06:00
Kevin Heifner 26025d7382 Merge pull request #684 from AntelopeIO/GH-662-terminate-at-block-3.1
[3.1] Fix --terminate-at-block to stop at correct block
2023-02-04 15:17:10 -06:00
Kevin Heifner 517ef20396 GH-662 Fixes for terminate-scenarios-test 2023-02-03 16:01:08 -06:00
Kevin Heifner 6f16383453 GH-662 Fix terminate-at-block test 2023-02-03 14:10:57 -06:00
Kevin Heifner debba62dd8 GH-662 Fix terminate-at-block to terminate at correct block 2023-02-03 14:10:38 -06:00
Kevin Heifner 343596a0c1 Merge pull request #676 from AntelopeIO/GH-588-handshake-3.1
[3.1] net_plugin improve block latency calculation
2023-02-02 14:47:12 -06:00
Kevin Heifner ec27d3d1f3 GH-588 Round using lround instead of the original hardcoded +1 2023-02-01 15:10:23 -06:00
Kevin Heifner f347ab534e GH-588 Add additional logging that would be helpful for debugging 2023-02-01 13:42:13 -06:00
Kevin Heifner 3db765e0f1 GH-588 Remove +1 to number of blocks latency calculation. With it 0 latency indicates 1 block latency. 2023-01-31 07:44:20 -06:00
Kevin Heifner 0dbd5cf68c Merge pull request #667 from AntelopeIO/GH-631-fork-test-3.1
[3.1] Test fix: nodeos_forked_chain_lr_test
2023-01-27 13:30:03 -06:00
Kevin Heifner da2a1dc996 GH-631 Update preKill info since waiting for producer to change before continuing. 2023-01-26 13:29:19 -06:00
Lin Huang 78973e4088 Merge pull request #651 from AntelopeIO/bump_to_3_1_4
bump Leap release to 3.1.4
2023-01-19 10:11:38 -05:00
Lin Huang d627a18e8e bump Leap release to 3.1.4 2023-01-19 09:27:35 -05:00
Kevin Heifner be7fc5714e Merge pull request #543 from AntelopeIO/GH-525-block-propagation-3.1
[3.1] Interrupt speculative start_block when a block is received
2023-01-18 12:13:35 -06:00
Kevin Heifner 2d6307b37e GH-525 rename start_block_interrupted to should_interrupt_start_block 2023-01-10 13:09:57 -06:00
Kevin Heifner 3d77eb001b GH-525 Add check for existing to be consistent 2023-01-10 13:09:04 -06:00
Kevin Heifner ef9b3ea1b6 Merge branch 'release/3.1' into GH-525-block-propagation-3.1 2023-01-10 07:00:41 -06:00
Kevin Heifner 943d113480 Merge pull request #606 from AntelopeIO/GH-605-dup-sync-stop-3.1
[3.1] Attempt connection retry for duplicate connections
2023-01-05 08:23:05 -06:00
Kevin Heifner 34b185d49b Merge branch 'release/3.1' into GH-605-dup-sync-stop-3.1 2022-12-30 10:42:56 -06:00
Kevin Heifner 79e99ad605 GH-605 Remove no_retry code from connect that was already in resolve_and_connect. connect is only called by resolve_and_connect. The no_retry code in connect didn't have the newly added re-connect for duplicate. 2022-12-30 10:37:31 -06:00
Luis Paris 6c9012874b Merge pull request #583 from AntelopeIO/fix-devrel#60b
[3.1] Update nodeos options help usage [docs]
2022-12-23 15:29:53 -05:00
Eric Passmore 278b94baf7 Merge pull request #569 from AntelopeIO/ehp/GH-547-producer-api-doc-cleanup-3.1
[3.1] Fixes Producer Plugin Schema Fixes and Better Alignment with OpenAPI spec
2022-12-19 17:06:02 -08:00
Eric Passmore 20b1da2b47 removed datatypes from descriptions 2022-12-19 13:45:24 -08:00
Luis 82ef97bf4e rename eos.io to example.org in net plugin help :doc 2022-12-19 16:23:27 -05:00
Luis cca0dc306e remove unsupported history plugin docs :doc 2022-12-19 14:57:45 -05:00
Luis 897edb9d9f update state history plugin options :doc 2022-12-19 14:56:06 -05:00
Luis f7c6b63cf7 update resource monitor plugin options and minor edits :doc 2022-12-19 14:54:09 -05:00
Luis 32d7d9f9fd update producer plugin options and minor edits :doc 2022-12-19 14:50:46 -05:00
Luis 97737fdd86 update net plugin options :doc 2022-12-19 14:47:12 -05:00
Luis 7a5930bb66 update http plugin options :doc 2022-12-19 14:45:17 -05:00
Luis 51d9cc22d7 update chain plugin options :doc 2022-12-19 14:33:22 -05:00
Luis ee1b184428 fix another small type that slipped :doc 2022-12-16 16:52:05 -05:00
Luis d34c40bd68 fix minor sentence contructions :doc 2022-12-16 16:36:47 -05:00
Luis a3bf1f54a1 minor edits and spelling corrections :doc 2022-12-16 16:33:15 -05:00
Kevin Heifner 9b5ec62e19 GH-525 Remove unused incoming::channels::transaction 2022-12-16 08:39:38 -06:00
Kevin Heifner 453e5d0975 GH-525 Add open_impl/close_impl so all methods of fork_database follow the same pattern. 2022-12-15 18:39:28 -06:00
Kevin Heifner 8f12805b4c GH-525 Minor cleanup from PR comments. 2022-12-15 15:12:10 -06:00
Kevin Heifner 9b1401aa4a GH-525 Only interrupt start_block for validated block_header. 2022-12-15 09:23:10 -06:00
Kevin Heifner b3391af3bf GH-525 Use shared_mutex to allow multiple readers 2022-12-15 08:15:44 -06:00
Kevin Heifner d0d7fa798b GH-525 Move scope_exit of schedule_production_loop since any call should restart block because speculative block may have been interrupted. 2022-12-15 08:15:32 -06:00
Kevin Heifner 7468dede46 GH-525 Remove unused block channel. 2022-12-15 08:15:17 -06:00
Kevin Heifner 43d45edb01 GH-525 Make forkdb thread-safe 2022-12-15 08:14:57 -06:00
Eric Passmore 76a341e52c updated version tag 2022-12-14 03:23:46 -08:00
Eric Passmore b0ea27b449 paused returns boolean, pause does not 2022-12-14 02:20:53 -08:00
Eric Passmore 16c8021e93 added 4xx return codes as required by redocly linter 2022-12-13 12:50:22 -08:00
Eric Passmore 266175a940 fixed component paths on openapi docs 2022-12-13 11:25:32 -08:00
Eric Passmore 1bd84d8447 fixes producer plugin docs 2022-12-13 03:22:36 -08:00
Kevin Heifner 40a7e34d14 GH-525 Honor deadline if we can produce 2022-12-12 08:58:59 -06:00
Kevin Heifner 82829648ba Merge pull request #541 from AntelopeIO/GH-535-trace-api-3.1
[3.1] Do not run maintenance task on shutdown
2022-12-09 06:19:17 -06:00
Kevin Heifner e63482a75e GH-525 Minor cleanup 2022-12-08 19:05:57 -06:00
Kevin Heifner 8027ecb367 GH-525 Fixed spelling of yield 2022-12-08 17:25:46 -06:00
Kevin Heifner 1f44c07cd8 GH-525 Use received block as interrupt for start_block when in speculative mode. Use deadline when in production mode. 2022-12-08 16:54:23 -06:00
Kevin Heifner 0103412fe7 GH-525 Interrupt speculative start_block when a block is received 2022-12-06 14:09:15 -06:00
Kevin Heifner 051f8fd186 Merge branch 'release/3.1' into GH-535-trace-api-3.1 2022-12-06 11:30:52 -06:00
Kevin Heifner 57b0acb59c GH-535 Add log of shutdown complete. 2022-12-06 09:54:01 -06:00
Kevin Heifner 2c4d19902c GH-535 Do not run maintenance task on shutdown 2022-12-06 09:41:55 -06:00
43 changed files with 1169 additions and 904 deletions
+58
View File
@@ -0,0 +1,58 @@
name: "Pinned Build"
on:
workflow_dispatch:
permissions:
packages: read
contents: read
defaults:
run:
shell: bash
jobs:
Build:
name: Build
strategy:
fail-fast: false
matrix:
platform: [ubuntu18, ubuntu20, ubuntu22]
runs-on: ["self-hosted", "enf-x86-beefy-long"]
container: ${{ matrix.platform == 'ubuntu18' && 'ubuntu:bionic' || matrix.platform == 'ubuntu20' && 'ubuntu:focal' || 'ubuntu:jammy' }}
steps:
- name: Conditionally update git repo
if: ${{ matrix.platform == 'ubuntu18' }}
run: |
apt-get update
apt-get install -y software-properties-common
apt-get update
add-apt-repository ppa:git-core/ppa
- name: Update and Install git
run: |
apt-get update
apt-get install -y git
git --version
- name: Clone leap
uses: actions/checkout@v3
with:
submodules: recursive
- name: Install dependencies
run: |
# https://github.com/actions/runner/issues/2033
chown -R $(id -u):$(id -g) $PWD
./scripts/install_deps.sh
- name: Build Pinned Build
env:
LEAP_PINNED_INSTALL_PREFIX: /usr
run: |
./scripts/pinned_build.sh deps build "$(nproc)"
- name: Upload package
uses: actions/upload-artifact@v3
with:
name: leap-${{matrix.platform}}-pinned-amd64
path: build/leap-3*.deb
- name: Run Parallel Tests
run: |
cd build
ctest --output-on-failure -j $(nproc) -LE "(nonparallelizable_tests|long_running_tests)" --timeout 420
+1 -1
View File
@@ -15,7 +15,7 @@ set( CXX_STANDARD_REQUIRED ON)
set(VERSION_MAJOR 3)
set(VERSION_MINOR 1)
set(VERSION_PATCH 3)
set(VERSION_PATCH 5)
#set(VERSION_SUFFIX rc4)
if(VERSION_SUFFIX)
+113 -103
View File
@@ -21,33 +21,35 @@ These can only be specified from the `nodeos` command-line:
```console
Command Line Options for eosio::chain_plugin:
--genesis-json arg File to read Genesis State from
--genesis-timestamp arg override the initial timestamp in the
--genesis-timestamp arg override the initial timestamp in the
Genesis State file
--print-genesis-json extract genesis_state from blocks.log
--print-genesis-json extract genesis_state from blocks.log
as JSON, print to console, and exit
--extract-genesis-json arg extract genesis_state from blocks.log
--extract-genesis-json arg extract genesis_state from blocks.log
as JSON, write into specified file, and
exit
--print-build-info print build environment information to
--print-build-info print build environment information to
console as JSON and exit
--extract-build-info arg extract build environment information
--extract-build-info arg extract build environment information
as JSON, write into specified file, and
exit
--force-all-checks do not skip any checks that can be
skipped while replaying irreversible
blocks
--force-all-checks do not skip any validation checks while
replaying blocks (useful for replaying
blocks from untrusted source)
--disable-replay-opts disable optimizations that specifically
target replay
--replay-blockchain clear chain state database and replay
--replay-blockchain clear chain state database and replay
all blocks
--hard-replay-blockchain clear chain state database, recover as
many blocks as possible from the block
--hard-replay-blockchain clear chain state database, recover as
many blocks as possible from the block
log, and then replay those blocks
--delete-all-blocks clear chain state database and block
--delete-all-blocks clear chain state database and block
log
--truncate-at-block arg (=0) stop hard replay / block log recovery
at this block number (if set to
--truncate-at-block arg (=0) stop hard replay / block log recovery
at this block number (if set to
non-zero number)
--terminate-at-block arg (=0) terminate after reaching this block
number (if set to a non-zero number)
--snapshot arg File to read Snapshot State from
```
@@ -58,162 +60,170 @@ These can be specified from both the `nodeos` command-line or the `config.ini` f
```console
Config Options for eosio::chain_plugin:
--blocks-dir arg (="blocks") the location of the blocks directory
(absolute path or relative to
--blocks-dir arg (="blocks") the location of the blocks directory
(absolute path or relative to
application data dir)
--protocol-features-dir arg (="protocol_features")
the location of the protocol_features
the location of the protocol_features
directory (absolute path or relative to
application config dir)
--checkpoint arg Pairs of [BLOCK_NUM,BLOCK_ID] that
--checkpoint arg Pairs of [BLOCK_NUM,BLOCK_ID] that
should be enforced as checkpoints.
--wasm-runtime runtime (=eos-vm-jit) Override default WASM runtime (
--wasm-runtime runtime (=eos-vm-jit) Override default WASM runtime (
"eos-vm-jit", "eos-vm")
"eos-vm-jit" : A WebAssembly runtime
that compiles WebAssembly code to
"eos-vm-jit" : A WebAssembly runtime
that compiles WebAssembly code to
native x86 code prior to execution.
"eos-vm" : A WebAssembly interpreter.
--profile-account arg The name of an account whose code will
--profile-account arg The name of an account whose code will
be profiled
--abi-serializer-max-time-ms arg (=15)
Override default maximum ABI
Override default maximum ABI
serialization time allowed in ms
--chain-state-db-size-mb arg (=1024) Maximum size (in MiB) of the chain
--chain-state-db-size-mb arg (=1024) Maximum size (in MiB) of the chain
state database
--chain-state-db-guard-size-mb arg (=128)
Safely shut down node when free space
remaining in the chain state database
Safely shut down node when free space
remaining in the chain state database
drops below this size (in MiB).
--signature-cpu-billable-pct arg (=50)
Percentage of actual signature recovery
cpu to bill. Whole number percentages,
cpu to bill. Whole number percentages,
e.g. 50 for 50%
--chain-threads arg (=2) Number of worker threads in controller
--chain-threads arg (=2) Number of worker threads in controller
thread pool
--contracts-console print contract's output to console
--deep-mind print deeper information about chain
--deep-mind print deeper information about chain
operations
--actor-whitelist arg Account added to actor whitelist (may
--actor-whitelist arg Account added to actor whitelist (may
specify multiple times)
--actor-blacklist arg Account added to actor blacklist (may
--actor-blacklist arg Account added to actor blacklist (may
specify multiple times)
--contract-whitelist arg Contract account added to contract
--contract-whitelist arg Contract account added to contract
whitelist (may specify multiple times)
--contract-blacklist arg Contract account added to contract
--contract-blacklist arg Contract account added to contract
blacklist (may specify multiple times)
--action-blacklist arg Action (in the form code::action) added
to action blacklist (may specify
to action blacklist (may specify
multiple times)
--key-blacklist arg Public key added to blacklist of keys
that should not be included in
authorities (may specify multiple
--key-blacklist arg Public key added to blacklist of keys
that should not be included in
authorities (may specify multiple
times)
--sender-bypass-whiteblacklist arg Deferred transactions sent by accounts
in this list do not have any of the
subjective whitelist/blacklist checks
applied to them (may specify multiple
--sender-bypass-whiteblacklist arg Deferred transactions sent by accounts
in this list do not have any of the
subjective whitelist/blacklist checks
applied to them (may specify multiple
times)
--read-mode arg (=speculative) Database read mode ("speculative",
--read-mode arg (=speculative) Database read mode ("speculative",
"head", "read-only", "irreversible").
In "speculative" mode: database
contains state changes by transactions
in the blockchain up to the head block
as well as some transactions not yet
In "speculative" mode: database
contains state changes by transactions
in the blockchain up to the head block
as well as some transactions not yet
included in the blockchain.
In "head" mode: database contains state
changes by only transactions in the
blockchain up to the head block;
transactions received by the node are
changes by only transactions in the
blockchain up to the head block;
transactions received by the node are
relayed if valid.
In "read-only" mode: (DEPRECATED: see
p2p-accept-transactions &
api-accept-transactions) database
contains state changes by only
transactions in the blockchain up to
the head block; transactions received
In "read-only" mode: (DEPRECATED: see
p2p-accept-transactions &
api-accept-transactions) database
contains state changes by only
transactions in the blockchain up to
the head block; transactions received
via the P2P network are not relayed and
transactions cannot be pushed via the
transactions cannot be pushed via the
chain API.
In "irreversible" mode: database
contains state changes by only
transactions in the blockchain up to
the last irreversible block;
transactions received via the P2P
network are not relayed and
transactions cannot be pushed via the
In "irreversible" mode: database
contains state changes by only
transactions in the blockchain up to
the last irreversible block;
transactions received via the P2P
network are not relayed and
transactions cannot be pushed via the
chain API.
--api-accept-transactions arg (=1) Allow API transactions to be evaluated
--api-accept-transactions arg (=1) Allow API transactions to be evaluated
and relayed if valid.
--validation-mode arg (=full) Chain validation mode ("full" or
--validation-mode arg (=full) Chain validation mode ("full" or
"light").
In "full" mode all incoming blocks will
be fully validated.
In "light" mode all incoming blocks
headers will be fully validated;
transactions in those validated blocks
will be trusted
--disable-ram-billing-notify-checks Disable the check which subjectively
In "light" mode all incoming blocks
headers will be fully validated;
transactions in those validated blocks
will be trusted
--disable-ram-billing-notify-checks Disable the check which subjectively
fails a transaction if a contract bills
more RAM to another account within the
more RAM to another account within the
context of a notification handler (i.e.
when the receiver is not the code of
when the receiver is not the code of
the action).
--maximum-variable-signature-length arg (=16384)
Subjectively limit the maximum length
of variable components in a variable
Subjectively limit the maximum length
of variable components in a variable
legnth signature to this size in bytes
--trusted-producer arg Indicate a producer whose blocks
headers signed by it will be fully
validated, but transactions in those
--trusted-producer arg Indicate a producer whose blocks
headers signed by it will be fully
validated, but transactions in those
validated blocks will be trusted.
--database-map-mode arg (=mapped) Database map mode ("mapped", "heap", or
"locked").
In "mapped" mode database is memory
In "mapped" mode database is memory
mapped as a file.
In "heap" mode database is preloaded in
to swappable memory and will use huge
to swappable memory and will use huge
pages if available.
In "locked" mode database is preloaded,
locked in to memory, and will use huge
locked in to memory, and will use huge
pages if available.
--enable-account-queries arg (=0) enable queries to find accounts by
--eos-vm-oc-cache-size-mb arg (=1024) Maximum size (in MiB) of the EOS VM OC
code cache
--eos-vm-oc-compile-threads arg (=1) Number of threads to use for EOS VM OC
tier-up
--eos-vm-oc-enable Enable EOS VM OC tier-up runtime
--enable-account-queries arg (=0) enable queries to find accounts by
various metadata.
--max-nonprivileged-inline-action-size arg (=4096)
maximum allowed size (in bytes) of an
inline action for a nonprivileged
maximum allowed size (in bytes) of an
inline action for a nonprivileged
account
--transaction-retry-max-storage-size-gb arg
Maximum size (in GiB) allowed to be
allocated for the Transaction Retry
feature. Setting above 0 enables this
Maximum size (in GiB) allowed to be
allocated for the Transaction Retry
feature. Setting above 0 enables this
feature.
--transaction-retry-interval-sec arg (=20)
How often, in seconds, to resend an
incoming transaction to network if not
How often, in seconds, to resend an
incoming transaction to network if not
seen in a block.
--transaction-retry-max-expiration-sec arg (=90)
Maximum allowed transaction expiration
for retry transactions, will retry
--transaction-retry-max-expiration-sec arg (=120)
Maximum allowed transaction expiration
for retry transactions, will retry
transactions up to this value.
--transaction-finality-status-max-storage-size-gb arg
Maximum size (in GiB) allowed to be
allocated for the Transaction Finality
Maximum size (in GiB) allowed to be
allocated for the Transaction Finality
Status feature. Setting above 0 enables
this feature.
--transaction-finality-status-success-duration-sec arg (=180)
Duration (in seconds) a successful
transaction's Finality Status will
remain available from being first
Duration (in seconds) a successful
transaction's Finality Status will
remain available from being first
identified.
--transaction-finality-status-failure-duration-sec arg (=180)
Duration (in seconds) a failed
transaction's Finality Status will
remain available from being first
Duration (in seconds) a failed
transaction's Finality Status will
remain available from being first
identified.
--block-log-retain-blocks arg if set, periodically prune the block
log to store only configured number of
most recent blocks
```
@@ -1,59 +0,0 @@
[[warning | Deprecation Notice]]
| The `history_plugin` that the `history_api_plugin` depends upon is deprecated and will no longer be maintained. Please use the [`state_history_plugin`](../state_history_plugin/index.md) instead.
## Description
The `history_api_plugin` exposes functionality from the [`history_plugin`](../history_plugin/index.md) to the RPC API interface managed by the [`http_plugin`](../http_plugin/index.md), providing read-only access to blockchain data.
It provides four RPC API endpoints:
* get_actions
* get_transaction
* get_key_accounts
* get_controlled_accounts
The four actions listed above are used by the following `cleos` commands (matching order):
* get actions
* get transaction
* get accounts
* get servants
## Usage
```console
# config.ini
plugin = eosio::history_api_plugin
```
```sh
# command-line
nodeos ... --plugin eosio::history_api_plugin
```
## Options
None
## Dependencies
* [`history_plugin`](../history_plugin/index.md)
* [`chain_plugin`](../chain_plugin/index.md)
* [`http_plugin`](../http_plugin/index.md)
### Load Dependency Examples
```console
# config.ini
plugin = eosio::history_plugin
[options]
plugin = eosio::chain_plugin
[options]
plugin = eosio::http_plugin
[options]
```
```sh
# command-line
nodeos ... --plugin eosio::history_plugin [options] \
--plugin eosio::chain_plugin [operations] [options] \
--plugin eosio::http_plugin [options]
```
@@ -1,41 +0,0 @@
[[warning | Deprecation Notice]]
| The `history_plugin` is deprecated and will no longer be maintained. Please use the [`state_history_plugin`](../state_history_plugin/index.md) instead.
## Description
The `history_plugin` provides a cache layer to obtain historical data about the blockchain objects. It depends on [`chain_plugin`](../chain_plugin/index.md) for the data.
## Usage
```console
# config.ini
plugin = eosio::history_plugin
[options]
```
```sh
# command-line
nodeos ... --plugin eosio::history_plugin [options]
```
## Options
These can be specified from both the `nodeos` command-line or the `config.ini` file:
```console
Config Options for eosio::history_plugin:
-f [ --filter-on ] arg Track actions which match
receiver:action:actor. Actor may be
blank to include all. Action and Actor
both blank allows all from Recieiver.
Receiver may not be blank.
-F [ --filter-out ] arg Do not track actions which match
receiver:action:actor. Action and Actor
both blank excludes all from Reciever.
Actor blank excludes all from
reciever:action. Receiver may not be
blank.
```
## Dependencies
* [`chain_plugin`](../chain_plugin/index.md)
+23 -22
View File
@@ -22,46 +22,47 @@ These can be specified from both the command-line or the `config.ini` file:
```console
Config Options for eosio::http_plugin:
--unix-socket-path arg The filename (relative to data-dir) to
create a unix socket for HTTP RPC; set
blank to disable (=keosd.sock for keosd)
--http-server-address arg (=127.0.0.1:8888 for nodeos)
The local IP and port to listen for
--unix-socket-path arg The filename (relative to data-dir) to
create a unix socket for HTTP RPC; set
blank to disable.
--http-server-address arg (=127.0.0.1:8888)
The local IP and port to listen for
incoming http connections; set blank to
disable.
--https-server-address arg The local IP and port to listen for
--https-server-address arg The local IP and port to listen for
incoming https connections; leave blank
to disable.
--https-certificate-chain-file arg Filename with the certificate chain to
present on https connections. PEM
--https-certificate-chain-file arg Filename with the certificate chain to
present on https connections. PEM
format. Required for https.
--https-private-key-file arg Filename with https private key in PEM
--https-private-key-file arg Filename with https private key in PEM
format. Required for https
--https-ecdh-curve arg (=secp384r1) Configure https ECDH curve to use:
--https-ecdh-curve arg (=secp384r1) Configure https ECDH curve to use:
secp384r1 or prime256v1
--access-control-allow-origin arg Specify the Access-Control-Allow-Origin
to be returned on each request.
--access-control-allow-headers arg Specify the Access-Control-Allow-Header
s to be returned on each request.
--access-control-max-age arg Specify the Access-Control-Max-Age to
--access-control-max-age arg Specify the Access-Control-Max-Age to
be returned on each request.
--access-control-allow-credentials Specify if Access-Control-Allow-Credent
ials: true should be returned on each
ials: true should be returned on each
request.
--max-body-size arg (=1048576) The maximum body size in bytes allowed
--max-body-size arg (=2097152) The maximum body size in bytes allowed
for incoming RPC requests
--http-max-bytes-in-flight-mb arg (=500)
Maximum size in megabytes http_plugin
should use for processing http
requests. 503 error response when
exceeded.
Maximum size in megabytes http_plugin
should use for processing http
requests. -1 for unlimited. 429 error
response when exceeded.
--http-max-response-time-ms arg (=30) Maximum time for processing a request.
--verbose-http-errors Append the error log to HTTP responses
--http-validate-host arg (=1) If set to false, then any incoming
--http-validate-host arg (=1) If set to false, then any incoming
"Host" header is considered valid
--http-alias arg Additionaly acceptable values for the
"Host" header of incoming HTTP
requests, can be specified multiple
times. Includes http/s_server_address
--http-alias arg Additionaly acceptable values for the
"Host" header of incoming HTTP
requests, can be specified multiple
times. Includes http/s_server_address
by default.
--http-threads arg (=2) Number of worker threads in http thread
pool
@@ -44,7 +44,7 @@ Config Options for eosio::net_plugin:
--p2p-accept-transactions arg (=1) Allow transactions received over p2p
network to be evaluated and relayed if
valid.
--agent-name arg (="EOS Test Agent") The name supplied to identify this node
--agent-name arg (=EOS Test Agent) The name supplied to identify this node
amongst the peers.
--allowed-connection arg (=any) Can be 'any' or 'producers' or
'specified' or 'none'. If 'specified',
@@ -73,13 +73,15 @@ Config Options for eosio::net_plugin:
synchronization
--use-socket-read-watermark arg (=0) Enable experimental socket read
watermark optimization
--peer-log-format arg (=["${_name}" ${_ip}:${_port}])
--peer-log-format arg (=["${_name}" - ${_cid} ${_ip}:${_port}] )
The string used to format peers when
logging messages about them. Variables
are escaped with ${<variable name>}.
Available Variables:
_name self-reported name
_cid assigned connection id
_id self-reported ID (64 hex
characters)
@@ -94,7 +96,10 @@ Config Options for eosio::net_plugin:
peer
_lport local port number connected
to peer
to peer
--p2p-keepalive-interval-ms arg (=10000)
peer heartbeat keepalive message
interval in milliseconds
```
## Dependencies
@@ -23,7 +23,6 @@ These can be specified from both the `nodeos` command-line or the `config.ini` f
```console
Config Options for eosio::producer_plugin:
-e [ --enable-stale-production ] Enable block production, even if the
chain is stale.
-x [ --pause-on-startup ] Start this node in a state where
@@ -49,7 +48,7 @@ Config Options for eosio::producer_plugin:
<public-key>=<provider-spec>
Where:
<public-key> is a string form of
a vaild Antelope public
a valid EOS public
key
<provider-spec> is a string in the
@@ -59,7 +58,7 @@ Config Options for eosio::producer_plugin:
<provider-type> is KEY, or KEOSD
KEY:<data> is a string form of
a valid Antelope
a valid EOS
private key which
maps to the provided
public key
@@ -119,11 +118,6 @@ Config Options for eosio::producer_plugin:
Sets the maximum amount of failures
that are allowed for a given account
per block.
Disregarded for accounts that have been
whitelisted by disabling subjective
billing for the account using the
disable-subjective-account-billing
configuration option.
--subjective-account-decay-time-minutes arg (=1440)
Sets the time to return full subjective
cpu for accounts
@@ -142,9 +136,6 @@ Config Options for eosio::producer_plugin:
--disable-subjective-account-billing arg
Account which is excluded from
subjective CPU billing
Account is considered whitelisted and
will not be subject to enforcement of
subjective-account-max-failures.
--disable-subjective-p2p-billing arg (=1)
Disable subjective CPU billing for P2P
transactions
@@ -1,19 +1,10 @@
## Overview
The `resource_monitor_plugin` monitors space usage in the computing system where `nodeos` is running. Specifically, every `resource-monitor-interval-seconds` seconds,
it measures the individual space used by each of the file systems mounted
by `data-dir`, `state-dir`, `blocks-log-dir`, `snapshots-dir`,
`state-history-dir`, and `trace-dir`.
When space usage in any of the monitored file system is within `5%` of the threshold
specified by `resource-monitor-space-threshold`, a warning containing the file system
path and percentage of space has used is printed out.
When space usage exceeds the threshold,
if `resource-monitor-not-shutdown-on-threshold-exceeded` is not set,
`nodeos` gracefully shuts down; if `resource-monitor-not-shutdown-on-threshold-exceeded` is set, `nodeos` prints out warnings periodically
until space usage goes under the threshold.
The `resource_monitor_plugin` monitors space usage in the computing system where `nodeos` is running. Specifically, every `resource-monitor-interval-seconds` seconds, it measures the individual space used by each of the file systems mounted by `data-dir`, `state-dir`, `blocks-log-dir`, `snapshots-dir`, `state-history-dir`, and `trace-dir`. When space usage in any of the monitored file system is within `5%` of the threshold specified by `resource-monitor-space-threshold`, a warning containing the file system path and percentage of space has used is printed out. When space usage exceeds the threshold, if `resource-monitor-not-shutdown-on-threshold-exceeded` is not set, `nodeos` gracefully shuts down; if `resource-monitor-not-shutdown-on-threshold-exceeded` is set, `nodeos` prints out warnings periodically until space usage goes under the threshold.
`resource_monitor_plugin` is always loaded.
## Usage
```console
@@ -32,33 +23,28 @@ These can be specified from both the `nodeos` command-line or the `config.ini` f
```console
Config Options for eosio::resource_monitor_plugin:
--resource-monitor-interval-seconds arg (=2)
Time in seconds between two consecutive checks
of space usage. Should be between 1 and 300.
Time in seconds between two consecutive
checks of resource usage. Should be
between 1 and 300
--resource-monitor-space-threshold arg (=90)
Threshold in terms of percentage of used space
vs total space. If the used space is within
`5%` of the threshold, a warning is generated.
If the used space is above the threshold and
`resource-monitor-not-shutdown-on-threshold-exceeded`
is enabled, a shutdown is initiated; otherwise
a warning will be continuously printed out.
The value should be between 6 and 99.
Threshold in terms of percentage of
used space vs total space. If used
space is above (threshold - 5%), a
warning is generated. Unless
resource-monitor-not-shutdown-on-thresh
old-exceeded is enabled, a graceful
shutdown is initiated if used space is
above the threshold. The value should
be between 6 and 99
--resource-monitor-not-shutdown-on-threshold-exceeded
A switch used to indicate `nodeos` will "not"
shutdown when threshold is exceeded. When not
set, `nodeos` will shutdown.
Used to indicate nodeos will not
shutdown when threshold is exceeded.
--resource-monitor-warning-interval arg (=30)
Number of monitor intervals between which a
warning is displayed. For example, if
`resource-monitor-warning-interval` is to 10
and `resource-monitor-interval-seconds` is 2,
a warning will be displayed every 20 seconds,
even though the space usage is checked every
2 seconds. This is used to throttle the
number of warnings in the `nodeos` log file.
Should be between 1 and 450.
Number of resource monitor intervals
between two consecutive warnings when
the threshold is hit. Should be between
1 and 450
```
## Plugin Dependencies
@@ -31,19 +31,21 @@ These can be specified from both the `nodeos` command-line or the `config.ini` f
```console
Config Options for eosio::state_history_plugin:
--state-history-dir arg (="state-history")
the location of the state-history
the location of the state-history
directory (absolute path or relative to
application data dir)
--trace-history enable trace history
--chain-state-history enable chain state history
--state-history-endpoint arg (=127.0.0.1:8080)
the endpoint upon which to listen for
incoming connections. Caution: only
expose this port to your internal
the endpoint upon which to listen for
incoming connections. Caution: only
expose this port to your internal
network.
--trace-history-debug-mode enable debug mode for trace history
--state-history-log-retain-blocks arg if set, periodically prune the state
history files to store only configured
number of most recent blocks
```
## Examples
+66 -36
View File
@@ -2056,43 +2056,64 @@ struct controller_impl {
}
} FC_CAPTURE_AND_RETHROW() } /// apply_block
// thread safe, expected to be called from thread other than the main thread
block_state_ptr create_block_state_i( const block_id_type& id, const signed_block_ptr& b, const block_header_state& prev ) {
auto trx_mroot = calculate_trx_merkle( b->transactions );
EOS_ASSERT( b->transaction_mroot == trx_mroot, block_validate_exception,
"invalid block transaction merkle root ${b} != ${c}", ("b", b->transaction_mroot)("c", trx_mroot) );
const bool skip_validate_signee = false;
auto bsp = std::make_shared<block_state>(
prev,
b,
protocol_features.get_protocol_feature_set(),
[this]( block_timestamp_type timestamp,
const flat_set<digest_type>& cur_features,
const vector<digest_type>& new_features )
{ check_protocol_features( timestamp, cur_features, new_features ); },
skip_validate_signee
);
EOS_ASSERT( id == bsp->id, block_validate_exception,
"provided id ${id} does not match block id ${bid}", ("id", id)("bid", bsp->id) );
return bsp;
}
std::future<block_state_ptr> create_block_state_future( const block_id_type& id, const signed_block_ptr& b ) {
EOS_ASSERT( b, block_validate_exception, "null block" );
return async_thread_pool( thread_pool.get_executor(), [b, id, control=this]() {
// no reason for a block_state if fork_db already knows about block
auto existing = control->fork_db.get_block( id );
EOS_ASSERT( !existing, fork_database_exception, "we already know about this block: ${id}", ("id", id) );
auto prev = control->fork_db.get_block_header( b->previous );
EOS_ASSERT( prev, unlinkable_block_exception,
"unlinkable block ${id}", ("id", id)("previous", b->previous) );
return control->create_block_state_i( id, b, *prev );
} );
}
// thread safe, expected to be called from thread other than the main thread
block_state_ptr create_block_state( const block_id_type& id, const signed_block_ptr& b ) {
EOS_ASSERT( b, block_validate_exception, "null block" );
// no reason for a block_state if fork_db already knows about block
auto existing = fork_db.get_block( id );
EOS_ASSERT( !existing, fork_database_exception, "we already know about this block: ${id}", ("id", id) );
// previous not found could mean that previous block not applied yet
auto prev = fork_db.get_block_header( b->previous );
EOS_ASSERT( prev, unlinkable_block_exception,
"unlinkable block ${id}", ("id", id)("previous", b->previous) );
if( !prev ) return {};
return async_thread_pool( thread_pool.get_executor(), [b, prev, id, control=this]() {
const bool skip_validate_signee = false;
auto trx_mroot = calculate_trx_merkle( b->transactions );
EOS_ASSERT( b->transaction_mroot == trx_mroot, block_validate_exception,
"invalid block transaction merkle root ${b} != ${c}", ("b", b->transaction_mroot)("c", trx_mroot) );
auto bsp = std::make_shared<block_state>(
*prev,
move( b ),
control->protocol_features.get_protocol_feature_set(),
[control]( block_timestamp_type timestamp,
const flat_set<digest_type>& cur_features,
const vector<digest_type>& new_features )
{ control->check_protocol_features( timestamp, cur_features, new_features ); },
skip_validate_signee
);
EOS_ASSERT( id == bsp->id, block_validate_exception,
"provided id ${id} does not match block id ${bid}", ("id", id)("bid", bsp->id) );
return bsp;
} );
return create_block_state_i( id, b, *prev );
}
void push_block( std::future<block_state_ptr>& block_state_future,
const forked_branch_callback& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup )
void push_block( const block_state_ptr& bsp,
const forked_branch_callback& forked_branch_cb,
const trx_meta_cache_lookup& trx_lookup )
{
controller::block_status s = controller::block_status::complete;
EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block");
@@ -2101,10 +2122,10 @@ struct controller_impl {
trusted_producer_light_validation = old_value;
});
try {
block_state_ptr bsp = block_state_future.get();
EOS_ASSERT( bsp, block_validate_exception, "null block" );
const auto& b = bsp->block;
if( conf.terminate_at_block > 0 && conf.terminate_at_block < self.head_block_num()) {
if( conf.terminate_at_block > 0 && conf.terminate_at_block <= self.head_block_num()) {
ilog("Reached configured maximum block ${num}; terminating", ("num", conf.terminate_at_block) );
shutdown();
return;
@@ -2139,7 +2160,7 @@ struct controller_impl {
EOS_ASSERT( (s == controller::block_status::irreversible || s == controller::block_status::validated),
block_validate_exception, "invalid block status for replay" );
if( conf.terminate_at_block > 0 && conf.terminate_at_block < self.head_block_num() ) {
if( conf.terminate_at_block > 0 && conf.terminate_at_block <= self.head_block_num() ) {
ilog("Reached configured maximum block ${num}; terminating", ("num", conf.terminate_at_block) );
shutdown();
return;
@@ -2816,11 +2837,16 @@ std::future<block_state_ptr> controller::create_block_state_future( const block_
return my->create_block_state_future( id, b );
}
void controller::push_block( std::future<block_state_ptr>& block_state_future,
const forked_branch_callback& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup )
block_state_ptr controller::create_block_state( const block_id_type& id, const signed_block_ptr& b ) const {
return my->create_block_state( id, b );
}
void controller::push_block( const block_state_ptr& bsp,
const forked_branch_callback& forked_branch_cb,
const trx_meta_cache_lookup& trx_lookup )
{
validate_db_available_size();
my->push_block( block_state_future, forked_branch_cb, trx_lookup );
my->push_block( bsp, forked_branch_cb, trx_lookup );
}
transaction_trace_ptr controller::push_transaction( const transaction_metadata_ptr& trx,
@@ -3468,10 +3494,14 @@ std::optional<chain_id_type> controller::extract_chain_id_from_db( const path& s
if( db.revision() < 1 ) return {};
return db.get<global_property_object>().chain_id;
} catch( const bad_database_version_exception& ) {
throw;
} catch( ... ) {
auto * gpo = db.find<global_property_object>();
if (gpo==nullptr) return {};
return gpo->chain_id;
} catch( const std::system_error& e ) {
// do not propagate db_error_code::not_found for absent db, so it will be created
if( e.code().value() != chainbase::db_error_code::not_found )
throw;
}
return {};
+180 -92
View File
@@ -9,6 +9,7 @@
#include <boost/multi_index/composite_key.hpp>
#include <fc/io/fstream.hpp>
#include <fstream>
#include <shared_mutex>
namespace eosio { namespace chain {
using boost::multi_index_container;
@@ -60,27 +61,44 @@ namespace eosio { namespace chain {
}
struct fork_database_impl {
fork_database_impl( fork_database& self, const fc::path& data_dir )
:self(self)
,datadir(data_dir)
explicit fork_database_impl( const fc::path& data_dir )
:datadir(data_dir)
{}
fork_database& self;
std::shared_mutex mtx;
fork_multi_index_type index;
block_state_ptr root; // Only uses the block_header_state portion
block_state_ptr head;
fc::path datadir;
void add( const block_state_ptr& n,
bool ignore_duplicate, bool validate,
const std::function<void( block_timestamp_type,
const flat_set<digest_type>&,
const vector<digest_type>& )>& validator );
void open_impl( const std::function<void( block_timestamp_type,
const flat_set<digest_type>&,
const vector<digest_type>& )>& validator );
void close_impl();
block_header_state_ptr get_block_header_impl( const block_id_type& id )const;
block_state_ptr get_block_impl( const block_id_type& id )const;
void reset_impl( const block_header_state& root_bhs );
void rollback_head_to_root_impl();
void advance_root_impl( const block_id_type& id );
void remove_impl( const block_id_type& id );
branch_type fetch_branch_impl( const block_id_type& h, uint32_t trim_after_block_num )const;
block_state_ptr search_on_branch_impl( const block_id_type& h, uint32_t block_num )const;
pair<branch_type, branch_type> fetch_branch_from_impl( const block_id_type& first,
const block_id_type& second )const;
void mark_valid_impl( const block_state_ptr& h );
void add_impl( const block_state_ptr& n,
bool ignore_duplicate, bool validate,
const std::function<void( block_timestamp_type,
const flat_set<digest_type>&,
const vector<digest_type>& )>& validator );
};
fork_database::fork_database( const fc::path& data_dir )
:my( new fork_database_impl( *this, data_dir ) )
:my( new fork_database_impl( data_dir ) )
{}
@@ -88,10 +106,18 @@ namespace eosio { namespace chain {
const flat_set<digest_type>&,
const vector<digest_type>& )>& validator )
{
if (!fc::is_directory(my->datadir))
fc::create_directories(my->datadir);
std::lock_guard g( my->mtx );
my->open_impl( validator );
}
auto fork_db_dat = my->datadir / config::forkdb_filename;
void fork_database_impl::open_impl( const std::function<void( block_timestamp_type,
const flat_set<digest_type>&,
const vector<digest_type>& )>& validator )
{
if (!fc::is_directory(datadir))
fc::create_directories(datadir);
auto fork_db_dat = datadir / config::forkdb_filename;
if( fc::exists( fork_db_dat ) ) {
try {
string content;
@@ -102,29 +128,29 @@ namespace eosio { namespace chain {
// validate totem
uint32_t totem = 0;
fc::raw::unpack( ds, totem );
EOS_ASSERT( totem == magic_number, fork_database_exception,
EOS_ASSERT( totem == fork_database::magic_number, fork_database_exception,
"Fork database file '${filename}' has unexpected magic number: ${actual_totem}. Expected ${expected_totem}",
("filename", fork_db_dat.generic_string())
("actual_totem", totem)
("expected_totem", magic_number)
("expected_totem", fork_database::magic_number)
);
// validate version
uint32_t version = 0;
fc::raw::unpack( ds, version );
EOS_ASSERT( version >= min_supported_version && version <= max_supported_version,
EOS_ASSERT( version >= fork_database::min_supported_version && version <= fork_database::max_supported_version,
fork_database_exception,
"Unsupported version of fork database file '${filename}'. "
"Fork database version is ${version} while code supports version(s) [${min},${max}]",
("filename", fork_db_dat.generic_string())
("version", version)
("min", min_supported_version)
("max", max_supported_version)
("min", fork_database::min_supported_version)
("max", fork_database::max_supported_version)
);
block_header_state bhs;
fc::raw::unpack( ds, bhs );
reset( bhs );
reset_impl( bhs );
unsigned_int size; fc::raw::unpack( ds, size );
for( uint32_t i = 0, n = size.value; i < n; ++i ) {
@@ -132,27 +158,27 @@ namespace eosio { namespace chain {
fc::raw::unpack( ds, s );
// do not populate transaction_metadatas, they will be created as needed in apply_block with appropriate key recovery
s.header_exts = s.block->validate_and_extract_header_extensions();
my->add( std::make_shared<block_state>( move( s ) ), false, true, validator );
add_impl( std::make_shared<block_state>( std::move( s ) ), false, true, validator );
}
block_id_type head_id;
fc::raw::unpack( ds, head_id );
if( my->root->id == head_id ) {
my->head = my->root;
if( root->id == head_id ) {
head = root;
} else {
my->head = get_block( head_id );
EOS_ASSERT( my->head, fork_database_exception,
head = get_block_impl( head_id );
EOS_ASSERT( head, fork_database_exception,
"could not find head while reconstructing fork database from file; '${filename}' is likely corrupted",
("filename", fork_db_dat.generic_string()) );
}
auto candidate = my->index.get<by_lib_block_num>().begin();
if( candidate == my->index.get<by_lib_block_num>().end() || !(*candidate)->is_valid() ) {
EOS_ASSERT( my->head->id == my->root->id, fork_database_exception,
auto candidate = index.get<by_lib_block_num>().begin();
if( candidate == index.get<by_lib_block_num>().end() || !(*candidate)->is_valid() ) {
EOS_ASSERT( head->id == root->id, fork_database_exception,
"head not set to root despite no better option available; '${filename}' is likely corrupted",
("filename", fork_db_dat.generic_string()) );
} else {
EOS_ASSERT( !first_preferred( **candidate, *my->head ), fork_database_exception,
EOS_ASSERT( !first_preferred( **candidate, *head ), fork_database_exception,
"head not set to best available option available; '${filename}' is likely corrupted",
("filename", fork_db_dat.generic_string()) );
}
@@ -163,10 +189,15 @@ namespace eosio { namespace chain {
}
void fork_database::close() {
auto fork_db_dat = my->datadir / config::forkdb_filename;
std::lock_guard g( my->mtx );
my->close_impl();
}
if( !my->root ) {
if( my->index.size() > 0 ) {
void fork_database_impl::close_impl() {
auto fork_db_dat = datadir / config::forkdb_filename;
if( !root ) {
if( index.size() > 0 ) {
elog( "fork_database is in a bad state when closing; not writing out '${filename}'",
("filename", fork_db_dat.generic_string()) );
}
@@ -174,13 +205,13 @@ namespace eosio { namespace chain {
}
std::ofstream out( fork_db_dat.generic_string().c_str(), std::ios::out | std::ios::binary | std::ofstream::trunc );
fc::raw::pack( out, magic_number );
fc::raw::pack( out, max_supported_version ); // write out current version which is always max_supported_version
fc::raw::pack( out, *static_cast<block_header_state*>(&*my->root) );
uint32_t num_blocks_in_fork_db = my->index.size();
fc::raw::pack( out, fork_database::magic_number );
fc::raw::pack( out, fork_database::max_supported_version ); // write out current version which is always max_supported_version
fc::raw::pack( out, *static_cast<block_header_state*>(&*root) );
uint32_t num_blocks_in_fork_db = index.size();
fc::raw::pack( out, unsigned_int{num_blocks_in_fork_db} );
const auto& indx = my->index.get<by_lib_block_num>();
const auto& indx = index.get<by_lib_block_num>();
auto unvalidated_itr = indx.rbegin();
auto unvalidated_end = boost::make_reverse_iterator( indx.lower_bound( false ) );
@@ -215,30 +246,40 @@ namespace eosio { namespace chain {
fc::raw::pack( out, *(*itr) );
}
if( my->head ) {
fc::raw::pack( out, my->head->id );
if( head ) {
fc::raw::pack( out, head->id );
} else {
elog( "head not set in fork database; '${filename}' will be corrupted",
("filename", fork_db_dat.generic_string()) );
}
my->index.clear();
index.clear();
}
fork_database::~fork_database() {
close();
my->close_impl();
}
void fork_database::reset( const block_header_state& root_bhs ) {
my->index.clear();
my->root = std::make_shared<block_state>();
static_cast<block_header_state&>(*my->root) = root_bhs;
my->root->validated = true;
my->head = my->root;
std::lock_guard g( my->mtx );
my->reset_impl(root_bhs);
}
void fork_database_impl::reset_impl( const block_header_state& root_bhs ) {
index.clear();
root = std::make_shared<block_state>();
static_cast<block_header_state&>(*root) = root_bhs;
root->validated = true;
head = root;
}
void fork_database::rollback_head_to_root() {
auto& by_id_idx = my->index.get<by_block_id>();
std::lock_guard g( my->mtx );
my->rollback_head_to_root_impl();
}
void fork_database_impl::rollback_head_to_root_impl() {
auto& by_id_idx = index.get<by_block_id>();
auto itr = by_id_idx.begin();
while (itr != by_id_idx.end()) {
by_id_idx.modify( itr, [&]( block_state_ptr& bsp ) {
@@ -246,13 +287,18 @@ namespace eosio { namespace chain {
} );
++itr;
}
my->head = my->root;
head = root;
}
void fork_database::advance_root( const block_id_type& id ) {
EOS_ASSERT( my->root, fork_database_exception, "root not yet set" );
std::lock_guard g( my->mtx );
my->advance_root_impl( id );
}
auto new_root = get_block( id );
void fork_database_impl::advance_root_impl( const block_id_type& id ) {
EOS_ASSERT( root, fork_database_exception, "root not yet set" );
auto new_root = get_block_impl( id );
EOS_ASSERT( new_root, fork_database_exception,
"cannot advance root to a block that does not exist in the fork database" );
EOS_ASSERT( new_root->is_valid(), fork_database_exception,
@@ -262,48 +308,53 @@ namespace eosio { namespace chain {
deque<block_id_type> blocks_to_remove;
for( auto b = new_root; b; ) {
blocks_to_remove.emplace_back( b->header.previous );
b = get_block( blocks_to_remove.back() );
EOS_ASSERT( b || blocks_to_remove.back() == my->root->id, fork_database_exception, "invariant violation: orphaned branch was present in forked database" );
b = get_block_impl( blocks_to_remove.back() );
EOS_ASSERT( b || blocks_to_remove.back() == root->id, fork_database_exception, "invariant violation: orphaned branch was present in forked database" );
}
// The new root block should be erased from the fork database index individually rather than with the remove method,
// because we do not want the blocks branching off of it to be removed from the fork database.
my->index.erase( my->index.find( id ) );
index.erase( index.find( id ) );
// The other blocks to be removed are removed using the remove method so that orphaned branches do not remain in the fork database.
for( const auto& block_id : blocks_to_remove ) {
remove( block_id );
remove_impl( block_id );
}
// Even though fork database no longer needs block or trxs when a block state becomes a root of the tree,
// avoid mutating the block state at all, for example clearing the block shared pointer, because other
// parts of the code which run asynchronously may later expect it remain unmodified.
my->root = new_root;
root = new_root;
}
block_header_state_ptr fork_database::get_block_header( const block_id_type& id )const {
if( my->root->id == id ) {
return my->root;
std::shared_lock g( my->mtx );
return my->get_block_header_impl( id );
}
block_header_state_ptr fork_database_impl::get_block_header_impl( const block_id_type& id )const {
if( root->id == id ) {
return root;
}
auto itr = my->index.find( id );
if( itr != my->index.end() )
auto itr = index.find( id );
if( itr != index.end() )
return *itr;
return block_header_state_ptr();
}
void fork_database_impl::add( const block_state_ptr& n,
bool ignore_duplicate, bool validate,
const std::function<void( block_timestamp_type,
const flat_set<digest_type>&,
const vector<digest_type>& )>& validator )
void fork_database_impl::add_impl( const block_state_ptr& n,
bool ignore_duplicate, bool validate,
const std::function<void( block_timestamp_type,
const flat_set<digest_type>&,
const vector<digest_type>& )>& validator )
{
EOS_ASSERT( root, fork_database_exception, "root not yet set" );
EOS_ASSERT( n, fork_database_exception, "attempt to add null block state" );
auto prev_bh = self.get_block_header( n->header.previous );
auto prev_bh = get_block_header_impl( n->header.previous );
EOS_ASSERT( prev_bh, unlinkable_block_exception,
"unlinkable block", ("id", n->id)("previous", n->header.previous) );
@@ -332,19 +383,27 @@ namespace eosio { namespace chain {
}
void fork_database::add( const block_state_ptr& n, bool ignore_duplicate ) {
my->add( n, ignore_duplicate, false,
[]( block_timestamp_type timestamp,
const flat_set<digest_type>& cur_features,
const vector<digest_type>& new_features )
{}
std::lock_guard g( my->mtx );
my->add_impl( n, ignore_duplicate, false,
[]( block_timestamp_type timestamp,
const flat_set<digest_type>& cur_features,
const vector<digest_type>& new_features )
{}
);
}
const block_state_ptr& fork_database::root()const { return my->root; }
block_state_ptr fork_database::root()const {
std::shared_lock g( my->mtx );
return my->root;
}
const block_state_ptr& fork_database::head()const { return my->head; }
block_state_ptr fork_database::head()const {
std::shared_lock g( my->mtx );
return my->head;
}
block_state_ptr fork_database::pending_head()const {
std::shared_lock g( my->mtx );
const auto& indx = my->index.get<by_lib_block_num>();
auto itr = indx.lower_bound( false );
@@ -357,8 +416,13 @@ namespace eosio { namespace chain {
}
branch_type fork_database::fetch_branch( const block_id_type& h, uint32_t trim_after_block_num )const {
std::shared_lock g( my->mtx );
return my->fetch_branch_impl( h, trim_after_block_num );
}
branch_type fork_database_impl::fetch_branch_impl( const block_id_type& h, uint32_t trim_after_block_num )const {
branch_type result;
for( auto s = get_block(h); s; s = get_block( s->header.previous ) ) {
for( auto s = get_block_impl(h); s; s = get_block_impl( s->header.previous ) ) {
if( s->block_num <= trim_after_block_num )
result.push_back( s );
}
@@ -367,7 +431,12 @@ namespace eosio { namespace chain {
}
block_state_ptr fork_database::search_on_branch( const block_id_type& h, uint32_t block_num )const {
for( auto s = get_block(h); s; s = get_block( s->header.previous ) ) {
std::shared_lock g( my->mtx );
return my->search_on_branch_impl( h, block_num );
}
block_state_ptr fork_database_impl::search_on_branch_impl( const block_id_type& h, uint32_t block_num )const {
for( auto s = get_block_impl(h); s; s = get_block_impl( s->header.previous ) ) {
if( s->block_num == block_num )
return s;
}
@@ -381,9 +450,15 @@ namespace eosio { namespace chain {
*/
pair< branch_type, branch_type > fork_database::fetch_branch_from( const block_id_type& first,
const block_id_type& second )const {
std::shared_lock g( my->mtx );
return my->fetch_branch_from_impl( first, second );
}
pair< branch_type, branch_type > fork_database_impl::fetch_branch_from_impl( const block_id_type& first,
const block_id_type& second )const {
pair<branch_type,branch_type> result;
auto first_branch = (first == my->root->id) ? my->root : get_block(first);
auto second_branch = (second == my->root->id) ? my->root : get_block(second);
auto first_branch = (first == root->id) ? root : get_block_impl(first);
auto second_branch = (second == root->id) ? root : get_block_impl(second);
EOS_ASSERT(first_branch, fork_db_block_not_found, "block ${id} does not exist", ("id", first));
EOS_ASSERT(second_branch, fork_db_block_not_found, "block ${id} does not exist", ("id", second));
@@ -392,7 +467,7 @@ namespace eosio { namespace chain {
{
result.first.push_back(first_branch);
const auto& prev = first_branch->header.previous;
first_branch = (prev == my->root->id) ? my->root : get_block( prev );
first_branch = (prev == root->id) ? root : get_block_impl( prev );
EOS_ASSERT( first_branch, fork_db_block_not_found,
"block ${id} does not exist",
("id", prev)
@@ -403,7 +478,7 @@ namespace eosio { namespace chain {
{
result.second.push_back( second_branch );
const auto& prev = second_branch->header.previous;
second_branch = (prev == my->root->id) ? my->root : get_block( prev );
second_branch = (prev == root->id) ? root : get_block_impl( prev );
EOS_ASSERT( second_branch, fork_db_block_not_found,
"block ${id} does not exist",
("id", prev)
@@ -417,9 +492,9 @@ namespace eosio { namespace chain {
result.first.push_back(first_branch);
result.second.push_back(second_branch);
const auto &first_prev = first_branch->header.previous;
first_branch = get_block( first_prev );
first_branch = get_block_impl( first_prev );
const auto &second_prev = second_branch->header.previous;
second_branch = get_block( second_prev );
second_branch = get_block_impl( second_prev );
EOS_ASSERT( first_branch, fork_db_block_not_found,
"block ${id} does not exist",
("id", first_prev)
@@ -436,13 +511,18 @@ namespace eosio { namespace chain {
result.second.push_back(second_branch);
}
return result;
} /// fetch_branch_from
} /// fetch_branch_from_impl
/// remove all of the invalid forks built off of this id including this id
void fork_database::remove( const block_id_type& id ) {
std::lock_guard g( my->mtx );
return my->remove_impl( id );
}
void fork_database_impl::remove_impl( const block_id_type& id ) {
deque<block_id_type> remove_queue{id};
const auto& previdx = my->index.get<by_prev>();
const auto& head_id = my->head->id;
const auto& previdx = index.get<by_prev>();
const auto& head_id = head->id;
for( uint32_t i = 0; i < remove_queue.size(); ++i ) {
EOS_ASSERT( remove_queue[i] != head_id, fork_database_exception,
@@ -456,16 +536,19 @@ namespace eosio { namespace chain {
}
for( const auto& block_id : remove_queue ) {
auto itr = my->index.find( block_id );
if( itr != my->index.end() )
my->index.erase(itr);
index.erase( block_id );
}
}
void fork_database::mark_valid( const block_state_ptr& h ) {
std::lock_guard g( my->mtx );
my->mark_valid_impl( h );
}
void fork_database_impl::mark_valid_impl( const block_state_ptr& h ) {
if( h->validated ) return;
auto& by_id_idx = my->index.get<by_block_id>();
auto& by_id_idx = index.get<by_block_id>();
auto itr = by_id_idx.find( h->id );
EOS_ASSERT( itr != by_id_idx.end(), fork_database_exception,
@@ -476,15 +559,20 @@ namespace eosio { namespace chain {
bsp->validated = true;
} );
auto candidate = my->index.get<by_lib_block_num>().begin();
if( first_preferred( **candidate, *my->head ) ) {
my->head = *candidate;
auto candidate = index.get<by_lib_block_num>().begin();
if( first_preferred( **candidate, *head ) ) {
head = *candidate;
}
}
block_state_ptr fork_database::get_block(const block_id_type& id)const {
auto itr = my->index.find( id );
if( itr != my->index.end() )
block_state_ptr fork_database::get_block(const block_id_type& id)const {
std::shared_lock g( my->mtx );
return my->get_block_impl(id);
}
block_state_ptr fork_database_impl::get_block_impl(const block_id_type& id)const {
auto itr = index.find( id );
if( itr != index.end() )
return *itr;
return block_state_ptr();
}
@@ -84,7 +84,7 @@ namespace eosio { namespace chain {
bool allow_ram_billing_in_notify = false;
uint32_t maximum_variable_signature_length = chain::config::default_max_variable_signature_length;
bool disable_all_subjective_mitigations = false; //< for developer & testing purposes, can be configured using `disable-all-subjective-mitigations` when `EOSIO_DEVELOPER` build option is provided
uint32_t terminate_at_block = 0; //< primarily for testing purposes
uint32_t terminate_at_block = 0;
wasm_interface::vm_type wasm_runtime = chain::config::default_wasm_runtime;
eosvmoc::config eosvmoc_config;
@@ -166,14 +166,17 @@ namespace eosio { namespace chain {
void sign_block( const signer_callback_type& signer_callback );
void commit_block();
// thread-safe
std::future<block_state_ptr> create_block_state_future( const block_id_type& id, const signed_block_ptr& b );
// thread-safe
block_state_ptr create_block_state( const block_id_type& id, const signed_block_ptr& b ) const;
/**
* @param block_state_future provide from call to create_block_state_future
* @param bsp block to push
* @param cb calls cb with forked applied transactions for each forked block
* @param trx_lookup user provided lookup function for externally cached transaction_metadata
*/
void push_block( std::future<block_state_ptr>& block_state_future,
void push_block( const block_state_ptr& bsp,
const forked_branch_callback& cb,
const trx_meta_cache_lookup& trx_lookup );
@@ -244,6 +247,7 @@ namespace eosio { namespace chain {
signed_block_ptr fetch_block_by_id( block_id_type id )const;
block_state_ptr fetch_block_state_by_number( uint32_t block_num )const;
// return block_state from forkdb, thread-safe
block_state_ptr fetch_block_state_by_id( block_id_type id )const;
block_id_type get_block_id_for_num( uint32_t block_num )const;
@@ -16,6 +16,8 @@ namespace eosio { namespace chain {
* database tracks the longest chain and the last irreversible block number. All
* blocks older than the last irreversible block are freed after emitting the
* irreversible signal.
*
* An internal mutex is used to provide thread-safety.
*/
class fork_database {
public:
@@ -55,9 +57,9 @@ namespace eosio { namespace chain {
void remove( const block_id_type& id );
const block_state_ptr& root()const;
const block_state_ptr& head()const;
block_state_ptr pending_head()const;
block_state_ptr root()const;
block_state_ptr head()const;
block_state_ptr pending_head()const;
/**
* Returns the sequence of block states resulting from trimming the branch from the
@@ -96,15 +96,15 @@ public:
return itr->trx_meta;
}
template <typename Func>
bool clear_expired( const time_point& pending_block_time, const time_point& deadline, Func&& callback ) {
template <typename Yield, typename Callback>
bool clear_expired( const time_point& pending_block_time, Yield&& yield, Callback&& callback ) {
auto& persisted_by_expiry = queue.get<by_expiry>();
while( !persisted_by_expiry.empty() ) {
const auto& itr = persisted_by_expiry.begin();
if( itr->expiry > pending_block_time ) {
break;
}
if( deadline <= fc::time_point::now() ) {
if( yield() ) {
return false;
}
callback( itr->trx_meta->packed_trx(), itr->trx_type );
@@ -247,7 +247,7 @@ std::unique_ptr<wasm_instantiated_module_interface> eos_vm_runtime<Impl>::instan
wasm_code_ptr code((uint8_t*)code_bytes, code_size);
apply_options options = { .max_pages = 65536,
.max_call_depth = 0 };
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options);
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options, false); // uses 2-passes parsing
eos_vm_host_functions_t::resolve(bkend->get_module());
return std::make_unique<eos_vm_instantiated_module<Impl>>(this, std::move(bkend));
} catch(eosio::vm::exception& e) {
@@ -273,7 +273,7 @@ std::unique_ptr<wasm_instantiated_module_interface> eos_vm_profile_runtime::inst
wasm_code_ptr code((uint8_t*)code_bytes, code_size);
apply_options options = { .max_pages = 65536,
.max_call_depth = 0 };
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options);
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options, false); // uses 2-passes parsing
eos_vm_host_functions_t::resolve(bkend->get_module());
return std::make_unique<eos_vm_profiling_module>(std::move(bkend), code_bytes, code_size);
} catch(eosio::vm::exception& e) {
@@ -597,7 +597,7 @@ namespace eosio { namespace testing {
signed_block_ptr produce_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms) )override {
auto sb = _produce_block(skip_time, false);
auto bsf = validating_node->create_block_state_future( sb->calculate_id(), sb );
validating_node->push_block( bsf, forked_branch_callback{}, trx_meta_cache_lookup{} );
validating_node->push_block( bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} );
return sb;
}
@@ -607,15 +607,15 @@ namespace eosio { namespace testing {
}
void validate_push_block(const signed_block_ptr& sb) {
auto bs = validating_node->create_block_state_future( sb->calculate_id(), sb );
validating_node->push_block( bs, forked_branch_callback{}, trx_meta_cache_lookup{} );
auto bsf = validating_node->create_block_state_future( sb->calculate_id(), sb );
validating_node->push_block( bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} );
}
signed_block_ptr produce_empty_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms) )override {
unapplied_transactions.add_aborted( control->abort_block() );
auto sb = _produce_block(skip_time, true);
auto bsf = validating_node->create_block_state_future( sb->calculate_id(), sb );
validating_node->push_block( bsf, forked_branch_callback{}, trx_meta_cache_lookup{} );
validating_node->push_block( bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} );
return sb;
}
+2 -2
View File
@@ -322,7 +322,7 @@ namespace eosio { namespace testing {
void base_tester::push_block(signed_block_ptr b) {
auto bsf = control->create_block_state_future(b->calculate_id(), b);
unapplied_transactions.add_aborted( control->abort_block() );
control->push_block( bsf, [this]( const branch_type& forked_branch ) {
control->push_block( bsf.get(), [this]( const branch_type& forked_branch ) {
unapplied_transactions.add_forked( forked_branch );
}, [this]( const transaction_id_type& id ) {
return unapplied_transactions.get_trx( id );
@@ -1050,7 +1050,7 @@ namespace eosio { namespace testing {
if( block ) { //&& !b.control->is_known_block(block->id()) ) {
auto bsf = b.control->create_block_state_future( block->calculate_id(), block );
b.control->abort_block();
b.control->push_block(bsf, forked_branch_callback{}, trx_meta_cache_lookup{}); //, eosio::chain::validation_steps::created_block);
b.control->push_block(bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{}); //, eosio::chain::validation_steps::created_block);
}
}
};
@@ -37,14 +37,9 @@ namespace eosio { namespace chain { namespace plugin_interface {
}
namespace incoming {
namespace channels {
using block = channel_decl<struct block_tag, signed_block_ptr>;
using transaction = channel_decl<struct transaction_tag, packed_transaction_ptr>;
}
namespace methods {
// synchronously push a block/trx to a single provider
using block_sync = method_decl<chain_plugin_interface, bool(const signed_block_ptr&, const std::optional<block_id_type>&), first_provider_policy>;
// synchronously push a block/trx to a single provider, block_state_ptr may be null
using block_sync = method_decl<chain_plugin_interface, bool(const signed_block_ptr&, const std::optional<block_id_type>&, const block_state_ptr&), first_provider_policy>;
using transaction_async = method_decl<chain_plugin_interface, void(const packed_transaction_ptr&, bool, bool, bool, next_function<transaction_trace_ptr>), first_provider_policy>;
}
}
+3 -5
View File
@@ -142,7 +142,6 @@ public:
,irreversible_block_channel(app().get_channel<channels::irreversible_block>())
,accepted_transaction_channel(app().get_channel<channels::accepted_transaction>())
,applied_transaction_channel(app().get_channel<channels::applied_transaction>())
,incoming_block_channel(app().get_channel<incoming::channels::block>())
,incoming_block_sync_method(app().get_method<incoming::methods::block_sync>())
,incoming_transaction_async_method(app().get_method<incoming::methods::transaction_async>())
{}
@@ -170,7 +169,6 @@ public:
channels::irreversible_block::channel_type& irreversible_block_channel;
channels::accepted_transaction::channel_type& accepted_transaction_channel;
channels::applied_transaction::channel_type& applied_transaction_channel;
incoming::channels::block::channel_type& incoming_block_channel;
// retained references to methods for easy calling
incoming::methods::block_sync::method_type& incoming_block_sync_method;
@@ -1333,8 +1331,8 @@ chain_apis::read_only chain_plugin::get_read_only_api() const {
}
bool chain_plugin::accept_block(const signed_block_ptr& block, const block_id_type& id ) {
return my->incoming_block_sync_method(block, id);
bool chain_plugin::accept_block(const signed_block_ptr& block, const block_id_type& id, const block_state_ptr& bsp ) {
return my->incoming_block_sync_method(block, id, bsp);
}
void chain_plugin::accept_transaction(const chain::packed_transaction_ptr& trx, next_function<chain::transaction_trace_ptr> next) {
@@ -2130,7 +2128,7 @@ fc::variant read_only::get_block_header_state(const get_block_header_state_param
void read_write::push_block(read_write::push_block_params&& params, next_function<read_write::push_block_results> next) {
try {
app().get_method<incoming::methods::block_sync>()(std::make_shared<signed_block>(std::move(params)), {});
app().get_method<incoming::methods::block_sync>()(std::make_shared<signed_block>( std::move(params) ), std::optional<block_id_type>{}, block_state_ptr{});
} catch ( boost::interprocess::bad_alloc& ) {
chain_plugin::handle_db_exhaustion();
} catch ( const std::bad_alloc& ) {
@@ -777,7 +777,7 @@ public:
chain_apis::read_write get_read_write_api();
chain_apis::read_only get_read_only_api() const;
bool accept_block( const chain::signed_block_ptr& block, const chain::block_id_type& id );
bool accept_block( const chain::signed_block_ptr& block, const chain::block_id_type& id, const chain::block_state_ptr& bsp );
void accept_transaction(const chain::packed_transaction_ptr& trx, chain::plugin_interface::next_function<chain::transaction_trace_ptr> next);
// Only call this after plugin_initialize()!
+1
View File
@@ -912,6 +912,7 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
my->url_handlers.clear();
app().post( 0, [me = my](){} ); // keep my pointer alive until queue is drained
fc_ilog( logger, "exit shutdown");
}
void http_plugin::add_handler(const string& url, const url_handler& handler, int priority) {
+56 -29
View File
@@ -26,6 +26,7 @@
#include <boost/asio/steady_timer.hpp>
#include <atomic>
#include <cmath>
#include <shared_mutex>
using namespace eosio::chain::plugin_interface;
@@ -785,7 +786,7 @@ namespace eosio {
void handle_message( const packed_transaction& msg ) = delete; // packed_transaction_ptr overload used instead
void handle_message( packed_transaction_ptr msg );
void process_signed_block( const block_id_type& id, signed_block_ptr msg );
void process_signed_block( const block_id_type& id, signed_block_ptr msg, block_state_ptr bsp );
fc::variant_object get_logger_variant() const {
fc::mutable_variant_object mvo;
@@ -1776,7 +1777,6 @@ namespace eosio {
if( c->is_transactions_only_connection() ) return;
uint32_t lib_num = 0;
uint32_t peer_lib = msg.last_irreversible_block_num;
uint32_t head = 0;
block_id_type head_id;
std::tie( lib_num, std::ignore, head,
@@ -1790,10 +1790,10 @@ namespace eosio {
peer_wlog(c, "Peer sent a handshake with a timestamp skewed by at least ${t}ms", ("t", network_latency_ns/1000000));
network_latency_ns = 0;
}
// number of blocks syncing node is behind from a peer node
uint32_t nblk_behind_by_net_latency = static_cast<uint32_t>(network_latency_ns / block_interval_ns);
// 2x for time it takes for message to reach back to peer node, +1 to compensate for integer division truncation
uint32_t nblk_combined_latency = 2 * nblk_behind_by_net_latency + 1;
// number of blocks syncing node is behind from a peer node, round up
uint32_t nblk_behind_by_net_latency = std::lround( static_cast<double>(network_latency_ns) / static_cast<double>(block_interval_ns) );
// 2x for time it takes for message to reach back to peer node
uint32_t nblk_combined_latency = 2 * nblk_behind_by_net_latency;
// message in the log below is used in p2p_high_latency_test.py test
peer_dlog(c, "Network latency is ${lat}ms, ${num} blocks discrepancy by network latency, ${tot_num} blocks discrepancy expected once message received",
("lat", network_latency_ns/1000000)("num", nblk_behind_by_net_latency)("tot_num", nblk_combined_latency));
@@ -1813,8 +1813,8 @@ namespace eosio {
//-----------------------------
if (head_id == msg.head_id) {
peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 0",
("lib", msg.last_irreversible_block_num)("head", msg.head_num)("id", msg.head_id.str().substr(8,16)) );
peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 0, lib ${l}",
("lib", msg.last_irreversible_block_num)("head", msg.head_num)("id", msg.head_id.str().substr(8,16))("l", lib_num) );
c->syncing = false;
notice_message note;
note.known_blocks.mode = none;
@@ -1823,9 +1823,10 @@ namespace eosio {
c->enqueue( note );
return;
}
if (head < peer_lib) {
peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 1",
("lib", msg.last_irreversible_block_num)("head", msg.head_num)("id", msg.head_id.str().substr(8,16)) );
if (head < msg.last_irreversible_block_num) {
peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 1, head ${h}, lib ${l}",
("lib", msg.last_irreversible_block_num)("head", msg.head_num)("id", msg.head_id.str().substr(8,16))
("h", head)("l", lib_num) );
c->syncing = false;
if (c->sent_handshake_count > 0) {
c->send_handshake();
@@ -1833,8 +1834,9 @@ namespace eosio {
return;
}
if (lib_num > msg.head_num + nblk_combined_latency) {
peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 2",
("lib", msg.last_irreversible_block_num)("head", msg.head_num)("id", msg.head_id.str().substr(8,16)) );
peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 2, head ${h}, lib ${l}",
("lib", msg.last_irreversible_block_num)("head", msg.head_num)("id", msg.head_id.str().substr(8,16))
("h", head)("l", lib_num) );
if (msg.generation > 1 || c->protocol_version > proto_base) {
notice_message note;
note.known_trx.pending = lib_num;
@@ -1848,14 +1850,16 @@ namespace eosio {
}
if (head + nblk_combined_latency < msg.head_num ) {
peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 3",
("lib", msg.last_irreversible_block_num)("head", msg.head_num)("id", msg.head_id.str().substr(8,16)) );
peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 3, head ${h}, lib ${l}",
("lib", msg.last_irreversible_block_num)("head", msg.head_num)("id", msg.head_id.str().substr(8,16))
("h", head)("l", lib_num) );
c->syncing = false;
verify_catchup(c, msg.head_num, msg.head_id);
return;
} else if(head >= msg.head_num + nblk_combined_latency) {
peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 4",
("lib", msg.last_irreversible_block_num)("head", msg.head_num)("id", msg.head_id.str().substr(8,16)) );
peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 4, head ${h}, lib ${l}",
("lib", msg.last_irreversible_block_num)("head", msg.head_num)("id", msg.head_id.str().substr(8,16))
("h", head)("l", lib_num) );
if (msg.generation > 1 || c->protocol_version > proto_base) {
notice_message note;
note.known_trx.mode = none;
@@ -2341,14 +2345,6 @@ namespace eosio {
// called from connection strand
void connection::connect( const std::shared_ptr<tcp::resolver>& resolver, tcp::resolver::results_type endpoints ) {
switch ( no_retry ) {
case no_reason:
case wrong_version:
case benign_other:
break;
default:
return;
}
connecting = true;
pending_message_buffer.reset();
buffer_queue.clear_out_queue();
@@ -3143,13 +3139,44 @@ namespace eosio {
// called from connection strand
void connection::handle_message( const block_id_type& id, signed_block_ptr ptr ) {
peer_dlog( this, "received signed_block ${num}, id ${id}", ("num", ptr->block_num())("id", id) );
app().post(priority::medium, [ptr{std::move(ptr)}, id, c = shared_from_this()]() mutable {
c->process_signed_block( id, std::move( ptr ) );
controller& cc = my_impl->chain_plug->chain();
block_state_ptr bsp;
bool exception = false;
try {
if( cc.fetch_block_state_by_id( id ) ) {
my_impl->dispatcher->add_peer_block( id, connection_id );
my_impl->sync_master->sync_recv_block( shared_from_this(), id, ptr->block_num(), false );
return;
}
// this may return null if block is not immediately ready to be processed
bsp = cc.create_block_state( id, ptr );
} catch( const fc::exception& ex ) {
exception = true;
peer_elog(this, "bad block exception: #${n} ${id}...: ${m}",
("n", ptr->block_num())("id", id.str().substr(8,16))("m",ex.to_string()));
} catch( ... ) {
exception = true;
peer_elog(this, "bad block: #${n} ${id}...: unknown exception",
("n", ptr->block_num())("id", id.str().substr(8,16)));
}
if( exception ) {
my_impl->sync_master->rejected_block( shared_from_this(), ptr->block_num() );
my_impl->dispatcher->rejected_block( id );
return;
}
bool signal_producer = !!bsp; // ready to process immediately, so signal producer to interrupt start_block
app().post(priority::medium, [ptr{std::move(ptr)}, bsp{std::move(bsp)}, id, c = shared_from_this()]() mutable {
c->process_signed_block( id, std::move(ptr), std::move(bsp) );
});
if( signal_producer )
my_impl->producer_plug->received_block();
}
// called from application thread
void connection::process_signed_block( const block_id_type& blk_id, signed_block_ptr msg ) {
void connection::process_signed_block( const block_id_type& blk_id, signed_block_ptr msg, block_state_ptr bsp ) {
controller& cc = my_impl->chain_plug->chain();
uint32_t blk_num = msg->block_num();
// use c in this method instead of this to highlight that all methods called on c-> must be thread safe
@@ -3179,7 +3206,7 @@ namespace eosio {
go_away_reason reason = fatal_other;
try {
bool accepted = my_impl->chain_plug->accept_block(msg, blk_id);
bool accepted = my_impl->chain_plug->accept_block(msg, blk_id, bsp);
my_impl->update_chain_info();
if( !accepted ) return;
reason = no_reason;
+421 -290
View File
@@ -7,11 +7,12 @@ info:
name: MIT
url: https://opensource.org/licenses/MIT
contact:
url: https://eosnetwork.com
url: https://antelope.io
tags:
- name: eosio
- name: Protocol Version 3.1
description: The release tag for Leap binaries is also the protocol version
servers:
- url: "{protocol}://{host}:{port}/v1/"
- url: "{protocol}://{host}:{port}/v1"
variables:
protocol:
enum:
@@ -22,285 +23,223 @@ servers:
default: localhost
port:
default: "8080"
components:
securitySchemes: {}
schemas: {}
security:
- {}
paths:
/producer/pause:
post:
summary: pause
description: Pause producer node
description: Pause producer node. Takes no arguments and returns no values.
operationId: pause
parameters: []
requestBody:
content:
application/json:
schema:
type: object
properties: {}
responses:
"200":
"201":
description: OK
content:
application/json:
schema:
type: boolean
description: "returns status"
$ref: '#/components/schemas/OK'
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/resume:
post:
summary: resume
description: Resume producer node
description: Resume producer node. Takes no arguments and returns no values.
operationId: resume
parameters: []
requestBody:
content:
application/json:
schema:
type: object
description: Resumes activity for producer
responses:
"200":
"201":
description: OK
content:
application/json:
schema:
description: Returns Nothing
$ref: '#/components/schemas/OK'
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/paused:
post:
summary: paused
description: Retreives paused status for producer node
description: Retrieves paused status for producer node. Takes no arguments and returns no values.
operationId: paused
parameters: []
requestBody:
content:
application/json:
schema:
type: object
properties: {}
responses:
"200":
"201":
description: OK
content:
application/json:
schema:
type: boolean
description: True if producer is paused, false otherwise
$ref: '#/components/schemas/OK_PAUSED'
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/get_runtime_options:
post:
summary: get_runtime_options
description: Retreives run time options for producer node
description: Retrieves runtime options for producer node.
operationId: get_runtime_options
parameters: []
responses:
"201":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Runtime_Options'
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/update_runtime_options:
post:
summary: update_runtime_options
description: Update runtime options for producer node. May post any of the runtime options in combination or alone.
operationId: update_runtime_options
requestBody:
content:
application/json:
schema:
type: object
properties: {}
$ref: '#/components/schemas/Runtime_Options'
responses:
"200":
"201":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/OK'
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/get_greylist:
post:
summary: get_greylist
description: Retrieves the greylist for producer node.
operationId: get_greylist
responses:
"201":
description: OK
content:
application/json:
schema:
type: object
description: Returns run time options set for the producer
properties:
max_transaction_time:
type: integer
description: Max transaction time
max_irreversible_block_age:
type: integer
description: Max irreversible block age
produce_time_offset_us:
type: integer
description: Time offset
last_block_time_offset_us:
type: integer
description: Last block time offset
max_scheduled_transaction_time_per_block_ms:
type: integer
description: Max scheduled transaction time per block in ms
subjective_cpu_leeway_us:
type: integer
description: Subjective CPU leeway
incoming_defer_ratio:
type: integer
description: Incoming defer ration
/producer/update_runtime_options:
post:
summary: update_runtime_options
description: Update run time options for producer node
operationId: update_runtime_options
parameters: []
requestBody:
content:
application/json:
schema:
type: object
required:
- options
properties:
options:
type: object
description: Defines the run time options to set for the producer
properties:
max_transaction_time:
type: integer
description: Max transaction time
max_irreversible_block_age:
type: integer
description: Max irreversible block age
produce_time_offset_us:
type: integer
description: Time offset
last_block_time_offset_us:
type: integer
description: Last block time offset
max_scheduled_transaction_time_per_block_ms:
type: integer
description: Max scheduled transaction time per block in ms
subjective_cpu_leeway_us:
type: integer
description: Subjective CPU leeway
incoming_defer_ratio:
type: integer
description: Incoming defer ration
responses:
"200":
description: OK
accounts:
type: array
description: Array of account names stored in the greylist
items:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
"400":
description: client error
content:
application/json:
schema:
description: Returns Nothing
/producer/get_greylist:
post:
summary: get_greylist
description: Retreives the greylist for producer node
operationId: get_greylist
parameters: []
requestBody:
content:
application/json:
schema:
type: object
properties: {}
responses:
"200":
description: OK
content:
application/json:
schema:
type: array
description: List of account names stored in the greylist
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
$ref: '#/components/schemas/Error'
/producer/add_greylist_accounts:
post:
summary: add_greylist_accounts
description: Adds accounts to grey list for producer node
description: Adds accounts to greylist for producer node. At least one account is required.
operationId: add_greylist_accounts
parameters: []
requestBody:
content:
application/json:
schema:
type: object
required:
- params
properties:
params:
type: object
properties:
accounts:
type: array
description: List of account names to add
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
accounts:
type: array
description: List of account names to add
items:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
responses:
"200":
"201":
description: OK
content:
application/json:
schema:
description: Returns Nothing
$ref: '#/components/schemas/OK'
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/remove_greylist_accounts:
post:
summary: remove_greylist_accounts
description: Removes accounts from greylist for producer node
description: Removes accounts from greylist for producer node. At least one account is required.
operationId: remove_greylist_accounts
parameters: []
requestBody:
content:
application/json:
schema:
type: object
required:
- params
properties:
params:
type: object
properties:
accounts:
type: array
description: List of account names to remove
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
accounts:
type: array
description: List of account names to remove
items:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
responses:
"200":
"201":
description: OK
content:
application/json:
schema:
type: array
description: List of account names stored in the greylist
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
$ref: '#/components/schemas/OK'
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/get_whitelist_blacklist:
post:
summary: get_whitelist_blacklist
description: Retreives the white list and black list for producer node
description: Retrieves the whitelist and blacklist for producer node. A JSON object containing whitelist and blacklist information.
operationId: get_whitelist_blacklist
parameters: []
requestBody:
content:
application/json:
schema:
type: object
properties: {}
responses:
"200":
"201":
description: OK
content:
application/json:
schema:
type: object
description: Defines the actor whitelist and blacklist, the contract whitelist and blacklist, the action blacklist and key blacklist
properties:
actor_whitelist:
type: array
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
actor_blacklist:
type: array
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
contract_whitelist:
type: array
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
contract_blacklist:
type: array
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
action_blacklist:
type: array
items:
@@ -308,116 +247,118 @@ paths:
description: Array of two string values, the account name as the first and action name as the second
items:
allOf:
- $ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
- $ref: "https://eosio.github.io/schemata/v2.0/oas/CppSignature.yaml"
- $ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
- $ref: "https://docs.eosnetwork.com/openapi/v2.0/CppSignature.yaml"
key_blacklist:
type: array
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/KeyType.yaml"
- $ref: "https://docs.eosnetwork.com/openapi/v2.0/KeyType.yaml"
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/set_whitelist_blacklist:
post:
summary: set_whitelist_blacklist
description: Sets the white list and black list for producer node
description: Defines the whitelist and blacklist for a producer node. Takes a JSON object containing whitelist and blacklist information.
operationId: set_whitelist_blacklist
parameters: []
requestBody:
content:
application/json:
schema:
type: object
required:
- params
properties:
params:
type: object
description: Defines the actor whitelist and blacklist, the contract whitelist and blacklist, the action blacklist and key blacklist
properties:
actor_whitelist:
type: array
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
actor_blacklist:
type: array
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
contract_whitelist:
type: array
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
contract_blacklist:
type: array
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
action_blacklist:
type: array
items:
type: array
description: Array of two string values, the account name as the first and action name as the second
items:
allOf:
- $ref: "https://eosio.github.io/schemata/v2.0/oas/Name.yaml"
- $ref: "https://eosio.github.io/schemata/v2.0/oas/CppSignature.yaml"
key_blacklist:
type: array
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/KeyType.yaml"
actor_whitelist:
type: array
items:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
actor_blacklist:
type: array
items:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
contract_whitelist:
type: array
items:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
contract_blacklist:
type: array
items:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
action_blacklist:
type: array
items:
type: array
description: Array of two string values, the account name as the first and action name as the second
items:
anyOf:
- $ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
- $ref: "https://docs.eosnetwork.com/openapi/v2.0/CppSignature.yaml"
key_blacklist:
type: array
items:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/KeyType.yaml"
responses:
"200":
"201":
description: OK
content:
application/json:
schema:
description: Returns Nothing
$ref: '#/components/schemas/OK'
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/create_snapshot:
post:
summary: create_snapshot
description: Creates a snapshot for producer node
description: Creates a snapshot for producer node. Returns error when unable to create a snapshot.
operationId: create_snapshot
parameters: []
requestBody:
content:
application/json:
schema:
type: object
required:
- next
properties:
next:
type: object
description: Defines the snapshot to be created
properties:
snapshot_name:
type: string
description: The name of the snapshot
head_block_id:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Sha256.yaml"
responses:
"200":
"201":
description: OK
content:
application/json:
schema:
description: Returns Nothing
type: object
properties:
head_block_id:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Sha256.yaml"
head_block_num:
type: integer
description: Highest block number on the chain
example: 5102
head_block_time:
type: string
description: Highest block unix timestamp
example: 2020-11-16T00:00:00.000
version:
type: integer
description: version number
example: 6
snapshot_name:
type: string
description: The path and file name of the snapshot
example: /home/me/nodes/node-name/snapshots/snapshot-0000999f99999f9f999f99f99ff9999f999f9fff99ff99ffff9f9f9fff9f9999.bin
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/get_integrity_hash:
post:
summary: get_integrity_hash
description: Retreives the integrity hash for producer node
description: Retrieves the integrity hash for producer node
operationId: get_integrity_hash
parameters: []
requestBody:
content:
application/json:
schema:
type: object
properties: {}
responses:
"200":
"201":
description: OK
content:
application/json:
@@ -425,69 +366,67 @@ paths:
type: object
description: Defines the integrity hash information details
properties:
integrity_hash:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Sha256.yaml"
head_block_id:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Sha256.yaml"
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Sha256.yaml"
integrity_hash:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Sha256.yaml"
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/schedule_protocol_feature_activations:
post:
summary: schedule_protocol_feature_activations
description: Schedule protocol feature activation for producer node
description: Schedule protocol feature activation for producer node. Note some features may require pre-activation. Will return error for duplicate requests or when feature required pre-activation.
operationId: schedule_protocol_feature_activations
parameters: []
requestBody:
content:
application/json:
schema:
type: object
required:
- schedule
properties:
schedule:
type: object
properties:
protocol_features_to_activate:
type: array
description: List of protocol features to activate
items:
$ref: "https://eosio.github.io/schemata/v2.0/oas/Sha256.yaml"
protocol_features_to_activate:
type: array
description: List of protocol features to activate
items:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Sha256.yaml"
responses:
"200":
"201":
description: OK
content:
application/json:
schema:
description: Returns Nothing
$ref: '#/components/schemas/OK'
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/get_supported_protocol_features:
post:
summary: get_supported_protocol_features
description: Retreives supported protocol features for producer node
description: Retrieves supported protocol features for producer node. Pass filters in as part of the request body.
operationId: get_supported_protocol_features
parameters: []
requestBody:
content:
application/json:
schema:
type: object
required:
- params
properties:
params:
type: object
description: Defines filters based on which to return the supported protocol features
properties:
exclude_disabled:
type: boolean
description: Exclude disabled protocol features
exclude_unactivatable:
type: boolean
description: Exclude unactivatable protocol features
exclude_disabled:
type: boolean
description: Exclude disabled protocol features
exclude_unactivatable:
type: boolean
description: Exclude unactivatable protocol features
example: false
responses:
"200":
"201":
description: OK
content:
application/json:
@@ -495,4 +434,196 @@ paths:
type: array
description: Variant type, an array of strings with the supported protocol features
items:
type: string
type: object
properties:
feature_digest:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Sha256.yaml"
subjective_restrictions:
type: object
properties:
enabled:
type: boolean
example: true
preactivation_required:
type: boolean
example: true
earliest_allowed_activation_time:
type: string
example: "1970-01-01T00:00:00.000"
description_digest:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Sha256.yaml"
dependencies:
type: array
items:
$ref: "https://docs.eosnetwork.com/openapi/v2.0/Sha256.yaml"
protocol_feature_type:
type: string
example: "builtin"
specification:
type: array
items:
type: object
properties:
name:
type: string
value:
type: string
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/producer/get_account_ram_corrections:
post:
summary: get_account_ram_corrections
description: Retrieves accounts with ram corrections.
operationId: get_account_ram_corrections
requestBody:
content:
application/json:
schema:
type: object
properties:
lower_bound:
type: integer
description: lowest account key
upper_bound:
type: integer
description: highest account key
limit:
type: integer
description: number of rows to scan
example: 10
reverse:
type: boolean
description: direction of search
example: false
responses:
"201":
description: OK
content:
application/json:
schema:
type: object
required:
- rows
properties:
rows:
type: array
items:
type: string
more:
type: array
items:
- $ref: "https://docs.eosnetwork.com/openapi/v2.0/Name.yaml"
"400":
description: client error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
securitySchemes: {}
schemas:
Error:
type: object
properties:
code:
type: integer
description: http return code
example: 400
message:
type: string
description: summary of error
example: Invalid Request
error:
type: object
description: details on the error
properties:
code:
type: integer
description: internal error code
example: 3200006
name:
type: string
description: name of error
example: invalid_http_request
what:
type: string
description: prettier version of error name
example: invalid http request
details:
type: array
description: list of additional information for debugging
items:
type: object
properties:
message:
type: string
description: debugging message
example: Unable to parse valid input from POST body
file:
type: string
description: file where error was thrown
example: http_plugin.hpp
line_number:
type: integer
description: line number in file where error was thrown
example: 246
method:
type: string
description: function executed when error occurred
example: parse_params
OK:
type: object
properties:
result:
type: string
description: status
example: ok
OK_PAUSED:
type: object
properties:
json:
type: boolean
description: true/false indicating paused state
example: true
Runtime_Options:
type: object
properties:
max_transaction_time:
type: integer
description: Max transaction time
example: 100
max_irreversible_block_age:
type: integer
description: Max irreversible block age
example: -1
produce_time_offset_us:
type: integer
description: Time offset
example: -100000
last_block_time_offset_us:
type: integer
description: Last block time offset
example: -200000
max_scheduled_transaction_time_per_block_ms:
type: integer
description: Max scheduled transaction time per block in ms
example: 100
subjective_cpu_leeway_us:
type: integer
description: in micro seconds
example: 10
incoming_defer_ratio:
type: string
description: Incoming defer ratio, parsed to double
example: "1.00000000000000000"
greylist_limit:
type: integer
description: limit on number of Names supported by greylist
example: 1000
@@ -114,7 +114,10 @@ public:
get_account_ram_corrections_result get_account_ram_corrections( const get_account_ram_corrections_params& params ) const;
void log_failed_transaction(const transaction_id_type& trx_id, const chain::packed_transaction_ptr& packed_trx_ptr, const char* reason) const;
void log_failed_transaction(const transaction_id_type& trx_id, const chain::packed_transaction_ptr& packed_trx_ptr, const char* reason) const;
// thread-safe, called when a new block is received
void received_block();
private:
std::shared_ptr<class producer_plugin_impl> my;
@@ -180,7 +180,8 @@ public:
fc_dlog( log, "Subjective billed accounts ${n} removed ${r}", ("n", orig_count)("r", orig_count - _account_subjective_bill_cache.size()) );
}
bool remove_expired( fc::logger& log, const fc::time_point& pending_block_time, const fc::time_point& now, const fc::time_point& deadline ) {
template <typename Yield>
bool remove_expired( fc::logger& log, const fc::time_point& pending_block_time, const fc::time_point& now, Yield&& yield ) {
bool exhausted = false;
auto& idx = _trx_cache_index.get<by_expiry>();
if( !idx.empty() ) {
@@ -189,7 +190,7 @@ public:
uint32_t num_expired = 0;
while( !idx.empty() ) {
if( deadline <= fc::time_point::now() ) {
if( yield() ) {
exhausted = true;
break;
}
+91 -60
View File
@@ -41,6 +41,13 @@ using std::vector;
using std::deque;
using boost::signals2::scoped_connection;
// in release/3.2+ move to fc logger.hpp
#define fc_tlog( LOGGER, FORMAT, ... ) \
FC_MULTILINE_MACRO_BEGIN \
if( (LOGGER).is_enabled( fc::log_level::all ) ) \
(LOGGER).log( FC_LOG_MESSAGE( all, FORMAT, __VA_ARGS__ ) ); \
FC_MULTILINE_MACRO_END
#undef FC_LOG_AND_DROP
#define LOG_AND_DROP() \
catch ( const guard_exception& e ) { \
@@ -197,8 +204,9 @@ public:
{
}
void set_max_failures_per_account( uint32_t max_failures ) {
max_failures_per_account = max_failures;
void set_max_failures_per_account( uint32_t max_failures, uint32_t size ) {
max_failures_per_account = max_failures;
reset_window_size_in_num_blocks = size;
}
void add( const account_name& n, int64_t exception_code ) {
@@ -218,10 +226,24 @@ public:
return false;
}
void report() const {
if( _log.is_enabled( fc::log_level::debug ) ) {
void report_and_clear(uint32_t block_num) {
if (last_reset_block_num != block_num && (block_num % reset_window_size_in_num_blocks == 0) ) {
report(block_num);
failed_accounts.clear();
last_reset_block_num = block_num;
}
}
fc::time_point next_reset_timepoint(uint32_t current_block_num, fc::time_point current_block_time) const {
auto num_blocks_to_reset = reset_window_size_in_num_blocks - (current_block_num % reset_window_size_in_num_blocks);
return current_block_time + fc::milliseconds(num_blocks_to_reset * eosio::chain::config::block_interval_ms);
}
private:
void report(uint32_t block_num) const {
if( _log.is_enabled(fc::log_level::debug)) {
auto now = fc::time_point::now();
for( const auto& e : failed_accounts ) {
for ( const auto& e : failed_accounts ) {
std::string reason;
if( e.second.is_deadline() ) reason += "deadline";
if( e.second.is_tx_cpu_usage() ) {
@@ -242,12 +264,6 @@ public:
}
}
}
void clear() {
failed_accounts.clear();
}
private:
struct account_failure {
enum class ex_fields : uint8_t {
ex_deadline_exception = 1,
@@ -282,6 +298,8 @@ private:
std::map<account_name, account_failure> failed_accounts;
uint32_t max_failures_per_account = 3;
uint32_t last_reset_block_num = 0;
uint32_t reset_window_size_in_num_blocks = 1;
const eosio::subjective_billing& subjective_billing;
};
@@ -322,6 +340,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
std::optional<named_thread_pool> _thread_pool;
std::atomic<int32_t> _max_transaction_time_ms; // modified by app thread, read by net_plugin thread pool
std::atomic<bool> _received_block{false}; // modified by net_plugin thread pool and app thread
fc::microseconds _max_irreversible_block_age_us;
int32_t _produce_time_offset_us = 0;
int32_t _last_block_time_offset_us = 0;
@@ -339,9 +358,6 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
chain_plugin* chain_plug = nullptr;
incoming::channels::block::channel_type::handle _incoming_block_subscription;
incoming::channels::transaction::channel_type::handle _incoming_transaction_subscription;
compat::channels::transaction_ack::channel_type& _transaction_ack_channel;
incoming::methods::block_sync::method_type::handle _incoming_block_sync_provider;
@@ -431,7 +447,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
_subjective_billing.abort_block();
}
bool on_incoming_block(const signed_block_ptr& block, const std::optional<block_id_type>& block_id) {
bool on_incoming_block(const signed_block_ptr& block, const std::optional<block_id_type>& block_id, const block_state_ptr& bsp) {
auto& chain = chain_plug->chain();
if ( _pending_block_mode == pending_block_mode::producing ) {
fc_wlog( _log, "dropped incoming block #${num} id: ${id}",
@@ -439,6 +455,11 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
return false;
}
// start a new speculative block, speculative start_block may have been interrupted
auto ensure = fc::make_scoped_exit([this](){
schedule_production_loop();
});
const auto& id = block_id ? *block_id : block->calculate_id();
auto blk_num = block->block_num();
@@ -452,16 +473,14 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
if( existing ) { return false; }
// start processing of block
auto bsf = chain.create_block_state_future( id, block );
std::future<block_state_ptr> bsf;
if( !bsp ) {
bsf = chain.create_block_state_future( id, block );
}
// abort the pending block
abort_block();
// exceptions throw out, make sure we restart our loop
auto ensure = fc::make_scoped_exit([this](){
schedule_production_loop();
});
// push the new block
auto handle_error = [&](const auto& e)
{
@@ -471,7 +490,8 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
};
try {
chain.push_block( bsf, [this]( const branch_type& forked_branch ) {
const block_state_ptr& bspr = bsp ? bsp : bsf.get();
chain.push_block( bspr, [this]( const branch_type& forked_branch ) {
_unapplied_transactions.add_forked( forked_branch );
}, [this]( const transaction_id_type& id ) {
return _unapplied_transactions.get_trx( id );
@@ -673,8 +693,9 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
auto first_auth = trx->packed_trx()->get_transaction().first_authorizer();
if( _account_fails.failure_limit( first_auth ) ) {
send_response( std::static_pointer_cast<fc::exception>( std::make_shared<tx_cpu_usage_exceeded>(
FC_LOG_MESSAGE( error, "transaction ${id} exceeded failure limit for account ${a}",
("id", trx->id())("a", first_auth) ) ) ) );
FC_LOG_MESSAGE( error, "transaction ${id} exceeded failure limit for account ${a} until ${next_reset_time}",
("id", trx->id())("a", first_auth)
("next_reset_time", _account_fails.next_reset_timepoint(chain.head_block_num(),chain.head_block_time())) ) ) ) );
return true;
}
@@ -694,7 +715,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
auto prev_billed_cpu_time_us = trx->billed_cpu_time_us;
auto trace = chain.push_transaction( trx, block_deadline, max_trx_time, prev_billed_cpu_time_us, false, sub_bill );
fc_dlog( _trx_failed_trace_log, "Subjective bill for ${a}: ${b} elapsed ${t}us", ("a",first_auth)("b",sub_bill)("t",trace->elapsed));
fc_tlog( _log, "Subjective bill for ${a}: ${b} elapsed ${t}us", ("a",first_auth)("b",sub_bill)("t",trace->elapsed));
if( trace->except ) {
if( exception_is_exhausted( *trace->except ) ) {
_unapplied_transactions.add_incoming( trx, persist_until_expired, return_failure_traces, next );
@@ -786,6 +807,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
exhausted
};
inline bool should_interrupt_start_block( const fc::time_point& deadline ) const;
start_block_result start_block();
fc::time_point calculate_pending_block_time() const;
@@ -876,7 +898,9 @@ void producer_plugin::set_program_options(
("subjective-cpu-leeway-us", boost::program_options::value<int32_t>()->default_value( config::default_subjective_cpu_leeway_us ),
"Time in microseconds allowed for a transaction that starts with insufficient CPU quota to complete and cover its CPU usage.")
("subjective-account-max-failures", boost::program_options::value<uint32_t>()->default_value(3),
"Sets the maximum amount of failures that are allowed for a given account per block.")
"Sets the maximum amount of failures that are allowed for a given account per window size.")
("subjective-account-max-failures-window-size", boost::program_options::value<uint32_t>()->default_value(1),
"Sets the window size in number of blocks for subjective-account-max-failures.")
("subjective-account-decay-time-minutes", bpo::value<uint32_t>()->default_value( config::account_cpu_usage_average_window_ms / 1000 / 60 ),
"Sets the time to return full subjective cpu for accounts")
("incoming-defer-ratio", bpo::value<double>()->default_value(1.0),
@@ -1026,7 +1050,13 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_
my->_keosd_provider_timeout_us = fc::milliseconds(options.at("keosd-provider-timeout").as<int32_t>());
my->_account_fails.set_max_failures_per_account( options.at("subjective-account-max-failures").as<uint32_t>() );
auto subjective_account_max_failures_window_size = options.at("subjective-account-max-failures-window-size").as<uint32_t>();
EOS_ASSERT( subjective_account_max_failures_window_size > 0, plugin_config_exception,
"subjective-account-max-failures-window-size ${s} must be greater than 0", ("s", subjective_account_max_failures_window_size) );
my->_account_fails.set_max_failures_per_account( options.at("subjective-account-max-failures").as<uint32_t>(),
subjective_account_max_failures_window_size );
my->_produce_time_offset_us = options.at("produce-time-offset-us").as<int32_t>();
EOS_ASSERT( my->_produce_time_offset_us <= 0 && my->_produce_time_offset_us >= -config::block_interval_us, plugin_config_exception,
@@ -1128,23 +1158,9 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_
}
}
my->_incoming_block_subscription = app().get_channel<incoming::channels::block>().subscribe(
[this](const signed_block_ptr& block) {
try {
my->on_incoming_block(block, {});
} LOG_AND_DROP();
});
my->_incoming_transaction_subscription = app().get_channel<incoming::channels::transaction>().subscribe(
[this](const packed_transaction_ptr& trx) {
try {
my->on_incoming_transaction_async(trx, false, false, false, [](const auto&){});
} LOG_AND_DROP();
});
my->_incoming_block_sync_provider = app().get_method<incoming::methods::block_sync>().register_provider(
[this](const signed_block_ptr& block, const std::optional<block_id_type>& block_id) {
return my->on_incoming_block(block, block_id);
[this](const signed_block_ptr& block, const std::optional<block_id_type>& block_id, const block_state_ptr& bsp) {
return my->on_incoming_block(block, block_id, bsp);
});
my->_incoming_transaction_async_provider = app().get_method<incoming::methods::transaction_async>().register_provider(
@@ -1242,6 +1258,7 @@ void producer_plugin::plugin_shutdown() {
}
app().post( 0, [me = my](){} ); // keep my pointer alive until queue is drained
fc_ilog(_log, "exit shutdown");
}
void producer_plugin::handle_sighup() {
@@ -1679,6 +1696,14 @@ fc::time_point producer_plugin_impl::calculate_block_deadline( const fc::time_po
}
}
bool producer_plugin_impl::should_interrupt_start_block( const fc::time_point& deadline ) const {
if( _pending_block_mode == pending_block_mode::producing ) {
return deadline <= fc::time_point::now();
}
// if we can produce then honor deadline so production starts on time
return (!_producers.empty() && deadline <= fc::time_point::now()) || _received_block;
}
producer_plugin_impl::start_block_result producer_plugin_impl::start_block() {
chain::controller& chain = chain_plug->chain();
@@ -1687,7 +1712,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() {
const auto& hbs = chain.head_block_state();
if( chain.get_terminate_at_block() > 0 && chain.get_terminate_at_block() < chain.head_block_num() ) {
if( chain.get_terminate_at_block() > 0 && chain.get_terminate_at_block() <= chain.head_block_num() ) {
ilog("Reached configured maximum block ${num}; terminating", ("num", chain.get_terminate_at_block()));
app().quit();
return start_block_result::failed;
@@ -1854,16 +1879,19 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() {
}
try {
_account_fails.report_and_clear(hbs->block_num);
if( !remove_expired_trxs( preprocess_deadline ) )
return start_block_result::exhausted;
if( !remove_expired_blacklisted_trxs( preprocess_deadline ) )
return start_block_result::exhausted;
if( !_subjective_billing.remove_expired( _log, chain.pending_block_time(), fc::time_point::now(), preprocess_deadline ) )
if( !_subjective_billing.remove_expired( _log, chain.pending_block_time(), fc::time_point::now(),
[&](){ return should_interrupt_start_block( preprocess_deadline ); } ) ) {
return start_block_result::exhausted;
}
// limit execution of pending incoming to once per block
size_t pending_incoming_process_limit = _unapplied_transactions.incoming_size();
_account_fails.clear();
if( !process_unapplied_trxs( preprocess_deadline ) )
return start_block_result::exhausted;
@@ -1882,7 +1910,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() {
if( app().is_quiting() ) // db guard exception above in LOG_AND_DROP could have called app().quit()
return start_block_result::failed;
if (preprocess_deadline <= fc::time_point::now() || block_is_exhausted()) {
if ( should_interrupt_start_block( preprocess_deadline ) || block_is_exhausted() ) {
return start_block_result::exhausted;
} else {
if( !process_incoming_trxs( preprocess_deadline, pending_incoming_process_limit ) )
@@ -1913,7 +1941,7 @@ bool producer_plugin_impl::remove_expired_trxs( const fc::time_point& deadline )
size_t num_expired_persistent = 0;
size_t num_expired_other = 0;
size_t orig_count = _unapplied_transactions.size();
bool exhausted = !_unapplied_transactions.clear_expired( pending_block_time, deadline,
bool exhausted = !_unapplied_transactions.clear_expired( pending_block_time, [&](){ return should_interrupt_start_block( deadline ); },
[chain_plug = chain_plug, &num_expired_persistent, &num_expired_other, pbm = _pending_block_mode,
&chain, has_producers = !_producers.empty()]( const packed_transaction_ptr& packed_trx_ptr, trx_enum_type trx_type ) {
if( trx_type == trx_enum_type::persisted ) {
@@ -1955,7 +1983,7 @@ bool producer_plugin_impl::remove_expired_trxs( const fc::time_point& deadline )
}
});
if( exhausted ) {
if( exhausted && _pending_block_mode == pending_block_mode::producing ) {
fc_wlog( _log, "Unable to process all expired transactions in unapplied queue before deadline, "
"Persistent expired ${persistent_expired}, Other expired ${other_expired}",
("persistent_expired", num_expired_persistent)("other_expired", num_expired_other) );
@@ -1981,7 +2009,7 @@ bool producer_plugin_impl::remove_expired_blacklisted_trxs( const fc::time_point
int orig_count = _blacklisted_transactions.size();
while (!blacklist_by_expiry.empty() && blacklist_by_expiry.begin()->expiry <= lib_time) {
if (deadline <= fc::time_point::now()) {
if ( should_interrupt_start_block( deadline ) ) {
exhausted = true;
break;
}
@@ -2009,7 +2037,7 @@ bool producer_plugin_impl::process_unapplied_trxs( const fc::time_point& deadlin
auto end_itr = (_pending_block_mode == pending_block_mode::producing) ?
_unapplied_transactions.unapplied_end() : _unapplied_transactions.persisted_end();
while( itr != end_itr ) {
if( deadline <= fc::time_point::now() ) {
if( should_interrupt_start_block( deadline ) ) {
exhausted = true;
break;
}
@@ -2024,8 +2052,9 @@ bool producer_plugin_impl::process_unapplied_trxs( const fc::time_point& deadlin
++num_failed;
if( itr->next ) {
itr->next( std::make_shared<tx_cpu_usage_exceeded>(
FC_LOG_MESSAGE( error, "transaction ${id} exceeded failure limit for account ${a}",
("id", trx->id())("a", first_auth) ) ) );
FC_LOG_MESSAGE( error, "transaction ${id} exceeded failure limit for account ${a} until ${next_reset_time}",
("id", trx->id())("a", first_auth)
("next_reset_time", _account_fails.next_reset_timepoint(chain.head_block_num(),chain.head_block_time())) ) ) );
}
itr = _unapplied_transactions.erase( itr );
continue;
@@ -2048,7 +2077,7 @@ bool producer_plugin_impl::process_unapplied_trxs( const fc::time_point& deadlin
|| trx->read_only;
auto trace = chain.push_transaction( trx, deadline, max_trx_time, prev_billed_cpu_time_us, false, sub_bill );
fc_dlog( _trx_failed_trace_log, "Subjective unapplied bill for ${a}: ${b} prev ${t}us", ("a",first_auth)("b",prev_billed_cpu_time_us)("t",trace->elapsed));
fc_tlog( _log, "Subjective unapplied bill for ${a}: ${b} prev ${t}us", ("a",first_auth)("b",prev_billed_cpu_time_us)("t",trace->elapsed));
if( trace->except ) {
if( exception_is_exhausted( *trace->except ) ) {
if( block_is_exhausted() ) {
@@ -2057,7 +2086,7 @@ bool producer_plugin_impl::process_unapplied_trxs( const fc::time_point& deadlin
break;
}
} else {
fc_dlog( _trx_failed_trace_log, "Subjective unapplied bill for failed ${a}: ${b} prev ${t}us", ("a",first_auth)("b",prev_billed_cpu_time_us)("t",trace->elapsed));
fc_tlog( _log, "Subjective unapplied bill for failed ${a}: ${b} prev ${t}us", ("a",first_auth)("b",prev_billed_cpu_time_us)("t",trace->elapsed));
auto failure_code = trace->except->code();
if( failure_code != tx_duplicate::code_value ) {
// this failed our configured maximum transaction time, we don't want to replay it
@@ -2076,7 +2105,7 @@ bool producer_plugin_impl::process_unapplied_trxs( const fc::time_point& deadlin
continue;
}
} else {
fc_dlog( _trx_successful_trace_log, "Subjective unapplied bill for success ${a}: ${b} prev ${t}us", ("a",first_auth)("b",prev_billed_cpu_time_us)("t",trace->elapsed));
fc_tlog( _log, "Subjective unapplied bill for success ${a}: ${b} prev ${t}us", ("a",first_auth)("b",prev_billed_cpu_time_us)("t",trace->elapsed));
// if db_read_mode SPECULATIVE then trx is in the pending block and not immediately reverted
if (!disable_subjective_billing)
_subjective_billing.subjective_bill( trx->id(), trx->packed_trx()->expiration(), first_auth, trace->elapsed,
@@ -2210,7 +2239,7 @@ bool producer_plugin_impl::process_incoming_trxs( const fc::time_point& deadline
auto itr = _unapplied_transactions.incoming_begin();
auto end = _unapplied_transactions.incoming_end();
while( pending_incoming_process_limit && itr != end ) {
if (deadline <= fc::time_point::now()) {
if ( should_interrupt_start_block( deadline ) ) {
exhausted = true;
break;
}
@@ -2250,6 +2279,7 @@ bool producer_plugin_impl::block_is_exhausted() const {
// -> Idle
// --> Start block B (block time y.000) at time x.500
void producer_plugin_impl::schedule_production_loop() {
_received_block = false;
_timer.cancel();
auto result = start_block();
@@ -2437,9 +2467,6 @@ void producer_plugin_impl::produce_block() {
block_state_ptr new_bs = chain.head_block_state();
_account_fails.report();
_account_fails.clear();
ilog("Produced block ${id}... #${n} @ ${t} signed by ${p} [trxs: ${count}, lib: ${lib}, confirmed: ${confs}]",
("p",new_bs->header.producer)("id",new_bs->id.str().substr(8,16))
("n",new_bs->block_num)("t",new_bs->header.timestamp)
@@ -2447,6 +2474,10 @@ void producer_plugin_impl::produce_block() {
}
void producer_plugin::received_block() {
my->_received_block = true;
}
void producer_plugin::log_failed_transaction(const transaction_id_type& trx_id, const packed_transaction_ptr& packed_trx_ptr, const char* reason) const {
fc_dlog(_trx_failed_trace_log, "[TRX_TRACE] Speculative execution is REJECTING tx: ${txid} : ${why}",
("txid", trx_id)("why", reason));
@@ -50,7 +50,7 @@ BOOST_AUTO_TEST_CASE( subjective_bill_test ) {
BOOST_CHECK_EQUAL( 9, sub_bill.get_subjective_bill(b, now) );
// expires transactions but leaves them in the decay at full value
sub_bill.remove_expired( log, now + fc::microseconds(1), now, fc::time_point::maximum() );
sub_bill.remove_expired( log, now + fc::microseconds(1), now, [](){ return false; } );
BOOST_CHECK_EQUAL( 13+11, sub_bill.get_subjective_bill(a, now) );
BOOST_CHECK_EQUAL( 9, sub_bill.get_subjective_bill(b, now) );
@@ -138,7 +138,7 @@ BOOST_AUTO_TEST_CASE( subjective_bill_test ) {
BOOST_CHECK_EQUAL( 1024 + 1024, sub_bill.get_subjective_bill(a, now) );
BOOST_CHECK_EQUAL( 1024, sub_bill.get_subjective_bill(b, now) );
sub_bill.remove_expired( log, now, now, fc::time_point::maximum() );
sub_bill.remove_expired( log, now, now, [](){ return false; } );
BOOST_CHECK_EQUAL( 1024 + 1024, sub_bill.get_subjective_bill(a, now) );
BOOST_CHECK_EQUAL( 1024, sub_bill.get_subjective_bill(b, now) );
@@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE( subjective_bill_test ) {
BOOST_CHECK_EQUAL( 1024, sub_bill.get_subjective_bill(a, endtime) );
BOOST_CHECK_EQUAL( 0, sub_bill.get_subjective_bill(b, endtime) );
sub_bill.remove_expired( log, now + fc::microseconds(1), now, fc::time_point::maximum() );
sub_bill.remove_expired( log, now + fc::microseconds(1), now, [](){ return false; } );
BOOST_CHECK_EQUAL( 1024 + 1024, sub_bill.get_subjective_bill(a, now) );
BOOST_CHECK_EQUAL( 1024, sub_bill.get_subjective_bill(b, now) );
+4 -5
View File
@@ -307,8 +307,11 @@ namespace eosio::trace_api {
_maintenance_condition.wait(lock);
}
if (_maintenance_shutdown) {
break;
}
uint32_t best_known_lib = _best_known_lib;
bool shutdown = _maintenance_shutdown;
lock.unlock();
log(std::string("Waking up to handle lib: ") + std::to_string(best_known_lib));
@@ -319,10 +322,6 @@ namespace eosio::trace_api {
last_lib = best_known_lib;
} FC_LOG_AND_DROP();
}
if (shutdown) {
break;
}
}
});
}
@@ -455,6 +455,7 @@ void trace_api_plugin::plugin_startup() {
void trace_api_plugin::plugin_shutdown() {
my->plugin_shutdown();
rpc->plugin_shutdown();
fc_ilog( _log, "exit shutdown");
}
void trace_api_plugin::handle_sighup() {
+12
View File
@@ -71,6 +71,17 @@ bfs::path determine_home_directory()
return home;
}
enum return_codes {
OTHER_FAIL = -2,
INITIALIZE_FAIL = -1,
SUCCESS = 0,
BAD_ALLOC = 1,
DATABASE_DIRTY = 2,
FIXED_REVERSIBLE = SUCCESS,
EXTRACTED_GENESIS = SUCCESS,
NODE_MANAGEMENT_SUCCESS = 5
};
int main(int argc, char** argv)
{
try {
@@ -90,6 +101,7 @@ int main(int argc, char** argv)
opts.count("print-default-config")) {
return 0;
}
return INITIALIZE_FAIL;
}
initialize_logging();
auto& http = app().get_plugin<http_plugin>();
+1 -1
View File
@@ -132,7 +132,7 @@ pushdir ${LEAP_DIR}
# build Leap
echo "Building Leap ${SCRIPT_DIR}"
try cmake -DCMAKE_TOOLCHAIN_FILE=${SCRIPT_DIR}/pinned_toolchain.cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=${LLVM_DIR}/lib/cmake -DCMAKE_PREFIX_PATH=${BOOST_DIR}/bin ${SCRIPT_DIR}/..
try cmake -DCMAKE_TOOLCHAIN_FILE=${SCRIPT_DIR}/pinned_toolchain.cmake -DCMAKE_INSTALL_PREFIX=${LEAP_PINNED_INSTALL_PREFIX:-/usr/local} -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=${LLVM_DIR}/lib/cmake -DCMAKE_PREFIX_PATH=${BOOST_DIR}/bin ${SCRIPT_DIR}/..
try make -j${JOBS}
try cpack
+3 -3
View File
@@ -120,11 +120,11 @@ add_test(NAME restart-scenarios-test-hard_replay COMMAND tests/restart-scenarios
set_property(TEST restart-scenarios-test-hard_replay PROPERTY LABELS nonparallelizable_tests)
add_test(NAME restart-scenarios-test-none COMMAND tests/restart-scenarios-test.py -c none --kill-sig term -p4 -v --clean-run --dump-error-details WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST restart-scenarios-test-none PROPERTY LABELS nonparallelizable_tests)
add_test(NAME terminate-scenarios-test-resync COMMAND tests/terminate-scenarios-test.py -p 1 -c resync --kill-count 1 --terminate-at-block 10 --kill-sig term --dump-error-details WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_test(NAME terminate-scenarios-test-resync COMMAND tests/terminate-scenarios-test.py -c resync --terminate-at-block 10 --kill-sig term --dump-error-details WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST terminate-scenarios-test-resync PROPERTY LABELS nonparallelizable_tests)
add_test(NAME terminate-scenarios-test-replay COMMAND tests/terminate-scenarios-test.py -p 1 -c replay --kill-count 1 --terminate-at-block 10 --kill-sig term --dump-error-details WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_test(NAME terminate-scenarios-test-replay COMMAND tests/terminate-scenarios-test.py -c replay --terminate-at-block 10 --kill-sig term --dump-error-details WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST terminate-scenarios-test-replay PROPERTY LABELS nonparallelizable_tests)
add_test(NAME terminate-scenarios-test-hard_replay COMMAND tests/terminate-scenarios-test.py -p 1 -c hardReplay --kill-count 1 --terminate-at-block 10 --kill-sig term --dump-error-details WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_test(NAME terminate-scenarios-test-hard_replay COMMAND tests/terminate-scenarios-test.py -c hardReplay --terminate-at-block 10 --kill-sig term --dump-error-details WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST terminate-scenarios-test-hard_replay PROPERTY LABELS nonparallelizable_tests)
add_test(NAME validate_dirty_db_test COMMAND tests/validate-dirty-db.py -v --clean-run --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST validate_dirty_db_test PROPERTY LABELS nonparallelizable_tests)
+2 -2
View File
@@ -1430,14 +1430,14 @@ class Cluster(object):
time.sleep(1) # Give processes time to stand down
return True
def relaunchEosInstances(self, cachePopen=False, nodeArgs=""):
def relaunchEosInstances(self, cachePopen=False, nodeArgs="", waitForTerm=False):
chainArg=self.__chainSyncStrategy.arg + " " + nodeArgs
newChain= False if self.__chainSyncStrategy.name in [Utils.SyncHardReplayTag, Utils.SyncNoneTag] else True
for i in range(0, len(self.nodes)):
node=self.nodes[i]
if node.killed and not node.relaunch(chainArg, newChain=newChain, cachePopen=cachePopen):
if node.killed and not node.relaunch(chainArg, newChain=newChain, cachePopen=cachePopen, waitForTerm=waitForTerm):
return False
return True
+6 -5
View File
@@ -1210,7 +1210,7 @@ class Node(object):
# pylint: disable=too-many-locals
# If nodeosPath is equal to None, it will use the existing nodeos path
def relaunch(self, chainArg=None, newChain=False, skipGenesis=True, timeout=Utils.systemWaitTimeout, addSwapFlags=None, cachePopen=False, nodeosPath=None, waitForTerm=True):
def relaunch(self, chainArg=None, newChain=False, skipGenesis=True, timeout=Utils.systemWaitTimeout, addSwapFlags=None, cachePopen=False, nodeosPath=None, waitForTerm=False):
assert(self.pid is None)
assert(self.killed)
@@ -1265,15 +1265,16 @@ class Node(object):
except subprocess.TimeoutExpired:
return False
with open(popen.errfile.name, 'r') as f:
if "Reached configured maximum block 10; terminating" in f.read():
if "successfully exiting" in f.read():
return True
else:
return False
if "terminate-at-block" not in cmd or not waitForTerm:
isAlive=Utils.waitForBool(isNodeAlive, timeout, sleepTime=1)
else:
if waitForTerm:
isAlive=Utils.waitForBoolWithArg(didNodeExitGracefully, self.popenProc, timeout, sleepTime=1)
else:
isAlive=Utils.waitForBool(isNodeAlive, timeout, sleepTime=1)
if isAlive:
Utils.Print("Node relaunch was successful.")
else:
+2
View File
@@ -375,6 +375,8 @@ try:
if preKillBlockProducer == "defproducerj" or preKillBlockProducer == "defproducerk":
# wait for defproduceri so there is plenty of time to send kill before defproducerk
nonProdNode.waitForProducer("defproduceri")
preKillBlockNum=nonProdNode.getBlockNum()
preKillBlockProducer=nonProdNode.getBlockProducerByNum(preKillBlockNum)
Print("preKillBlockProducer = {}".format(preKillBlockProducer))
# kill at last block before defproducerl, since the block it is killed on will get propagated
killAtProducer="defproducerk"
+27 -47
View File
@@ -25,8 +25,6 @@ relaunchTimeout = 10
numOfProducers = 1
totalNodes = 4
termAtFutureBlockNum = 30
# Parse command line arguments
args = TestHelper.parse_args({
"-v",
@@ -47,7 +45,7 @@ keepLogs = args.keep_logs
# Wrapper function to execute test
# This wrapper function will resurrect the node to be tested, and shut
# it down by the end of the test
def executeTest(cluster, producerNode, testNodeId, testNodeArgs, resultMsgs):
def executeTest(cluster, testNodeId, testNodeArgs, resultMsgs):
testNode = None
testResult = False
resultDesc = "!!!BUG IS CONFIRMED ON TEST CASE #{} ({})".format(
@@ -63,17 +61,12 @@ def executeTest(cluster, producerNode, testNodeId, testNodeArgs, resultMsgs):
)
)
# Get current information from the producer.
producerNode.waitForHeadToAdvance()
# Launch the node with the terminate-at-block option specified
# in testNodeArgs. The option for each node has already
# been set via specificExtraNodeosArg in the cluster launch.
cluster.launchUnstarted(cachePopen=True)
testNode = cluster.getNode(testNodeId)
assert not testNode.verifyAlive() # resets pid so reluanch works
testNode.relaunch(addSwapFlags={"--terminate-at-block": "9999999"}, cachePopen=True)
# Wait for node to start up.
time.sleep(10)
time.sleep(3)
# Check the node stops at the correct block.
checkStatus(testNode, testNodeArgs)
@@ -107,8 +100,7 @@ def checkStatus(testNode, testNodeArgs):
"""Test --terminate-at-block stops at the correct block."""
Print(" ".join([
"The test node has begun receiving from the producing node and",
"is expected to stop at or little bigger than the block number",
"specified here: ",
"is expected to stop at the block number specified here: ",
testNodeArgs
]))
@@ -122,6 +114,12 @@ def checkStatus(testNode, testNodeArgs):
else:
checkHeadOrSpeculative(head, lib)
# Check for the terminate at block message.
match = re.search(r"--terminate-at-block (\d+)", testNodeArgs)
termAtBlock = int(match.group(1))
assert head == termAtBlock, f"head {head} termAtBlock {termAtBlock}"
def checkReplay(testNode, testNodeArgs):
"""Test --terminate-at-block with --replay-blockchain."""
@@ -135,20 +133,18 @@ def checkReplay(testNode, testNodeArgs):
testNodeArgs
]))
testNode.relaunch(chainArg="--replay-blockchain", cachePopen=True)
assert not testNode.verifyAlive()
testNode.relaunch(chainArg="--replay-blockchain", addSwapFlags={"--terminate-at-block": "9999999"}, cachePopen=True)
# Wait for node to finish up.
time.sleep(10)
time.sleep(3)
# Check for the terminate at block message.
match = re.search(r"--terminate-at-block=(\d+)", testNodeArgs)
match = re.search(r"--terminate-at-block (\d+)", testNodeArgs)
termAtBlock = int(match.group(1))
termMsg = "Reached configured maximum block {}; terminating".format(
termAtBlock
)
assert checkLog(testNode.popenProc.errfile.name, termMsg)
head, lib = getBlockNumInfo(testNode)
assert head == termAtBlock, f"head {head} termAtBlock {termAtBlock}"
def getBlockNumInfo(testNode):
@@ -159,11 +155,12 @@ def getBlockNumInfo(testNode):
info = testNode.getInfo()
if not info:
break
continue
try:
head = info["head_block_num"]
lib = info["last_irreversible_block_num"]
break
except KeyError:
pass
@@ -172,26 +169,6 @@ def getBlockNumInfo(testNode):
return head, lib
def checkLog(log, message, sleepDuration=1, maxAttempt=10):
attemptCnt = 0
found = False
while not found and attemptCnt < maxAttempt:
try:
with open(log, "r") as f:
found = message in f.read()
except OSError:
pass
if not found:
time.sleep(sleepDuration)
attemptCnt = attemptCnt + 1
return found
def checkIrreversible(head, lib):
assert head == lib, (
"Head ({}) should be equal to lib ({})".format(head, lib)
@@ -215,9 +192,9 @@ testSuccessful = False
try:
specificNodeosArgs = {
0 : "--enable-stale-production",
1 : "--read-mode irreversible --terminate-at-block=250",
2 : "--read-mode speculative --terminate-at-block=550",
3 : "--read-mode head --terminate-at-block=850",
1 : "--read-mode irreversible --terminate-at-block 75",
2 : "--read-mode speculative --terminate-at-block 100",
3 : "--read-mode head --terminate-at-block 125",
}
traceNodeosArgs = " --plugin eosio::trace_api_plugin --trace-no-abis "
@@ -229,7 +206,6 @@ try:
prodCount=numOfProducers,
totalProducers=numOfProducers,
totalNodes=totalNodes,
unstartedNodes=totalNodes - numOfProducers,
pnodes=1,
useBiosBootFile=False,
topo="mesh",
@@ -240,6 +216,11 @@ try:
producingNodeId = 0
producingNode = cluster.getNode(producingNodeId)
# wait for all to terminate, needs to be larger than largest terminate-at-block
producingNode.waitForBlock( 150, timeout=150 )
cluster.biosNode.kill(signal.SIGTERM)
producingNode.kill(signal.SIGTERM)
# Start executing test cases here
Utils.Print("Script Begin .............................")
@@ -250,7 +231,6 @@ try:
success = executeTest(
cluster,
producingNode,
nodeId,
nodeArgs,
testResultMsgs
+9 -9
View File
@@ -20,16 +20,15 @@ import random
Print=Utils.Print
errorExit=Utils.errorExit
args=TestHelper.parse_args({"-p","-d","-s","-c","--kill-sig","--kill-count","--keep-logs"
args=TestHelper.parse_args({"-d","-s","-c","--kill-sig","--keep-logs"
,"--dump-error-details","-v","--leave-running","--clean-run"
,"--terminate-at-block"})
pnodes=args.p
pnodes=1
topo=args.s
delay=args.d
chainSyncStrategyStr=args.c
debug=args.v
total_nodes = pnodes
killCount=args.kill_count if args.kill_count > 0 else 1
killSignal=args.kill_sig
killEosInstances= not args.leave_running
dumpErrorDetails=args.dump_error_details
@@ -70,19 +69,20 @@ try:
if not cluster.waitOnClusterBlockNumSync(3):
errorExit("Cluster never stabilized")
Print("Kill %d cluster node instances." % (killCount))
if cluster.killSomeEosInstances(killCount, killSignal) is False:
Print("Kill cluster node instance.")
if cluster.killSomeEosInstances(1, killSignal) is False:
errorExit("Failed to kill Eos instances")
assert not cluster.getNode(0).verifyAlive()
Print("nodeos instances killed.")
Print ("Relaunch dead cluster nodes instances.")
Print ("Relaunch dead cluster node instance.")
nodeArg = "--terminate-at-block %d" % terminate if terminate > 0 else ""
if nodeArg != "":
if chainSyncStrategyStr == "hardReplay":
nodeArg += " --truncate-at-block %d" % terminate
if cluster.relaunchEosInstances(cachePopen=True, nodeArgs=nodeArg) is False:
errorExit("Failed to relaunch Eos instances")
Print("nodeos instances relaunched.")
if cluster.relaunchEosInstances(cachePopen=True, nodeArgs=nodeArg, waitForTerm=(terminate > 0)) is False:
errorExit("Failed to relaunch Eos instance")
Print("nodeos instance relaunched.")
testSuccessful=True
finally:
@@ -332,9 +332,9 @@ def stepSetSystemContract():
retry(args.cleos + 'push action eosio activate \'["ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43"]\' -p eosio@active')
# DISALLOW_EMPTY_PRODUCER_SCHEDULE
retry(args.cleos + 'push action eosio activate \'["68dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428"]\' -p eosio@active')
# FIX_LINKAUTH_RESTRICTION
# FIX_LINKAUTH_RESTRICTION
retry(args.cleos + 'push action eosio activate \'["e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526"]\' -p eosio@active')
# REPLACE_DEFERRED
# REPLACE_DEFERRED
retry(args.cleos + 'push action eosio activate \'["ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99"]\' -p eosio@active')
# NO_DUPLICATE_DEFERRED_ID
retry(args.cleos + 'push action eosio activate \'["4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f"]\' -p eosio@active')
@@ -346,6 +346,12 @@ def stepSetSystemContract():
retry(args.cleos + 'push action eosio activate \'["4fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2"]\' -p eosio@active')
# WTMSIG_BLOCK_SIGNATURES
retry(args.cleos + 'push action eosio activate \'["299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707"]\' -p eosio@active')
# GET_CODE_HASH
retry(args.cleos + 'push action eosio activate \'["bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99"]\' -p eosio@active')
# GET_BLOCK_NUM
retry(args.cleos + 'push action eosio activate \'["35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b"]\' -p eosio@active')
# CRYPTO_PRIMITIVES
retry(args.cleos + 'push action eosio activate \'["6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc"]\' -p eosio@active')
sleep(1)
# install eosio.system latest version
+4 -4
View File
@@ -44,9 +44,9 @@ BOOST_AUTO_TEST_CASE(block_with_invalid_tx_test)
// Push block with invalid transaction to other chain
tester validator;
auto bs = validator.control->create_block_state_future( copy_b->calculate_id(), copy_b );
auto bsf = validator.control->create_block_state_future( copy_b->calculate_id(), copy_b );
validator.control->abort_block();
BOOST_REQUIRE_EXCEPTION(validator.control->push_block( bs, forked_branch_callback{}, trx_meta_cache_lookup{} ), fc::exception ,
BOOST_REQUIRE_EXCEPTION(validator.control->push_block( bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} ), fc::exception ,
[] (const fc::exception &e)->bool {
return e.code() == account_name_exists_exception::code_value ;
}) ;
@@ -82,9 +82,9 @@ BOOST_AUTO_TEST_CASE(block_with_invalid_tx_mroot_test)
// Push block with invalid transaction to other chain
tester validator;
auto bs = validator.control->create_block_state_future( copy_b->calculate_id(), copy_b );
auto bsf = validator.control->create_block_state_future( copy_b->calculate_id(), copy_b );
validator.control->abort_block();
BOOST_REQUIRE_EXCEPTION(validator.control->push_block( bs, forked_branch_callback{}, trx_meta_cache_lookup{} ), fc::exception ,
BOOST_REQUIRE_EXCEPTION(validator.control->push_block( bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} ), fc::exception ,
[] (const fc::exception &e)->bool {
return e.code() == block_validate_exception::code_value &&
e.to_detail_string().find("invalid block transaction merkle root") != std::string::npos;
+2 -2
View File
@@ -267,9 +267,9 @@ BOOST_AUTO_TEST_CASE( forking ) try {
signed_block bad_block = std::move(*b);
bad_block.action_mroot = bad_block.previous;
auto bad_id = bad_block.calculate_id();
auto bad_block_bs = c.control->create_block_state_future( bad_id, std::make_shared<signed_block>(std::move(bad_block)) );
auto bad_block_bsf = c.control->create_block_state_future( bad_id, std::make_shared<signed_block>(std::move(bad_block)) );
c.control->abort_block();
BOOST_REQUIRE_EXCEPTION(c.control->push_block( bad_block_bs, forked_branch_callback{}, trx_meta_cache_lookup{} ), fc::exception,
BOOST_REQUIRE_EXCEPTION(c.control->push_block( bad_block_bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} ), fc::exception,
[] (const fc::exception &ex)->bool {
return ex.to_detail_string().find("block signed by unexpected key") != std::string::npos;
});
@@ -305,7 +305,7 @@ BOOST_AUTO_TEST_CASE( unapplied_transaction_queue_test ) try {
q.add_aborted( { trx20, trx22 } );
q.add_persisted( trx21 );
q.add_persisted( trx23 );
q.clear_expired( fc::time_point::now(), fc::time_point::now() + fc::seconds( 300 ), [](auto, auto){} );
q.clear_expired( fc::time_point::now(), [](){ return false; }, [](auto, auto){} );
BOOST_CHECK( q.size() == 2 );
BOOST_REQUIRE( next( q ) == trx23 );
BOOST_REQUIRE( next( q ) == trx22 );