Merge branch 'devel'

This commit is contained in:
Ștefan Talpalaru 2020-04-08 22:54:18 +02:00
commit b574799088
No known key found for this signature in database
GPG Key ID: CBF7934204F1B6F9
95 changed files with 1861 additions and 2067 deletions

View File

@ -9,7 +9,6 @@ init: # Scripts called at the very beginning
cache: cache:
- NimBinaries - NimBinaries
- p2pdCache
- jsonTestsCache - jsonTestsCache
matrix: matrix:
@ -36,8 +35,8 @@ build_script:
test_script: test_script:
# the "go-checks" target fails in AppVeyor, for some reason; easier to disable than to debug # the "go-checks" target fails in AppVeyor, for some reason; easier to disable than to debug
- mingw32-make -j2 ARCH_OVERRIDE=%PLATFORM% DISABLE_GO_CHECKS=1 P2PD_CACHE=p2pdCache LOG_LEVEL=TRACE - mingw32-make -j2 ARCH_OVERRIDE=%PLATFORM% DISABLE_GO_CHECKS=1 LOG_LEVEL=TRACE
- mingw32-make -j2 ARCH_OVERRIDE=%PLATFORM% DISABLE_GO_CHECKS=1 P2PD_CACHE=p2pdCache LOG_LEVEL=TRACE NIMFLAGS="-d:NETWORK_TYPE=libp2p -d:testnet_servers_image" - mingw32-make -j2 ARCH_OVERRIDE=%PLATFORM% DISABLE_GO_CHECKS=1 LOG_LEVEL=TRACE NIMFLAGS="-d:testnet_servers_image"
- mingw32-make -j2 ARCH_OVERRIDE=%PLATFORM% DISABLE_TEST_FIXTURES_SCRIPT=1 DISABLE_GO_CHECKS=1 test - mingw32-make -j2 ARCH_OVERRIDE=%PLATFORM% DISABLE_TEST_FIXTURES_SCRIPT=1 DISABLE_GO_CHECKS=1 test
deploy: off deploy: off

2
.gitmodules vendored
View File

@ -136,6 +136,8 @@
[submodule "vendor/nim-sqlite3-abi"] [submodule "vendor/nim-sqlite3-abi"]
path = vendor/nim-sqlite3-abi path = vendor/nim-sqlite3-abi
url = https://github.com/arnetheduck/nim-sqlite3-abi.git url = https://github.com/arnetheduck/nim-sqlite3-abi.git
ignore = dirty
branch = master
[submodule "vendor/nim-testutils"] [submodule "vendor/nim-testutils"]
path = vendor/nim-testutils path = vendor/nim-testutils
url = https://github.com/status-im/nim-testutils.git url = https://github.com/status-im/nim-testutils.git

View File

@ -50,6 +50,6 @@ script:
# Building Nim-1.0.4 takes up to 10 minutes on Travis - the time limit after which jobs are cancelled for having no output # Building Nim-1.0.4 takes up to 10 minutes on Travis - the time limit after which jobs are cancelled for having no output
- make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC}" V=1 update # to allow a newer Nim version to be detected - make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC}" V=1 update # to allow a newer Nim version to be detected
- make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC}" LOG_LEVEL=TRACE - make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC}" LOG_LEVEL=TRACE
- make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC} -d:NETWORK_TYPE=libp2p -d:testnet_servers_image" LOG_LEVEL=TRACE - make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC} -d:testnet_servers_image" LOG_LEVEL=TRACE
- make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC}" DISABLE_TEST_FIXTURES_SCRIPT=1 test - make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC}" DISABLE_TEST_FIXTURES_SCRIPT=1 test

View File

@ -51,7 +51,14 @@ OK: 2/2 Fail: 0/2 Skip: 0/2
+ Attestation topics OK + Attestation topics OK
``` ```
OK: 1/1 Fail: 0/1 Skip: 0/1 OK: 1/1 Fail: 0/1 Skip: 0/1
## Official - 0.11.0 - constants & config [Preset: mainnet] ## Interop
```diff
+ Interop genesis OK
+ Interop signatures OK
+ Mocked start private key OK
```
OK: 3/3 Fail: 0/3 Skip: 0/3
## Official - 0.11.1 - constants & config [Preset: mainnet]
```diff ```diff
+ BASE_REWARD_FACTOR 64 [Preset: mainnet] OK + BASE_REWARD_FACTOR 64 [Preset: mainnet] OK
+ BLS_WITHDRAWAL_PREFIX "0x00" [Preset: mainnet] OK + BLS_WITHDRAWAL_PREFIX "0x00" [Preset: mainnet] OK
@ -80,7 +87,7 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
+ EPOCHS_PER_SLASHINGS_VECTOR 8192 [Preset: mainnet] OK + EPOCHS_PER_SLASHINGS_VECTOR 8192 [Preset: mainnet] OK
+ ETH1_FOLLOW_DISTANCE 1024 [Preset: mainnet] OK + ETH1_FOLLOW_DISTANCE 1024 [Preset: mainnet] OK
+ GASPRICE_ADJUSTMENT_COEFFICIENT 8 [Preset: mainnet] OK + GASPRICE_ADJUSTMENT_COEFFICIENT 8 [Preset: mainnet] OK
+ GENESIS_FORK_VERSION "0x00000000" [Preset: mainnet] OK - GENESIS_FORK_VERSION "0x00000000" [Preset: mainnet] Fail
+ HISTORICAL_ROOTS_LIMIT 16777216 [Preset: mainnet] OK + HISTORICAL_ROOTS_LIMIT 16777216 [Preset: mainnet] OK
+ HYSTERESIS_DOWNWARD_MULTIPLIER 1 [Preset: mainnet] OK + HYSTERESIS_DOWNWARD_MULTIPLIER 1 [Preset: mainnet] OK
+ HYSTERESIS_QUOTIENT 4 [Preset: mainnet] OK + HYSTERESIS_QUOTIENT 4 [Preset: mainnet] OK
@ -141,7 +148,7 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
+ VALIDATOR_REGISTRY_LIMIT 1099511627776 [Preset: mainnet] OK + VALIDATOR_REGISTRY_LIMIT 1099511627776 [Preset: mainnet] OK
+ WHISTLEBLOWER_REWARD_QUOTIENT 512 [Preset: mainnet] OK + WHISTLEBLOWER_REWARD_QUOTIENT 512 [Preset: mainnet] OK
``` ```
OK: 85/87 Fail: 2/87 Skip: 0/87 OK: 84/87 Fail: 3/87 Skip: 0/87
## PeerPool testing suite ## PeerPool testing suite
```diff ```diff
+ Access peers by key test OK + Access peers by key test OK
@ -222,4 +229,4 @@ OK: 4/4 Fail: 0/4 Skip: 0/4
OK: 8/8 Fail: 0/8 Skip: 0/8 OK: 8/8 Fail: 0/8 Skip: 0/8
---TOTAL--- ---TOTAL---
OK: 142/144 Fail: 2/144 Skip: 0/144 OK: 144/147 Fail: 3/147 Skip: 0/147

View File

@ -78,7 +78,14 @@ OK: 2/2 Fail: 0/2 Skip: 0/2
+ Attestation topics OK + Attestation topics OK
``` ```
OK: 1/1 Fail: 0/1 Skip: 0/1 OK: 1/1 Fail: 0/1 Skip: 0/1
## Official - 0.11.0 - constants & config [Preset: minimal] ## Interop
```diff
+ Interop genesis OK
+ Interop signatures OK
+ Mocked start private key OK
```
OK: 3/3 Fail: 0/3 Skip: 0/3
## Official - 0.11.1 - constants & config [Preset: minimal]
```diff ```diff
+ BASE_REWARD_FACTOR 64 [Preset: minimal] OK + BASE_REWARD_FACTOR 64 [Preset: minimal] OK
+ BLS_WITHDRAWAL_PREFIX "0x00" [Preset: minimal] OK + BLS_WITHDRAWAL_PREFIX "0x00" [Preset: minimal] OK
@ -107,7 +114,7 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
+ EPOCHS_PER_SLASHINGS_VECTOR 64 [Preset: minimal] OK + EPOCHS_PER_SLASHINGS_VECTOR 64 [Preset: minimal] OK
+ ETH1_FOLLOW_DISTANCE 16 [Preset: minimal] OK + ETH1_FOLLOW_DISTANCE 16 [Preset: minimal] OK
+ GASPRICE_ADJUSTMENT_COEFFICIENT 8 [Preset: minimal] OK + GASPRICE_ADJUSTMENT_COEFFICIENT 8 [Preset: minimal] OK
+ GENESIS_FORK_VERSION "0x00000001" [Preset: minimal] OK - GENESIS_FORK_VERSION "0x00000001" [Preset: minimal] Fail
+ HISTORICAL_ROOTS_LIMIT 16777216 [Preset: minimal] OK + HISTORICAL_ROOTS_LIMIT 16777216 [Preset: minimal] OK
+ HYSTERESIS_DOWNWARD_MULTIPLIER 1 [Preset: minimal] OK + HYSTERESIS_DOWNWARD_MULTIPLIER 1 [Preset: minimal] OK
+ HYSTERESIS_QUOTIENT 4 [Preset: minimal] OK + HYSTERESIS_QUOTIENT 4 [Preset: minimal] OK
@ -168,7 +175,7 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
+ VALIDATOR_REGISTRY_LIMIT 1099511627776 [Preset: minimal] OK + VALIDATOR_REGISTRY_LIMIT 1099511627776 [Preset: minimal] OK
+ WHISTLEBLOWER_REWARD_QUOTIENT 512 [Preset: minimal] OK + WHISTLEBLOWER_REWARD_QUOTIENT 512 [Preset: minimal] OK
``` ```
OK: 85/87 Fail: 2/87 Skip: 0/87 OK: 84/87 Fail: 3/87 Skip: 0/87
## PeerPool testing suite ## PeerPool testing suite
```diff ```diff
+ Access peers by key test OK + Access peers by key test OK
@ -249,4 +256,4 @@ OK: 4/4 Fail: 0/4 Skip: 0/4
OK: 8/8 Fail: 0/8 Skip: 0/8 OK: 8/8 Fail: 0/8 Skip: 0/8
---TOTAL--- ---TOTAL---
OK: 157/159 Fail: 2/159 Skip: 0/159 OK: 159/162 Fail: 3/162 Skip: 0/162

View File

@ -45,6 +45,7 @@ OK: 3/3 Fail: 0/3 Skip: 0/3
+ [Invalid] after_epoch_slots OK + [Invalid] after_epoch_slots OK
+ [Invalid] bad_source_root OK + [Invalid] bad_source_root OK
+ [Invalid] before_inclusion_delay OK + [Invalid] before_inclusion_delay OK
+ [Invalid] empty_aggregation_bits OK
+ [Invalid] future_target_epoch OK + [Invalid] future_target_epoch OK
+ [Invalid] invalid_attestation_signature OK + [Invalid] invalid_attestation_signature OK
+ [Invalid] invalid_current_source_root OK + [Invalid] invalid_current_source_root OK
@ -58,7 +59,6 @@ OK: 3/3 Fail: 0/3 Skip: 0/3
+ [Invalid] too_many_aggregation_bits OK + [Invalid] too_many_aggregation_bits OK
+ [Invalid] wrong_index_for_committee_signature OK + [Invalid] wrong_index_for_committee_signature OK
+ [Invalid] wrong_index_for_slot OK + [Invalid] wrong_index_for_slot OK
+ [Valid] empty_aggregation_bits OK
+ [Valid] success OK + [Valid] success OK
+ [Valid] success_multi_proposer_index_iterations OK + [Valid] success_multi_proposer_index_iterations OK
+ [Valid] success_previous_epoch OK + [Valid] success_previous_epoch OK

View File

@ -45,6 +45,7 @@ OK: 3/3 Fail: 0/3 Skip: 0/3
+ [Invalid] after_epoch_slots OK + [Invalid] after_epoch_slots OK
+ [Invalid] bad_source_root OK + [Invalid] bad_source_root OK
+ [Invalid] before_inclusion_delay OK + [Invalid] before_inclusion_delay OK
+ [Invalid] empty_aggregation_bits OK
+ [Invalid] future_target_epoch OK + [Invalid] future_target_epoch OK
+ [Invalid] invalid_attestation_signature OK + [Invalid] invalid_attestation_signature OK
+ [Invalid] invalid_current_source_root OK + [Invalid] invalid_current_source_root OK
@ -58,7 +59,6 @@ OK: 3/3 Fail: 0/3 Skip: 0/3
+ [Invalid] too_many_aggregation_bits OK + [Invalid] too_many_aggregation_bits OK
+ [Invalid] wrong_index_for_committee_signature OK + [Invalid] wrong_index_for_committee_signature OK
+ [Invalid] wrong_index_for_slot OK + [Invalid] wrong_index_for_slot OK
+ [Valid] empty_aggregation_bits OK
+ [Valid] success OK + [Valid] success OK
+ [Valid] success_multi_proposer_index_iterations OK + [Valid] success_multi_proposer_index_iterations OK
+ [Valid] success_previous_epoch OK + [Valid] success_previous_epoch OK

View File

@ -1,6 +1,6 @@
FixtureSSZConsensus-mainnet FixtureSSZConsensus-mainnet
=== ===
## Official - 0.11.0 - SSZ consensus objects [Preset: mainnet] ## Official - 0.11.1 - SSZ consensus objects [Preset: mainnet]
```diff ```diff
+ Testing AggregateAndProof OK + Testing AggregateAndProof OK
+ Testing Attestation OK + Testing Attestation OK

View File

@ -1,6 +1,6 @@
FixtureSSZConsensus-minimal FixtureSSZConsensus-minimal
=== ===
## Official - 0.11.0 - SSZ consensus objects [Preset: minimal] ## Official - 0.11.1 - SSZ consensus objects [Preset: minimal]
```diff ```diff
+ Testing AggregateAndProof OK + Testing AggregateAndProof OK
+ Testing Attestation OK + Testing Attestation OK

6
Jenkinsfile vendored
View File

@ -22,7 +22,7 @@ def runStages() {
"tools": { "tools": {
stage("Tools") { stage("Tools") {
sh "make -j${env.NPROC}" sh "make -j${env.NPROC}"
sh "make -j${env.NPROC} LOG_LEVEL=TRACE NIMFLAGS='-d:NETWORK_TYPE=libp2p -d:testnet_servers_image'" sh "make -j${env.NPROC} LOG_LEVEL=TRACE NIMFLAGS='-d:testnet_servers_image'"
} }
}, },
"test suite": { "test suite": {
@ -31,8 +31,8 @@ def runStages() {
} }
if ("${NODE_NAME}" ==~ /linux.*/) { if ("${NODE_NAME}" ==~ /linux.*/) {
stage("testnet finalization") { stage("testnet finalization") {
sh "./scripts/launch_local_testnet.sh --testnet 0 --nodes 4 --disable-htop -- --verify-finalization --stop-at-epoch=5" sh "./scripts/launch_local_testnet.sh --testnet 0 --nodes 4 --log-level INFO --disable-htop -- --verify-finalization --stop-at-epoch=5"
sh "./scripts/launch_local_testnet.sh --testnet 1 --nodes 4 --disable-htop -- --verify-finalization --stop-at-epoch=5" sh "./scripts/launch_local_testnet.sh --testnet 1 --nodes 4 --log-level INFO --disable-htop -- --verify-finalization --stop-at-epoch=5"
} }
} }
} }

View File

@ -37,7 +37,6 @@ TOOLS_CSV := $(subst $(SPACE),$(COMMA),$(TOOLS))
build-system-checks \ build-system-checks \
deps \ deps \
update \ update \
p2pd \
test \ test \
$(TOOLS) \ $(TOOLS) \
clean_eth2_network_simulation_files \ clean_eth2_network_simulation_files \
@ -59,12 +58,11 @@ endif
# must be included after the default target # must be included after the default target
-include $(BUILD_SYSTEM_DIR)/makefiles/targets.mk -include $(BUILD_SYSTEM_DIR)/makefiles/targets.mk
# "--import" can't be added to config.nims, for some reason # "--define:release" implies "--stacktrace:off" and it cannot be added to config.nims
# "--define:release" implies "--stacktrace:off" and it cannot be added to config.nims either
ifeq ($(USE_LIBBACKTRACE), 0) ifeq ($(USE_LIBBACKTRACE), 0)
NIM_PARAMS := $(NIM_PARAMS) -d:debug -d:disable_libbacktrace NIM_PARAMS := $(NIM_PARAMS) -d:debug -d:disable_libbacktrace
else else
NIM_PARAMS := $(NIM_PARAMS) -d:release --import:libbacktrace NIM_PARAMS := $(NIM_PARAMS) -d:release
endif endif
#- the Windows build fails on Azure Pipelines if we have Unicode symbols copy/pasted here, #- the Windows build fails on Azure Pipelines if we have Unicode symbols copy/pasted here,
@ -80,7 +78,7 @@ build-system-checks:
}; \ }; \
exit 0 exit 0
deps: | deps-common beacon_chain.nims p2pd deps: | deps-common beacon_chain.nims
ifneq ($(USE_LIBBACKTRACE), 0) ifneq ($(USE_LIBBACKTRACE), 0)
deps: | libbacktrace deps: | libbacktrace
endif endif
@ -96,13 +94,7 @@ beacon_chain.nims:
# nim-libbacktrace # nim-libbacktrace
libbacktrace: libbacktrace:
+ $(MAKE) -C vendor/nim-libbacktrace BUILD_CXX_LIB=0 + $(MAKE) -C vendor/nim-libbacktrace BUILD_CXX_LIB=0 $(HANDLE_OUTPUT)
P2PD_CACHE :=
p2pd: | go-checks
BUILD_MSG="$(BUILD_MSG) $@" \
V=$(V) \
$(ENV_SCRIPT) $(BUILD_SYSTEM_DIR)/scripts/build_p2pd.sh "$(P2PD_CACHE)"
# Windows 10 with WSL enabled, but no distro installed, fails if "../../nimble.sh" is executed directly # Windows 10 with WSL enabled, but no distro installed, fails if "../../nimble.sh" is executed directly
# in a Makefile recipe but works when prefixing it with `bash`. No idea how the PATH is overridden. # in a Makefile recipe but works when prefixing it with `bash`. No idea how the PATH is overridden.
@ -121,7 +113,7 @@ $(TOOLS): | build deps
clean_eth2_network_simulation_files: clean_eth2_network_simulation_files:
rm -rf tests/simulation/{data,validators} rm -rf tests/simulation/{data,validators}
eth2_network_simulation: | build deps p2pd clean_eth2_network_simulation_files process_dashboard eth2_network_simulation: | build deps clean_eth2_network_simulation_files process_dashboard
+ GIT_ROOT="$$PWD" NIMFLAGS="$(NIMFLAGS)" LOG_LEVEL="$(LOG_LEVEL)" tests/simulation/start.sh + GIT_ROOT="$$PWD" NIMFLAGS="$(NIMFLAGS)" LOG_LEVEL="$(LOG_LEVEL)" tests/simulation/start.sh
clean-testnet0: clean-testnet0:

View File

@ -48,9 +48,8 @@ You can check where the beacon chain fits in the Ethereum ecosystem our Two-Poin
At the moment, Nimbus has to be built from source. At the moment, Nimbus has to be built from source.
Nimbus has 4 external dependencies: Nimbus has the following external dependencies:
* Go 1.12 (for compiling libp2p daemon - being phased out)
* Developer tools (C compiler, Make, Bash, Git) * Developer tools (C compiler, Make, Bash, Git)
* PCRE * PCRE
@ -61,13 +60,13 @@ Nim is not an external dependency, Nimbus will build its own local copy.
On common Linux distributions the dependencies can be installed with: On common Linux distributions the dependencies can be installed with:
```sh ```sh
# Debian and Ubuntu # Debian and Ubuntu
sudo apt-get install build-essential git golang-go libpcre3-dev sudo apt-get install build-essential git libpcre3-dev
# Fedora # Fedora
dnf install @development-tools go pcre dnf install @development-tools pcre
# Archlinux, using an AUR manager for pcre-static # Archlinux, using an AUR manager for pcre-static
yourAURmanager -S base-devel go pcre-static yourAURmanager -S base-devel pcre-static
``` ```
### MacOS ### MacOS
@ -75,17 +74,14 @@ yourAURmanager -S base-devel go pcre-static
Assuming you use [Homebrew](https://brew.sh/) to manage packages Assuming you use [Homebrew](https://brew.sh/) to manage packages
```sh ```sh
brew install go pcre brew install pcre
``` ```
### Windows ### Windows
* install [Go](https://golang.org/doc/install#windows)
You can install the developer tools by following the instruction in our [Windows dev environment section](#windows-dev-environment). You can install the developer tools by following the instruction in our [Windows dev environment section](#windows-dev-environment).
It also provides a downloading script for prebuilt PCRE. It also provides a downloading script for prebuilt PCRE.
If you choose to install Go from source, both Go and Nimbus requires the same initial steps of installing Mingw.
### Android ### Android
* Install the [Termux](https://termux.com) app from FDroid or the Google Play store * Install the [Termux](https://termux.com) app from FDroid or the Google Play store
@ -95,7 +91,7 @@ Note, the Ubuntu PRoot is known to contain all Nimbus prerequisites compiled on
*Assuming Ubuntu PRoot is used* *Assuming Ubuntu PRoot is used*
```sh ```sh
apt install build-essential git golang-go libpcre3-dev apt install build-essential git libpcre3-dev
``` ```
## For users ## For users
@ -295,24 +291,8 @@ sudo reboot
# Install prerequisites # Install prerequisites
sudo apt-get install git libgflags-dev libsnappy-dev libpcre3-dev sudo apt-get install git libgflags-dev libsnappy-dev libpcre3-dev
mkdir status
cd status
# Install Go at least 1.12 (Buster only includes up to 1.11)
# Raspbian is 32-bit, so the package is go1.XX.X.linux-armv6l.tar.gz (and not arm64)
curl -O https://storage.googleapis.com/golang/go1.13.3.linux-armv6l.tar.gz
sudo tar -C /usr/local -xzf go1.13.3.linux-armv6l.tar.gz
echo '# Go install' >> ~/.profile
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile
# Reload the environment variable changes
source ~/.profile
git clone https://github.com/status-im/nim-beacon-chain.git
cd nim-beacon-chain
# Then you can follow instructions for Linux. # Then you can follow instructions for Linux.
``` ```
### Makefile tips and tricks for developers ### Makefile tips and tricks for developers

View File

@ -14,15 +14,9 @@ jobs:
- task: CacheBeta@1 - task: CacheBeta@1
displayName: 'cache Nim binaries' displayName: 'cache Nim binaries'
inputs: inputs:
key: NimBinaries | $(Agent.OS) | $(PLATFORM) | "$(Build.SourceBranchName)" | "v2" key: NimBinaries | $(Agent.OS) | $(PLATFORM) | "$(Build.SourceBranchName)" | "v4"
path: NimBinaries path: NimBinaries
- task: CacheBeta@1
displayName: 'cache p2pd binaries'
inputs:
key: p2pdCache | $(Agent.OS) | $(PLATFORM) | "$(Build.SourceBranchName)"
path: p2pdCache
- task: CacheBeta@1 - task: CacheBeta@1
displayName: 'cache official test fixtures' displayName: 'cache official test fixtures'
inputs: inputs:
@ -71,8 +65,10 @@ jobs:
scripts/setup_official_tests.sh jsonTestsCache scripts/setup_official_tests.sh jsonTestsCache
mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} CI_CACHE=NimBinaries update mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} CI_CACHE=NimBinaries update
mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} fetch-dlls mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} fetch-dlls
mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} P2PD_CACHE=p2pdCache LOG_LEVEL=TRACE mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} LOG_LEVEL=TRACE
mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} P2PD_CACHE=p2pdCache LOG_LEVEL=TRACE NIMFLAGS="-d:NETWORK_TYPE=libp2p -d:testnet_servers_image" mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} LOG_LEVEL=TRACE NIMFLAGS="-d:testnet_servers_image"
file build/beacon_node file build/beacon_node
# fail fast
export NIMTEST_ABORT_ON_ERROR=1
mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} DISABLE_TEST_FIXTURES_SCRIPT=1 test mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} DISABLE_TEST_FIXTURES_SCRIPT=1 test
displayName: 'build and test' displayName: 'build and test'

View File

@ -5,20 +5,12 @@
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms. # at your option. This file may not be copied, modified, or distributed except according to those terms.
# Have an an aggregated aggregation ready for broadcast at
# SECONDS_PER_SLOT * 2 / 3, i.e. 2/3 through relevant slot
# intervals.
#
# The other part is arguably part of attestation pool -- the validation's # The other part is arguably part of attestation pool -- the validation's
# something that should be happing on receipt, not aggregation per se. In # something that should be happing on receipt, not aggregation per se. In
# that part, check that messages conform -- so, check for each type # that part, check that messages conform -- so, check for each type
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/p2p-interface.md#topics-and-messages # https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/p2p-interface.md#topics-and-messages
# specifies. So by the time this calls attestation pool, all validation's # specifies. So by the time this calls attestation pool, all validation's
# already done. # already done.
#
# Finally, some of the filtering's libp2p stuff. Consistency checks between
# topic/message types and GOSSIP_MAX_SIZE -- mostly doesn't belong here, so
# while TODO, isn't TODO for this module.
import import
options, options,
@ -26,15 +18,7 @@ import
state_transition_block], state_transition_block],
./attestation_pool, ./beacon_node_types, ./ssz ./attestation_pool, ./beacon_node_types, ./ssz
# TODO gossipsub validation lives somewhere, maybe here # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#aggregation-selection
# TODO add tests, especially for validation
# https://github.com/status-im/nim-beacon-chain/issues/122#issuecomment-562479965
const
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/p2p-interface.md#configuration
ATTESTATION_PROPAGATION_SLOT_RANGE = 32
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#aggregation-selection
func is_aggregator(state: BeaconState, slot: Slot, index: uint64, func is_aggregator(state: BeaconState, slot: Slot, index: uint64,
slot_signature: ValidatorSig): bool = slot_signature: ValidatorSig): bool =
# TODO index is a CommitteeIndex, aka uint64 # TODO index is a CommitteeIndex, aka uint64
@ -47,34 +31,49 @@ func is_aggregator(state: BeaconState, slot: Slot, index: uint64,
proc aggregate_attestations*( proc aggregate_attestations*(
pool: AttestationPool, state: BeaconState, index: uint64, pool: AttestationPool, state: BeaconState, index: uint64,
privkey: ValidatorPrivKey): Option[AggregateAndProof] = privkey: ValidatorPrivKey, trailing_distance: uint64): Option[AggregateAndProof] =
# TODO alias CommitteeIndex to actual type then convert various uint64's here # TODO alias CommitteeIndex to actual type then convert various uint64's here
let doAssert state.slot >= trailing_distance
slot = state.slot - 2
slot_signature = get_slot_signature(state.fork, slot, privkey) # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/p2p-interface.md#configuration
doAssert trailing_distance <= ATTESTATION_PROPAGATION_SLOT_RANGE
let
slot = state.slot - trailing_distance
slot_signature = get_slot_signature(
state.fork, state.genesis_validators_root, slot, privkey)
if slot < 0:
return none(AggregateAndProof)
doAssert slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= state.slot doAssert slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= state.slot
doAssert state.slot >= slot doAssert state.slot >= slot
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#aggregation-selection # TODO performance issue for future, via get_active_validator_indices(...)
doAssert index < get_committee_count_at_slot(state, slot)
# TODO for testing purposes, refactor this into the condition check
# and just calculation
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#aggregation-selection
if not is_aggregator(state, slot, index, slot_signature): if not is_aggregator(state, slot, index, slot_signature):
return none(AggregateAndProof) return none(AggregateAndProof)
let attestation_data = # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#attestation-data
makeAttestationData(state, slot, index, get_block_root_at_slot(state, slot)) # describes how to construct an attestation, which applies for makeAttestationData(...)
# TODO this won't actually match anything
let attestation_data = AttestationData(
slot: slot,
index: index,
beacon_block_root: get_block_root_at_slot(state, slot))
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#construct-aggregate # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#construct-aggregate
for attestation in getAttestationsForBlock(pool, state, slot): # TODO once EV goes in w/ refactoring of getAttestationsForBlock, pull out the getSlot version and use
# it. This is incorrect.
for attestation in getAttestationsForBlock(pool, state):
# getAttestationsForBlock(...) already aggregates
if attestation.data == attestation_data: if attestation.data == attestation_data:
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#aggregateandproof # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#aggregateandproof
return some(AggregateAndProof( return some(AggregateAndProof(
aggregator_index: index, aggregator_index: index,
aggregate: attestation, aggregate: attestation,
selection_proof: slot_signature)) selection_proof: slot_signature))
# TODO in catch-up mode, we could get here, so probably shouldn't assert
doAssert false
none(AggregateAndProof) none(AggregateAndProof)

View File

@ -1,5 +1,5 @@
import import
deques, sequtils, tables, deques, sequtils, tables, options,
chronicles, stew/[bitseqs, byteutils], json_serialization/std/sets, chronicles, stew/[bitseqs, byteutils], json_serialization/std/sets,
./spec/[beaconstate, datatypes, crypto, digest, helpers, validator], ./spec/[beaconstate, datatypes, crypto, digest, helpers, validator],
./extras, ./ssz, ./block_pool, ./beacon_node_types ./extras, ./ssz, ./block_pool, ./beacon_node_types
@ -35,6 +35,7 @@ proc combine*(tgt: var Attestation, src: Attestation, flags: UpdateFlags) =
else: else:
trace "Ignoring overlapping attestations" trace "Ignoring overlapping attestations"
# TODO remove/merge with p2p-interface validation
proc validate( proc validate(
state: BeaconState, attestation: Attestation): bool = state: BeaconState, attestation: Attestation): bool =
# TODO what constitutes a valid attestation when it's about to be added to # TODO what constitutes a valid attestation when it's about to be added to
@ -265,26 +266,20 @@ proc add*(pool: var AttestationPool, attestation: Attestation) =
pool.addResolved(blck, attestation) pool.addResolved(blck, attestation)
proc getAttestationsForBlock*( proc getAttestationsForSlot(pool: AttestationPool, newBlockSlot: Slot):
pool: AttestationPool, state: BeaconState): seq[Attestation] = Option[SlotData] =
## Retrieve attestations that may be added to a new block at the slot of the
## given state
logScope: pcs = "retrieve_attestation"
let newBlockSlot = state.slot
if newBlockSlot < (GENESIS_SLOT + MIN_ATTESTATION_INCLUSION_DELAY): if newBlockSlot < (GENESIS_SLOT + MIN_ATTESTATION_INCLUSION_DELAY):
debug "Too early for attestations", debug "Too early for attestations",
newBlockSlot = shortLog(newBlockSlot), newBlockSlot = shortLog(newBlockSlot),
cat = "query" cat = "query"
return return none(SlotData)
if pool.slots.len == 0: # startingSlot not set yet! if pool.slots.len == 0: # startingSlot not set yet!
info "No attestations found (pool empty)", info "No attestations found (pool empty)",
newBlockSlot = shortLog(newBlockSlot), newBlockSlot = shortLog(newBlockSlot),
cat = "query" cat = "query"
return return none(SlotData)
var cache = get_empty_per_epoch_cache()
let let
# TODO in theory we could include attestations from other slots also, but # TODO in theory we could include attestations from other slots also, but
# we're currently not tracking which attestations have already been included # we're currently not tracking which attestations have already been included
@ -300,15 +295,32 @@ proc getAttestationsForBlock*(
startingSlot = shortLog(pool.startingSlot), startingSlot = shortLog(pool.startingSlot),
endingSlot = shortLog(pool.startingSlot + pool.slots.len.uint64), endingSlot = shortLog(pool.startingSlot + pool.slots.len.uint64),
cat = "query" cat = "query"
return return none(SlotData)
let slotDequeIdx = int(attestationSlot - pool.startingSlot)
some(pool.slots[slotDequeIdx])
proc getAttestationsForBlock*(
pool: AttestationPool, state: BeaconState): seq[Attestation] =
## Retrieve attestations that may be added to a new block at the slot of the
## given state
logScope: pcs = "retrieve_attestation"
# TODO this shouldn't really need state -- it's to recheck/validate, but that
# should be refactored
let let
slotDequeIdx = int(attestationSlot - pool.startingSlot) newBlockSlot = state.slot
slotData = pool.slots[slotDequeIdx] maybeSlotData = getAttestationsForSlot(pool, newBlockSlot)
if maybeSlotData.isNone:
# Logging done in getAttestationsForSlot(...)
return
let slotData = maybeSlotData.get
var cache = get_empty_per_epoch_cache()
for a in slotData.attestations: for a in slotData.attestations:
var var
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#construct-attestation # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#construct-attestation
attestation = Attestation( attestation = Attestation(
aggregation_bits: a.validations[0].aggregation_bits, aggregation_bits: a.validations[0].aggregation_bits,
data: a.data, data: a.data,
@ -438,3 +450,80 @@ proc selectHead*(pool: AttestationPool): BlockRef =
lmdGhost(pool, pool.blockPool.justifiedState.data.data, justifiedHead.blck) lmdGhost(pool, pool.blockPool.justifiedState.data.data, justifiedHead.blck)
newHead newHead
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/p2p-interface.md#attestation-subnets
proc isValidAttestation*(
pool: AttestationPool, attestation: Attestation, current_slot: Slot,
topicCommitteeIndex: uint64, flags: UpdateFlags): bool =
# The attestation's committee index (attestation.data.index) is for the
# correct subnet.
if attestation.data.index != topicCommitteeIndex:
debug "isValidAttestation: attestation's committee index not for the correct subnet",
topicCommitteeIndex = topicCommitteeIndex,
attestation_data_index = attestation.data.index
return false
if not (attestation.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >=
current_slot and current_slot >= attestation.data.slot):
debug "isValidAttestation: attestation.data.slot not within ATTESTATION_PROPAGATION_SLOT_RANGE"
return false
# The attestation is unaggregated -- that is, it has exactly one
# participating validator (len([bit for bit in attestation.aggregation_bits
# if bit == 0b1]) == 1).
# TODO a cleverer algorithm, along the lines of countOnes() in nim-stew
# But that belongs in nim-stew, since it'd break abstraction layers, to
# use details of its representation from nim-beacon-chain.
var onesCount = 0
for aggregation_bit in attestation.aggregation_bits:
if not aggregation_bit:
continue
onesCount += 1
if onesCount > 1:
debug "isValidAttestation: attestation has too many aggregation bits",
aggregation_bits = attestation.aggregation_bits
return false
if onesCount != 1:
debug "isValidAttestation: attestation has too few aggregation bits"
return false
# The attestation is the first valid attestation received for the
# participating validator for the slot, attestation.data.slot.
let maybeSlotData = getAttestationsForSlot(pool, attestation.data.slot)
if maybeSlotData.isSome:
for attestationEntry in maybeSlotData.get.attestations:
if attestation.data != attestationEntry.data:
continue
# Attestations might be aggregated eagerly or lazily; allow for both.
for validation in attestationEntry.validations:
if attestation.aggregation_bits.isSubsetOf(validation.aggregation_bits):
debug "isValidAttestation: attestation already exists at slot",
attestation_data_slot = attestation.data.slot,
attestation_aggregation_bits = attestation.aggregation_bits,
attestation_pool_validation = validation.aggregation_bits
return false
# The block being voted for (attestation.data.beacon_block_root) passes
# validation.
# We rely on the block pool to have been validated, so check for the
# existence of the block in the pool.
# TODO: consider a "slush pool" of attestations whose blocks have not yet
# propagated - i.e. imagine that attestations are smaller than blocks and
# therefore propagate faster, thus reordering their arrival in some nodes
if pool.blockPool.get(attestation.data.beacon_block_root).isNone():
debug "isValidAttestation: block doesn't exist in block pool",
attestation_data_beacon_block_root = attestation.data.beacon_block_root
return false
# The signature of attestation is valid.
# TODO need to know above which validator anyway, and this is too general
# as it supports aggregated attestations (which this can't be)
var cache = get_empty_per_epoch_cache()
if not is_valid_indexed_attestation(
pool.blockPool.headState.data.data,
get_indexed_attestation(
pool.blockPool.headState.data.data, attestation, cache), {}):
debug "isValidAttestation: signature verification failed"
return false
true

View File

@ -1,6 +1,6 @@
import import
# Standard library # Standard library
os, tables, random, strutils, times, sequtils, os, tables, random, strutils, times,
# Nimble packages # Nimble packages
stew/[objects, bitseqs, byteutils], stew/shims/macros, stew/[objects, bitseqs, byteutils], stew/shims/macros,
@ -12,10 +12,11 @@ import
# Local modules # Local modules
spec/[datatypes, digest, crypto, beaconstate, helpers, validator, network, spec/[datatypes, digest, crypto, beaconstate, helpers, validator, network,
state_transition_block], spec/presets/custom, state_transition_block], spec/presets/custom,
conf, time, state_transition, beacon_chain_db, validator_pool, extras, conf, time, beacon_chain_db, validator_pool, extras,
attestation_pool, block_pool, eth2_network, eth2_discovery, attestation_pool, block_pool, eth2_network, eth2_discovery,
beacon_node_types, mainchain_monitor, version, ssz, ssz/dynamic_navigator, beacon_node_types, mainchain_monitor, version, ssz, ssz/dynamic_navigator,
sync_protocol, request_manager, validator_keygen, interop, statusbar sync_protocol, request_manager, validator_keygen, interop, statusbar,
attestation_aggregation
const const
genesisFile = "genesis.ssz" genesisFile = "genesis.ssz"
@ -56,8 +57,6 @@ type
forkVersion: array[4, byte] forkVersion: array[4, byte]
netKeys: KeyPair netKeys: KeyPair
requestManager: RequestManager requestManager: RequestManager
bootstrapNodes: seq[ENode]
bootstrapEnrs: seq[enr.Record]
db: BeaconChainDB db: BeaconChainDB
config: BeaconNodeConf config: BeaconNodeConf
attachedValidators: ValidatorPool attachedValidators: ValidatorPool
@ -134,7 +133,6 @@ proc getStateFromSnapshot(conf: BeaconNodeConf, state: var BeaconState): bool =
proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async.} = proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async.} =
let let
netKeys = getPersistentNetKeys(conf) netKeys = getPersistentNetKeys(conf)
ourPubKey = netKeys.pubkey.skkey
nickname = if conf.nodeName == "auto": shortForm(netKeys) nickname = if conf.nodeName == "auto": shortForm(netKeys)
else: conf.nodeName else: conf.nodeName
db = BeaconChainDB.init(kvStore SqliteStoreRef.init(conf.databaseDir)) db = BeaconChainDB.init(kvStore SqliteStoreRef.init(conf.databaseDir))
@ -188,25 +186,7 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async
# monitor # monitor
mainchainMonitor.start() mainchainMonitor.start()
var bootNodes: seq[ENode] let network = await createEth2Node(conf)
var bootEnrs: seq[enr.Record]
for node in conf.bootstrapNodes: addBootstrapNode(node, bootNodes, bootEnrs, ourPubKey)
loadBootstrapFile(string conf.bootstrapNodesFile, bootNodes, bootEnrs, ourPubKey)
when networkBackend == libp2pDaemon:
for enr in bootEnrs:
let enode = toENode(enr)
if enode.isOk:
bootNodes.add enode.value
let persistentBootstrapFile = conf.dataDir / "bootstrap_nodes.txt"
if fileExists(persistentBootstrapFile):
loadBootstrapFile(persistentBootstrapFile, bootNodes, bootEnrs, ourPubKey)
let
network = await createEth2Node(conf, bootNodes)
addressFile = string(conf.dataDir) / "beacon_node.address"
network.saveConnectionAddressFile(addressFile)
let rpcServer = if conf.rpcEnabled: let rpcServer = if conf.rpcEnabled:
RpcServer.init(conf.rpcAddress, conf.rpcPort) RpcServer.init(conf.rpcAddress, conf.rpcPort)
@ -219,8 +199,6 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async
forkVersion: blockPool.headState.data.data.fork.current_version, forkVersion: blockPool.headState.data.data.fork.current_version,
netKeys: netKeys, netKeys: netKeys,
requestManager: RequestManager.init(network), requestManager: RequestManager.init(network),
bootstrapNodes: bootNodes,
bootstrapEnrs: bootEnrs,
db: db, db: db,
config: conf, config: conf,
attachedValidators: ValidatorPool.init(), attachedValidators: ValidatorPool.init(),
@ -258,13 +236,10 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async
return res return res
proc connectToNetwork(node: BeaconNode) {.async.} = proc connectToNetwork(node: BeaconNode) {.async.} =
if node.bootstrapNodes.len > 0: await node.network.connectToNetwork()
info "Connecting to bootstrap nodes", bootstrapNodes = node.bootstrapNodes
else:
info "Waiting for connections"
await node.network.connectToNetwork(node.bootstrapNodes, let addressFile = node.config.dataDir / "beacon_node.address"
node.bootstrapEnrs) writeFile(addressFile, node.network.announcedENR.toURI)
template findIt(s: openarray, predicate: untyped): int = template findIt(s: openarray, predicate: untyped): int =
var res = -1 var res = -1
@ -341,14 +316,15 @@ proc updateHead(node: BeaconNode): BlockRef =
proc sendAttestation(node: BeaconNode, proc sendAttestation(node: BeaconNode,
fork: Fork, fork: Fork,
genesis_validators_root: Eth2Digest,
validator: AttachedValidator, validator: AttachedValidator,
attestationData: AttestationData, attestationData: AttestationData,
committeeLen: int, committeeLen: int,
indexInCommittee: int) {.async.} = indexInCommittee: int) {.async.} =
logScope: pcs = "send_attestation" logScope: pcs = "send_attestation"
let let validatorSignature = await validator.signAttestation(attestationData,
validatorSignature = await validator.signAttestation(attestationData, fork) fork, genesis_validators_root)
var aggregationBits = CommitteeValidatorsBits.init(committeeLen) var aggregationBits = CommitteeValidatorsBits.init(committeeLen)
aggregationBits.setBit indexInCommittee aggregationBits.setBit indexInCommittee
@ -359,7 +335,7 @@ proc sendAttestation(node: BeaconNode,
aggregation_bits: aggregationBits aggregation_bits: aggregationBits
) )
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#broadcast-attestation # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#broadcast-attestation
node.network.broadcast( node.network.broadcast(
getAttestationTopic(attestationData.index), attestation) getAttestationTopic(attestationData.index), attestation)
@ -409,7 +385,7 @@ proc proposeBlock(node: BeaconNode,
let message = makeBeaconBlock( let message = makeBeaconBlock(
state, state,
head.root, head.root,
validator.genRandaoReveal(state.fork, slot), validator.genRandaoReveal(state.fork, state.genesis_validators_root, slot),
eth1data, eth1data,
Eth2Digest(), Eth2Digest(),
node.attestationPool.getAttestationsForBlock(state), node.attestationPool.getAttestationsForBlock(state),
@ -425,8 +401,8 @@ proc proposeBlock(node: BeaconNode,
let blockRoot = hash_tree_root(newBlock.message) let blockRoot = hash_tree_root(newBlock.message)
# Careful, state no longer valid after here because of the await.. # Careful, state no longer valid after here because of the await..
newBlock.signature = newBlock.signature = await validator.signBlockProposal(
await validator.signBlockProposal(state.fork, slot, blockRoot) state.fork, state.genesis_validators_root, slot, blockRoot)
(blockRoot, newBlock) (blockRoot, newBlock)
@ -581,7 +557,8 @@ proc handleAttestations(node: BeaconNode, head: BlockRef, slot: Slot) =
for a in attestations: for a in attestations:
traceAsyncErrors sendAttestation( traceAsyncErrors sendAttestation(
node, state.fork, a.validator, a.data, a.committeeLen, a.indexInCommittee) node, state.fork, state.genesis_validators_root, a.validator, a.data,
a.committeeLen, a.indexInCommittee)
proc handleProposal(node: BeaconNode, head: BlockRef, slot: Slot): proc handleProposal(node: BeaconNode, head: BlockRef, slot: Slot):
Future[BlockRef] {.async.} = Future[BlockRef] {.async.} =
@ -625,6 +602,45 @@ proc verifyFinalization(node: BeaconNode, slot: Slot) =
node.blockPool.finalizedHead.blck.slot.compute_epoch_at_slot() node.blockPool.finalizedHead.blck.slot.compute_epoch_at_slot()
doAssert finalizedEpoch + 2 == epoch doAssert finalizedEpoch + 2 == epoch
proc broadcastAggregatedAttestations(
node: BeaconNode, state: auto, head: var auto, slot: Slot,
trailing_distance: uint64) =
# The index is via a
# locally attested validator. Unlike in handleAttestations(...) there's a
# single one at most per slot (because that's how aggregation attestation
# works), so the machinery that has to handle looping across, basically a
# set of locally attached validators is in principle not necessary, but a
# way to organize this. Then the private key for that validator should be
# the corresponding one -- whatver they are, they match.
let
bs = BlockSlot(blck: head, slot: slot)
committees_per_slot = get_committee_count_at_slot(state, slot)
var cache = get_empty_per_epoch_cache()
for committee_index in 0'u64..<committees_per_slot:
let
committee = get_beacon_committee(state, slot, committee_index, cache)
for index_in_committee, validatorIdx in committee:
let validator = node.getAttachedValidator(state, validatorIdx)
if validator != nil:
# This is slightly strange/inverted control flow, since really it's
# going to happen once per slot, but this is the best way to get at
# the validator index and private key pair. TODO verify it only has
# one isSome() with test.
let option_aggregateandproof =
aggregate_attestations(node.attestationPool, state,
committee_index,
# TODO https://github.com/status-im/nim-beacon-chain/issues/545
# this assumes in-process private keys
validator.privKey,
trailing_distance)
# Don't broadcast when, e.g., this node isn't an aggregator
if option_aggregateandproof.isSome:
node.network.broadcast(
topicAggregateAndProof, option_aggregateandproof.get)
proc onSlotStart(node: BeaconNode, lastSlot, scheduledSlot: Slot) {.gcsafe, async.} = proc onSlotStart(node: BeaconNode, lastSlot, scheduledSlot: Slot) {.gcsafe, async.} =
## Called at the beginning of a slot - usually every slot, but sometimes might ## Called at the beginning of a slot - usually every slot, but sometimes might
## skip a few in case we're running late. ## skip a few in case we're running late.
@ -720,7 +736,7 @@ proc onSlotStart(node: BeaconNode, lastSlot, scheduledSlot: Slot) {.gcsafe, asyn
var head = node.updateHead() var head = node.updateHead()
# TODO is the slot of the clock or the head block more interestion? provide # TODO is the slot of the clock or the head block more interesting? provide
# rationale in comment # rationale in comment
beacon_head_slot.set slot.int64 beacon_head_slot.set slot.int64
@ -785,11 +801,12 @@ proc onSlotStart(node: BeaconNode, lastSlot, scheduledSlot: Slot) {.gcsafe, asyn
# with any clock discrepancies once only, at the start of slot timer # with any clock discrepancies once only, at the start of slot timer
# processing.. # processing..
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.4/specs/validator/0_beacon-chain-validator.md#attesting # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#attesting
# A validator should create and broadcast the attestation to the # A validator should create and broadcast the attestation to the associated
# associated attestation subnet one-third of the way through the slot # attestation subnet when either (a) the validator has received a valid
# during which the validator is assigned―that is, SECONDS_PER_SLOT / 3 # block from the expected block proposer for the assigned slot or
# seconds after the start of slot. # (b) one-third of the slot has transpired (`SECONDS_PER_SLOT / 3` seconds
# after the start of slot) -- whichever comes first.
let let
attestationStart = node.beaconClock.fromNow(slot) attestationStart = node.beaconClock.fromNow(slot)
thirdSlot = seconds(int64(SECONDS_PER_SLOT)) div 3 thirdSlot = seconds(int64(SECONDS_PER_SLOT)) div 3
@ -811,6 +828,25 @@ proc onSlotStart(node: BeaconNode, lastSlot, scheduledSlot: Slot) {.gcsafe, asyn
handleAttestations(node, head, slot) handleAttestations(node, head, slot)
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#broadcast-aggregate
# If the validator is selected to aggregate (is_aggregator), then they
# broadcast their best aggregate as a SignedAggregateAndProof to the global
# aggregate channel (beacon_aggregate_and_proof) two-thirds of the way
# through the slot-that is, SECONDS_PER_SLOT * 2 / 3 seconds after the start
# of slot.
if slot > 2:
const TRAILING_DISTANCE = 1
let aggregationSlot = slot - TRAILING_DISTANCE
var aggregationHead = getAncestorAt(head, aggregationSlot)
let bs = BlockSlot(blck: aggregationHead, slot: aggregationSlot)
node.blockPool.withState(node.blockPool.tmpState, bs):
let twoThirdsSlot =
toBeaconTime(slot, seconds(2*int64(SECONDS_PER_SLOT)) div 3)
addTimer(saturate(node.beaconClock.fromNow(twoThirdsSlot))) do (p: pointer):
broadcastAggregatedAttestations(
node, state, aggregationHead, aggregationSlot, TRAILING_DISTANCE)
# TODO ... and beacon clock might jump here also. sigh. # TODO ... and beacon clock might jump here also. sigh.
let let
nextSlotStart = saturate(node.beaconClock.fromNow(nextSlot)) nextSlotStart = saturate(node.beaconClock.fromNow(nextSlot))
@ -924,20 +960,11 @@ proc installBeaconApiHandlers(rpcServer: RpcServer, node: BeaconNode) =
return StringOfJson("null") return StringOfJson("null")
rpcServer.rpc("getNetworkPeerId") do () -> string: rpcServer.rpc("getNetworkPeerId") do () -> string:
when networkBackend != libp2p: return $publicKey(node.network)
if true:
raise newException(CatchableError, "Unsupported operation")
return ""
else:
return $publicKey(node.network)
rpcServer.rpc("getNetworkPeers") do () -> seq[string]: rpcServer.rpc("getNetworkPeers") do () -> seq[string]:
when networkBackend != libp2p: for peerId, peer in node.network.peerPool:
if true: result.add $peerId
raise newException(CatchableError, "Unsupported operation")
else:
for peerId, peer in node.network.peerPool:
result.add $peerId
rpcServer.rpc("getNetworkEnr") do () -> string: rpcServer.rpc("getNetworkEnr") do () -> string:
when networkBackend == libp2p: when networkBackend == libp2p:
@ -970,14 +997,31 @@ proc run*(node: BeaconNode) =
waitFor node.network.subscribe(topicBeaconBlocks) do (signedBlock: SignedBeaconBlock): waitFor node.network.subscribe(topicBeaconBlocks) do (signedBlock: SignedBeaconBlock):
onBeaconBlock(node, signedBlock) onBeaconBlock(node, signedBlock)
do (signedBlock: SignedBeaconBlock) -> bool:
let (afterGenesis, slot) = node.beaconClock.now.toSlot()
if not afterGenesis:
return false
node.blockPool.isValidBeaconBlock(signedBlock, slot, {})
waitFor allFutures(mapIt( proc attestationHandler(attestation: Attestation) =
0'u64 ..< ATTESTATION_SUBNET_COUNT.uint64, # Avoid double-counting attestation-topic attestations on shared codepath
node.network.subscribe(getAttestationTopic(it)) do (attestation: Attestation): # when they're reflected through beacon blocks
# Avoid double-counting attestation-topic attestations on shared codepath beacon_attestations_received.inc()
# when they're reflected through beacon blocks node.onAttestation(attestation)
beacon_attestations_received.inc()
node.onAttestation(attestation))) var attestationSubscriptions: seq[Future[void]] = @[]
for it in 0'u64 ..< ATTESTATION_SUBNET_COUNT.uint64:
closureScope:
let ci = it
attestationSubscriptions.add(node.network.subscribe(
getAttestationTopic(ci), attestationHandler,
proc(attestation: Attestation): bool =
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/p2p-interface.md#attestation-subnets
let (afterGenesis, slot) = node.beaconClock.now().toSlot()
if not afterGenesis:
return false
node.attestationPool.isValidAttestation(attestation, slot, ci, {})))
waitFor allFutures(attestationSubscriptions)
let let
t = node.beaconClock.now().toSlot() t = node.beaconClock.now().toSlot()
@ -1172,10 +1216,6 @@ when isMainModule:
proc (logLevel: LogLevel, msg: LogOutputStr) {.gcsafe.} = proc (logLevel: LogLevel, msg: LogOutputStr) {.gcsafe.} =
stdout.write(msg) stdout.write(msg)
debug "Launching beacon node",
version = fullVersionStr,
cmdParams = commandLineParams(), config
randomize() randomize()
if config.logLevel != LogLevel.NONE: if config.logLevel != LogLevel.NONE:
@ -1231,15 +1271,12 @@ when isMainModule:
if bootstrapFile.len > 0: if bootstrapFile.len > 0:
let let
networkKeys = getPersistentNetKeys(config) networkKeys = getPersistentNetKeys(config)
bootstrapAddress = enode.Address(
ip: config.bootstrapAddress,
tcpPort: config.bootstrapPort,
udpPort: config.bootstrapPort)
bootstrapEnr = enr.Record.init( bootstrapEnr = enr.Record.init(
1, # sequence number 1, # sequence number
networkKeys.seckey.asEthKey, networkKeys.seckey.asEthKey,
bootstrapAddress) some(config.bootstrapAddress),
config.bootstrapPort,
config.bootstrapPort)
writeFile(bootstrapFile, bootstrapEnr.toURI) writeFile(bootstrapFile, bootstrapEnr.toURI)
echo "Wrote ", bootstrapFile echo "Wrote ", bootstrapFile
@ -1261,6 +1298,11 @@ when isMainModule:
reportFailureFor keyFile.string reportFailureFor keyFile.string
of noCommand: of noCommand:
debug "Launching beacon node",
version = fullVersionStr,
cmdParams = commandLineParams(),
config
createPidFile(config.dataDir.string / "beacon_node.pid") createPidFile(config.dataDir.string / "beacon_node.pid")
var node = waitFor BeaconNode.init(config) var node = waitFor BeaconNode.init(config)

View File

@ -136,7 +136,10 @@ type
inAdd*: bool inAdd*: bool
headState*: StateData ## State given by the head block headState*: StateData ## \
## State given by the head block; only update in `updateHead`, not anywhere
## else via `withState`
justifiedState*: StateData ## Latest justified state, as seen from the head justifiedState*: StateData ## Latest justified state, as seen from the head
tmpState*: StateData ## Scratchpad - may be any state tmpState*: StateData ## Scratchpad - may be any state

View File

@ -943,7 +943,7 @@ proc getProposer*(pool: BlockPool, head: BlockRef, slot: Slot): Option[Validator
pool.withState(pool.tmpState, head.atSlot(slot)): pool.withState(pool.tmpState, head.atSlot(slot)):
var cache = get_empty_per_epoch_cache() var cache = get_empty_per_epoch_cache()
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#validator-assignments # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#validator-assignments
let proposerIdx = get_beacon_proposer_index(state, cache) let proposerIdx = get_beacon_proposer_index(state, cache)
if proposerIdx.isNone: if proposerIdx.isNone:
warn "Missing proposer index", warn "Missing proposer index",
@ -956,3 +956,131 @@ proc getProposer*(pool: BlockPool, head: BlockRef, slot: Slot): Option[Validator
return return
return some(state.validators[proposerIdx.get()].pubkey) return some(state.validators[proposerIdx.get()].pubkey)
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/p2p-interface.md#global-topics
proc isValidBeaconBlock*(pool: BlockPool,
signed_beacon_block: SignedBeaconBlock, current_slot: Slot,
flags: UpdateFlags): bool =
# In general, checks are ordered from cheap to expensive. Especially, crypto
# verification could be quite a bit more expensive than the rest. This is an
# externally easy-to-invoke function by tossing network packets at the node.
# The block is not from a future slot
# TODO allow `MAXIMUM_GOSSIP_CLOCK_DISPARITY` leniency, especially towards
# seemingly future slots.
if not (signed_beacon_block.message.slot <= current_slot):
debug "isValidBeaconBlock: block is from a future slot",
signed_beacon_block_message_slot = signed_beacon_block.message.slot,
current_slot = current_slot
return false
# The block is from a slot greater than the latest finalized slot (with a
# MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) -- i.e. validate that
# signed_beacon_block.message.slot >
# compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
if not (signed_beacon_block.message.slot > pool.finalizedHead.slot):
debug "isValidBeaconBlock: block is not from a slot greater than the latest finalized slot"
return false
# The proposer signature, signed_beacon_block.signature, is valid with
# respect to the proposer_index pubkey.
# TODO resolve following two checks' robustness and remove this early exit.
const alwaysTrue = true
if alwaysTrue:
return true
# TODO because this check depends on the proposer aspect, and see the comment
# there for that issue, the fallout is this check isn't reliable anymore.
# The block is the first block with valid signature received for the proposer
# for the slot, signed_beacon_block.message.slot.
#
# While this condition is similar to the proposer slashing condition at
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#proposer-slashing
# it's not identical, and this check does not address slashing:
#
# (1) The beacon blocks must be conflicting, i.e. different, for the same
# slot and proposer. This check also catches identical blocks.
#
# (2) By this point in the function, it's not been checked whether they're
# signed yet. As in general, expensive checks should be deferred, this
# would add complexity not directly relevant this function.
#
# (3) As evidenced by point (1), the similarity in the validation condition
# and slashing condition, while not coincidental, aren't similar enough
# to combine, as one or the other might drift.
#
# (4) Furthermore, this function, as much as possible, simply returns a yes
# or no answer, without modifying other state for p2p network interface
# validation. Complicating this interface, for the sake of sharing only
# couple lines of code, wouldn't be worthwhile.
#
# TODO might check unresolved/orphaned blocks too, and this might not see all
# blocks at a given slot (though, in theory, those get checked elsewhere), or
# adding metrics that count how often these conditions occur.
let slotBlockRef =
getBlockByPreciseSlot(pool, signed_beacon_block.message.slot)
if (not slotBlockRef.isNil) and
pool.get(slotBlockRef).data.message.proposer_index ==
signed_beacon_block.message.proposer_index:
debug "isValidBeaconBlock: block isn't first block with valid signature received for the proposer",
signed_beacon_block_message_slot = signed_beacon_block.message.slot,
blckRef = getBlockByPreciseSlot(pool, signed_beacon_block.message.slot)
return false
# If this block doesn't have a parent we know about, we can't/don't really
# trace it back to a known-good state/checkpoint to verify its prevenance;
# while one could getOrResolve to queue up searching for missing parent it
# might not be the best place. As much as feasible, this function aims for
# answering yes/no, not queuing other action or otherwise altering state.
let parent_ref = pool.getRef(signed_beacon_block.message.parent_root)
if parent_ref.isNil:
# TODO find where incorrect block's being produced at/around epoch 20,
# nim-beacon-chain commit 708ac80daef5e05e01d4fc84576f8692adc256a3, at
# 2020-04-02, running `make eth2_network_simulation`, or, alternately,
# why correctly produced ancestor block isn't found. By appearances, a
# chain is being forked, probably by node 0, as nodes 1/2/3 die first,
# then node 0 only dies eventually then nodes 1/2/3 are not around, to
# help it in turn finalize. So node 0 is probably culprit, around/near
# the end of epoch 19, in its block proposal(s). BlockPool.add() later
# discovers this same missing parent. The missing step here is that we
# need to be able to receive this block and store it in unresolved but
# without passing it on to other nodes (which is what EV actually does
# specify). The other BeaconBlock validation conditions cannot change,
# just because later blocks fill in gaps, but this one can. My read of
# the intent here is that only nodes which know about the parentage of
# a block should pass it on. That doesn't mean we shouldn't process it
# though, just not rebroadcast it.
# Debug output: isValidBeaconBlock: incorrectly skipping BLS validation when parent block unknown topics="blkpool" tid=2111475 file=block_pool.nim:1040 current_epoch=22 current_slot=133 parent_root=72b5b0f1 pool_head_slot=131 pool_head_state_root=48e9f4b8 proposed_block_slot=133 proposed_block_state_root=ed7b1ddd proposer_index=42 node=3
# So it's missing a head update, probably, at slot 132.
debug "isValidBeaconBlock: incorrectly skipping BLS validation when parent block unknown",
current_slot = current_slot,
current_epoch = compute_epoch_at_slot(current_slot),
parent_root = signed_beacon_block.message.parent_root,
proposed_block_slot = signed_beacon_block.message.slot,
proposer_index = signed_beacon_block.message.proposer_index,
proposed_block_state_root = signed_beacon_block.message.state_root,
pool_head_slot = pool.headState.data.data.slot,
pool_head_state_root = pool.headState.data.root
return false
let bs =
BlockSlot(blck: parent_ref, slot: pool.get(parent_ref).data.message.slot)
pool.withState(pool.tmpState, bs):
let
blockRoot = hash_tree_root(signed_beacon_block.message)
domain = get_domain(pool.headState.data.data, DOMAIN_BEACON_PROPOSER,
compute_epoch_at_slot(signed_beacon_block.message.slot))
signing_root = compute_signing_root(blockRoot, domain)
proposer_index = signed_beacon_block.message.proposer_index
if proposer_index >= pool.headState.data.data.validators.len.uint64:
return false
if not blsVerify(pool.headState.data.data.validators[proposer_index].pubkey,
signing_root.data, signed_beacon_block.signature):
debug "isValidBeaconBlock: block failed signature verification"
return false
true

View File

@ -67,7 +67,7 @@ proc main() {.async.} =
let cfg = CliConfig.load() let cfg = CliConfig.load()
let web3 = await newWeb3(cfg.depositWeb3Url) let web3 = await newWeb3(cfg.depositWeb3Url)
if cfg.privateKey.len != 0: if cfg.privateKey.len != 0:
web3.privateKey = initPrivateKey(cfg.privateKey) web3.privateKey = PrivateKey.fromHex(cfg.privateKey)[]
else: else:
let accounts = await web3.provider.eth_accounts() let accounts = await web3.provider.eth_accounts()
doAssert(accounts.len > 0) doAssert(accounts.len > 0)

View File

@ -1,6 +1,10 @@
# TODO Cannot use push here becaise it gets applied to PeerID.init (!)
# probably because it's a generic proc...
# {.push raises: [Defect].}
import import
os, net, strutils, strformat, parseutils, os, net, strutils, strformat, parseutils,
chronicles, stew/[result, objects], eth/keys, eth/trie/db, eth/p2p/enode, chronicles, stew/[results, objects], eth/keys, eth/trie/db, eth/p2p/enode,
eth/p2p/discoveryv5/[enr, protocol, discovery_db, types], eth/p2p/discoveryv5/[enr, protocol, discovery_db, types],
libp2p/[multiaddress, peer], libp2p/[multiaddress, peer],
libp2p/crypto/crypto as libp2pCrypto, libp2p/crypto/crypto as libp2pCrypto,
@ -12,26 +16,13 @@ type
PublicKey = keys.PublicKey PublicKey = keys.PublicKey
export export
Eth2DiscoveryProtocol, open, close, result Eth2DiscoveryProtocol, open, start, close, results
proc new*(T: type Eth2DiscoveryProtocol,
conf: BeaconNodeConf,
ip: IpAddress, rawPrivKeyBytes: openarray[byte]): T =
# TODO
# Implement more configuration options:
# * for setting up a specific key
# * for using a persistent database
var
pk = initPrivateKey(rawPrivKeyBytes)
db = DiscoveryDB.init(newMemoryDB())
newProtocol(pk, db, ip, conf.tcpPort, conf.udpPort)
proc toENode*(a: MultiAddress): Result[ENode, cstring] =
if not IPFS.match(a):
return err "Unsupported MultiAddress"
proc toENode*(a: MultiAddress): Result[ENode, cstring] {.raises: [Defect].} =
try: try:
if not IPFS.match(a):
return err "Unsupported MultiAddress"
# TODO. This code is quite messy with so much string handling. # TODO. This code is quite messy with so much string handling.
# MultiAddress can offer a more type-safe API? # MultiAddress can offer a more type-safe API?
var var
@ -58,7 +49,7 @@ proc toENode*(a: MultiAddress): Result[ENode, cstring] =
var pubkey: libp2pCrypto.PublicKey var pubkey: libp2pCrypto.PublicKey
if peerId.extractPublicKey(pubkey): if peerId.extractPublicKey(pubkey):
if pubkey.scheme == Secp256k1: if pubkey.scheme == Secp256k1:
return ok ENode(pubkey: pubkey.skkey, return ok ENode(pubkey: PublicKey(pubkey.skkey),
address: Address(ip: ipAddress, address: Address(ip: ipAddress,
tcpPort: Port tcpPort, tcpPort: Port tcpPort,
udpPort: Port udpPort)) udpPort: Port udpPort))
@ -66,15 +57,20 @@ proc toENode*(a: MultiAddress): Result[ENode, cstring] =
except CatchableError: except CatchableError:
# This will reach the error exit path below # This will reach the error exit path below
discard discard
except Exception as e:
# TODO:
# nim-libp2p/libp2p/multiaddress.nim(616, 40) Error: can raise an unlisted exception: Exception
if e of Defect:
raise (ref Defect)(e)
return err "Invalid MultiAddress" return err "Invalid MultiAddress"
proc toMultiAddressStr*(enode: ENode): string = proc toMultiAddressStr*(enode: ENode): string =
var peerId = PeerID.init(libp2pCrypto.PublicKey(scheme: Secp256k1, var peerId = PeerID.init(libp2pCrypto.PublicKey(
skkey: enode.pubkey)) scheme: Secp256k1, skkey: SkPublicKey(enode.pubkey)))
&"/ip4/{enode.address.ip}/tcp/{enode.address.tcpPort}/p2p/{peerId.pretty}" &"/ip4/{enode.address.ip}/tcp/{enode.address.tcpPort}/p2p/{peerId.pretty}"
proc toENode*(enrRec: enr.Record): Result[ENode, cstring] = proc toENode*(enrRec: enr.Record): Result[ENode, cstring] {.raises: [Defect].} =
try: try:
# TODO: handle IPv6 # TODO: handle IPv6
let ipBytes = enrRec.get("ip", seq[byte]) let ipBytes = enrRec.get("ip", seq[byte])
@ -85,10 +81,10 @@ proc toENode*(enrRec: enr.Record): Result[ENode, cstring] =
address_v4: toArray(4, ipBytes)) address_v4: toArray(4, ipBytes))
tcpPort = Port enrRec.get("tcp", uint16) tcpPort = Port enrRec.get("tcp", uint16)
udpPort = Port enrRec.get("udp", uint16) udpPort = Port enrRec.get("udp", uint16)
var pubKey: keys.PublicKey let pubkey = enrRec.get(PublicKey)
if not enrRec.get(pubKey): if pubkey.isNone:
return err "Failed to read public key from ENR record" return err "Failed to read public key from ENR record"
return ok ENode(pubkey: pubkey, return ok ENode(pubkey: pubkey.get(),
address: Address(ip: ip, address: Address(ip: ip,
tcpPort: tcpPort, tcpPort: tcpPort,
udpPort: udpPort)) udpPort: udpPort))
@ -165,3 +161,27 @@ proc loadBootstrapFile*(bootstrapFile: string,
error "Unknown bootstrap file format", ext error "Unknown bootstrap file format", ext
quit 1 quit 1
proc new*(T: type Eth2DiscoveryProtocol,
conf: BeaconNodeConf,
ip: Option[IpAddress], tcpPort, udpPort: Port,
rawPrivKeyBytes: openarray[byte]): T =
# TODO
# Implement more configuration options:
# * for setting up a specific key
# * for using a persistent database
var
pk = PrivateKey.fromRaw(rawPrivKeyBytes).tryGet()
ourPubKey = pk.toPublicKey().tryGet()
db = DiscoveryDB.init(newMemoryDB())
var bootNodes: seq[ENode]
var bootEnrs: seq[enr.Record]
for node in conf.bootstrapNodes:
addBootstrapNode(node, bootNodes, bootEnrs, ourPubKey)
loadBootstrapFile(string conf.bootstrapNodesFile, bootNodes, bootEnrs, ourPubKey)
let persistentBootstrapFile = conf.dataDir / "bootstrap_nodes.txt"
if fileExists(persistentBootstrapFile):
loadBootstrapFile(persistentBootstrapFile, bootNodes, bootEnrs, ourPubKey)
newProtocol(pk, db, ip, tcpPort, udpPort, bootEnrs)

File diff suppressed because it is too large Load Diff

View File

@ -51,7 +51,7 @@ func makeDeposit*(
withdrawal_credentials: makeWithdrawalCredentials(pubkey))) withdrawal_credentials: makeWithdrawalCredentials(pubkey)))
if skipBLSValidation notin flags: if skipBLSValidation notin flags:
let domain = compute_domain(DOMAIN_DEPOSIT) let domain = compute_domain(DOMAIN_DEPOSIT, GENESIS_FORK_VERSION)
let signing_root = compute_signing_root(ret.getDepositMessage, domain) let signing_root = compute_signing_root(ret.getDepositMessage, domain)
ret.data.signature = bls_sign(privkey, signing_root.data) ret.data.signature = bls_sign(privkey, signing_root.data)

View File

@ -1,423 +0,0 @@
import
algorithm, typetraits, net as stdNet,
stew/[varints,base58], stew/shims/[macros, tables], chronos, chronicles,
stint, faststreams/output_stream, serialization,
json_serialization/std/[net, options],
eth/[keys, async_utils], eth/p2p/[enode, p2p_protocol_dsl],
eth/p2p/discoveryv5/[enr, node],
# TODO: create simpler to use libp2p modules that use re-exports
libp2p/[switch, multistream, connection,
multiaddress, peerinfo, peer,
crypto/crypto, protocols/identify, protocols/protocol],
libp2p/muxers/mplex/[mplex, types],
libp2p/protocols/secure/[secure, secio],
libp2p/protocols/pubsub/[pubsub, floodsub],
libp2p/transports/[transport, tcptransport],
libp2p_json_serialization, eth2_discovery, conf, ssz,
peer_pool
import
eth/p2p/discoveryv5/protocol as discv5_protocol
export
p2pProtocol, libp2p_json_serialization, ssz
type
P2PStream = Connection
# TODO Is this really needed?
Eth2Node* = ref object of RootObj
switch*: Switch
discovery*: Eth2DiscoveryProtocol
wantedPeers*: int
peerPool*: PeerPool[Peer, PeerID]
protocolStates*: seq[RootRef]
libp2pTransportLoops*: seq[Future[void]]
EthereumNode = Eth2Node # needed for the definitions in p2p_backends_helpers
Peer* = ref object
network*: Eth2Node
info*: PeerInfo
wasDialed*: bool
discoveryId*: Eth2DiscoveryId
connectionState*: ConnectionState
protocolStates*: seq[RootRef]
maxInactivityAllowed*: Duration
score*: int
ConnectionState* = enum
None,
Connecting,
Connected,
Disconnecting,
Disconnected
UntypedResponder = object
peer*: Peer
stream*: P2PStream
Responder*[MsgType] = distinct UntypedResponder
MessageInfo* = object
name*: string
# Private fields:
libp2pCodecName: string
protocolMounter*: MounterProc
printer*: MessageContentPrinter
nextMsgResolver*: NextMsgResolver
ProtocolInfoObj* = object
name*: string
messages*: seq[MessageInfo]
index*: int # the position of the protocol in the
# ordered list of supported protocols
# Private fields:
peerStateInitializer*: PeerStateInitializer
networkStateInitializer*: NetworkStateInitializer
handshake*: HandshakeStep
disconnectHandler*: DisconnectionHandler
ProtocolInfo* = ptr ProtocolInfoObj
PeerStateInitializer* = proc(peer: Peer): RootRef {.gcsafe.}
NetworkStateInitializer* = proc(network: EthereumNode): RootRef {.gcsafe.}
HandshakeStep* = proc(peer: Peer, stream: P2PStream): Future[void] {.gcsafe.}
DisconnectionHandler* = proc(peer: Peer): Future[void] {.gcsafe.}
ThunkProc* = LPProtoHandler
MounterProc* = proc(network: Eth2Node) {.gcsafe.}
MessageContentPrinter* = proc(msg: pointer): string {.gcsafe.}
NextMsgResolver* = proc(msgData: SszReader, future: FutureBase) {.gcsafe.}
DisconnectionReason* = enum
ClientShutDown
IrrelevantNetwork
FaultOrError
PeerDisconnected* = object of CatchableError
reason*: DisconnectionReason
TransmissionError* = object of CatchableError
const
TCP = net.Protocol.IPPROTO_TCP
template `$`*(peer: Peer): string = id(peer.info)
chronicles.formatIt(Peer): $it
template remote*(peer: Peer): untyped =
peer.info.peerId
# TODO: This exists only as a compatibility layer between the daemon
# APIs and the native LibP2P ones. It won't be necessary once the
# daemon is removed.
#
template writeAllBytes(stream: P2PStream, bytes: seq[byte]): untyped =
write(stream, bytes)
template openStream(node: Eth2Node, peer: Peer, protocolId: string): untyped =
dial(node.switch, peer.info, protocolId)
proc peer(stream: P2PStream): PeerID =
# TODO: Can this be `nil`?
stream.peerInfo.peerId
#
# End of compatibility layer
proc init*(T: type Peer, network: Eth2Node, info: PeerInfo): Peer {.gcsafe.}
proc getPeer*(node: Eth2Node, peerInfo: PeerInfo): Peer {.gcsafe.} =
let peerId = peerInfo.peerId
result = node.peerPool.getOrDefault(peerId)
if result == nil:
result = Peer.init(node, peerInfo)
proc peerFromStream(network: Eth2Node, stream: P2PStream): Peer {.gcsafe.} =
# TODO: Can this be `nil`?
return network.getPeer(stream.peerInfo)
proc getKey*(peer: Peer): PeerID {.inline.} =
result = peer.info.peerId
proc getFuture*(peer: Peer): Future[void] {.inline.} =
result = peer.info.lifeFuture()
proc `<`*(a, b: Peer): bool =
result = `<`(a.score, b.score)
proc disconnect*(peer: Peer, reason: DisconnectionReason,
notifyOtherPeer = false) {.async.} =
# TODO: How should we notify the other peer?
if peer.connectionState notin {Disconnecting, Disconnected}:
peer.connectionState = Disconnecting
await peer.network.switch.disconnect(peer.info)
peer.connectionState = Disconnected
peer.network.peerPool.release(peer)
peer.info.close()
proc safeClose(stream: P2PStream) {.async.} =
if not stream.closed:
await close(stream)
proc handleIncomingPeer*(peer: Peer)
include eth/p2p/p2p_backends_helpers
include eth/p2p/p2p_tracing
include libp2p_backends_common
proc handleOutgoingPeer*(peer: Peer): Future[void] {.async.} =
let network = peer.network
proc onPeerClosed(udata: pointer) {.gcsafe.} =
debug "Peer (outgoing) lost", peer = $peer.info
libp2p_peers.set int64(len(network.peerPool))
let res = await network.peerPool.addOutgoingPeer(peer)
if res:
debug "Peer (outgoing) has been added to PeerPool", peer = $peer.info
peer.getFuture().addCallback(onPeerClosed)
libp2p_peers.set int64(len(network.peerPool))
proc handleIncomingPeer*(peer: Peer) =
let network = peer.network
proc onPeerClosed(udata: pointer) {.gcsafe.} =
debug "Peer (incoming) lost", peer = $peer.info
libp2p_peers.set int64(len(network.peerPool))
let res = network.peerPool.addIncomingPeerNoWait(peer)
if res:
debug "Peer (incoming) has been added to PeerPool", peer = $peer.info
peer.getFuture().addCallback(onPeerClosed)
libp2p_peers.set int64(len(network.peerPool))
proc toPeerInfo*(r: enr.TypedRecord): PeerInfo =
if r.secp256k1.isSome:
var pubKey: keys.PublicKey
if recoverPublicKey(r.secp256k1.get, pubKey) != EthKeysStatus.Success:
return # TODO
let peerId = PeerID.init crypto.PublicKey(scheme: Secp256k1, skkey: pubKey)
var addresses = newSeq[MultiAddress]()
if r.ip.isSome and r.tcp.isSome:
let ip = IpAddress(family: IpAddressFamily.IPv4,
address_v4: r.ip.get)
addresses.add MultiAddress.init(ip, TCP, Port r.tcp.get)
if r.ip6.isSome:
let ip = IpAddress(family: IpAddressFamily.IPv6,
address_v6: r.ip6.get)
if r.tcp6.isSome:
addresses.add MultiAddress.init(ip, TCP, Port r.tcp6.get)
elif r.tcp.isSome:
addresses.add MultiAddress.init(ip, TCP, Port r.tcp.get)
else:
discard
if addresses.len > 0:
return PeerInfo.init(peerId, addresses)
proc toPeerInfo(r: Option[enr.TypedRecord]): PeerInfo =
if r.isSome:
return r.get.toPeerInfo
proc dialPeer*(node: Eth2Node, peerInfo: PeerInfo) {.async.} =
logScope: peer = $peerInfo
debug "Connecting to peer"
await node.switch.connect(peerInfo)
var peer = node.getPeer(peerInfo)
peer.wasDialed = true
debug "Initializing connection"
await initializeConnection(peer)
inc libp2p_successful_dials
debug "Network handshakes completed"
await handleOutgoingPeer(peer)
proc runDiscoveryLoop*(node: Eth2Node) {.async.} =
debug "Starting discovery loop"
while true:
let currentPeerCount = node.peerPool.len
if currentPeerCount < node.wantedPeers:
try:
let discoveredPeers =
node.discovery.randomNodes(node.wantedPeers - currentPeerCount)
debug "Discovered peers", peer = $discoveredPeers
for peer in discoveredPeers:
try:
let peerInfo = peer.record.toTypedRecord.toPeerInfo
if peerInfo != nil and peerInfo.id notin node.switch.connections:
# TODO do this in parallel
await node.dialPeer(peerInfo)
except CatchableError as err:
debug "Failed to connect to peer", peer = $peer, err = err.msg
except CatchableError as err:
debug "Failure in discovery", err = err.msg
await sleepAsync seconds(1)
proc init*(T: type Eth2Node, conf: BeaconNodeConf,
switch: Switch, ip: IpAddress, privKey: keys.PrivateKey): T =
new result
result.switch = switch
result.discovery = Eth2DiscoveryProtocol.new(conf, ip, privKey.data)
result.wantedPeers = conf.maxPeers
result.peerPool = newPeerPool[Peer, PeerID](maxPeers = conf.maxPeers)
newSeq result.protocolStates, allProtocols.len
for proto in allProtocols:
if proto.networkStateInitializer != nil:
result.protocolStates[proto.index] = proto.networkStateInitializer(result)
for msg in proto.messages:
if msg.protocolMounter != nil:
msg.protocolMounter result
template publicKey*(node: Eth2Node): keys.PublicKey =
node.discovery.privKey.getPublicKey
template addKnownPeer*(node: Eth2Node, peer: ENode|enr.Record) =
node.discovery.addNode peer
proc start*(node: Eth2Node) {.async.} =
node.discovery.open()
node.libp2pTransportLoops = await node.switch.start()
traceAsyncErrors node.runDiscoveryLoop()
proc init*(T: type Peer, network: Eth2Node, info: PeerInfo): Peer =
new result
result.info = info
result.network = network
result.connectionState = Connected
result.maxInactivityAllowed = 15.minutes # TODO: Read this from the config
newSeq result.protocolStates, allProtocols.len
for i in 0 ..< allProtocols.len:
let proto = allProtocols[i]
if proto.peerStateInitializer != nil:
result.protocolStates[i] = proto.peerStateInitializer(result)
proc registerMsg(protocol: ProtocolInfo,
name: string,
mounter: MounterProc,
libp2pCodecName: string,
printer: MessageContentPrinter) =
protocol.messages.add MessageInfo(name: name,
protocolMounter: mounter,
libp2pCodecName: libp2pCodecName,
printer: printer)
proc p2pProtocolBackendImpl*(p: P2PProtocol): Backend =
var
Format = ident "SSZ"
Responder = bindSym "Responder"
P2PStream = bindSym "P2PStream"
OutputStream = bindSym "OutputStream"
Peer = bindSym "Peer"
Eth2Node = bindSym "Eth2Node"
messagePrinter = bindSym "messagePrinter"
milliseconds = bindSym "milliseconds"
registerMsg = bindSym "registerMsg"
initProtocol = bindSym "initProtocol"
bindSymOp = bindSym "bindSym"
errVar = ident "err"
msgVar = ident "msg"
msgBytesVar = ident "msgBytes"
networkVar = ident "network"
await = ident "await"
callUserHandler = ident "callUserHandler"
p.useRequestIds = false
p.useSingleRecordInlining = true
new result
result.PeerType = Peer
result.NetworkType = Eth2Node
result.registerProtocol = bindSym "registerProtocol"
result.setEventHandlers = bindSym "setEventHandlers"
result.SerializationFormat = Format
result.ResponderType = Responder
result.afterProtocolInit = proc (p: P2PProtocol) =
p.onPeerConnected.params.add newIdentDefs(streamVar, P2PStream)
result.implementMsg = proc (msg: Message) =
let
protocol = msg.protocol
msgName = $msg.ident
msgNameLit = newLit msgName
MsgRecName = msg.recName
MsgStrongRecName = msg.strongRecName
codecNameLit = getRequestProtoName(msg.procDef)
if msg.procDef.body.kind != nnkEmpty and msg.kind == msgRequest:
# Request procs need an extra param - the stream where the response
# should be written:
msg.userHandler.params.insert(2, newIdentDefs(streamVar, P2PStream))
msg.initResponderCall.add streamVar
##
## Implement the Thunk:
##
## The protocol handlers in nim-libp2p receive only a `P2PStream`
## parameter and there is no way to access the wider context (such
## as the current `Switch`). In our handlers, we may need to list all
## peers in the current network, so we must keep a reference to the
## network object in the closure environment of the installed handlers.
##
## For this reason, we define a `protocol mounter` proc that will
## initialize the network object by creating handlers bound to the
## specific network.
##
let
protocolMounterName = ident(msgName & "_mounter")
userHandlerCall = msg.genUserHandlerCall(msgVar, [peerVar, streamVar])
var mounter: NimNode
if msg.userHandler != nil:
protocol.outRecvProcs.add quote do:
template `callUserHandler`(`peerVar`: `Peer`,
`streamVar`: `P2PStream`,
`msgVar`: `MsgRecName`): untyped =
`userHandlerCall`
proc `protocolMounterName`(`networkVar`: `Eth2Node`) =
proc thunk(`streamVar`: `P2PStream`,
proto: string): Future[void] {.gcsafe.} =
return handleIncomingStream(`networkVar`, `streamVar`,
`MsgStrongRecName`, `Format`)
mount `networkVar`.switch,
LPProtocol(codec: `codecNameLit`, handler: thunk)
mounter = protocolMounterName
else:
mounter = newNilLit()
##
## Implement Senders and Handshake
##
if msg.kind == msgHandshake:
macros.error "Handshake messages are not supported in LibP2P protocols"
else:
var sendProc = msg.createSendProc()
implementSendProcBody sendProc
protocol.outProcRegistrations.add(
newCall(registerMsg,
protocol.protocolInfoVar,
msgNameLit,
mounter,
codecNameLit,
newTree(nnkBracketExpr, messagePrinter, MsgRecName)))
result.implementProtocolInit = proc (p: P2PProtocol): NimNode =
return newCall(initProtocol, newLit(p.name), p.peerInit, p.netInit)

View File

@ -1,407 +0,0 @@
import
metrics
type
ResponseCode* = enum
Success
InvalidRequest
ServerError
Bytes = seq[byte]
const
defaultIncomingReqTimeout = 5000
HandshakeTimeout = FaultOrError
# Spec constants
# https://github.com/ethereum/eth2.0-specs/blob/dev/specs/networking/p2p-interface.md#eth-20-network-interaction-domains
REQ_RESP_MAX_SIZE* = 1 * 1024 * 1024 # bytes
GOSSIP_MAX_SIZE* = 1 * 1024 * 1024 # bytes
TTFB_TIMEOUT* = 5.seconds
RESP_TIMEOUT* = 10.seconds
readTimeoutErrorMsg = "Exceeded read timeout for a request"
logScope:
topics = "libp2p"
declarePublicGauge libp2p_successful_dials,
"Number of successfully dialed peers"
declarePublicGauge libp2p_peers,
"Number of active libp2p peers"
template libp2pProtocol*(name: string, version: int) {.pragma.}
proc getRequestProtoName(fn: NimNode): NimNode =
# `getCustomPragmaVal` doesn't work yet on regular nnkProcDef nodes
# (TODO: file as an issue)
let pragmas = fn.pragma
if pragmas.kind == nnkPragma and pragmas.len > 0:
for pragma in pragmas:
if pragma.len > 0 and $pragma[0] == "libp2pProtocol":
let protoName = $(pragma[1])
let protoVer = $(pragma[2].intVal)
return newLit("/eth2/beacon_chain/req/" & protoName & "/" & protoVer & "/ssz")
return newLit("")
template raisePeerDisconnected(msg: string, r: DisconnectionReason) =
var e = newException(PeerDisconnected, msg)
e.reason = r
raise e
proc disconnectAndRaise(peer: Peer,
reason: DisconnectionReason,
msg: string) {.async.} =
let r = reason
await peer.disconnect(r)
raisePeerDisconnected(msg, r)
proc readChunk(stream: P2PStream,
MsgType: type,
withResponseCode: bool,
deadline: Future[void]): Future[Option[MsgType]] {.gcsafe.}
proc readSizePrefix(stream: P2PStream,
deadline: Future[void]): Future[int] {.async.} =
trace "about to read msg size prefix"
var parser: VarintParser[uint64, ProtoBuf]
while true:
var nextByte: byte
var readNextByte = stream.readExactly(addr nextByte, 1)
await readNextByte or deadline
if not readNextByte.finished:
trace "size prefix byte not received in time"
return -1
case parser.feedByte(nextByte)
of Done:
let res = parser.getResult
if res > uint64(REQ_RESP_MAX_SIZE):
trace "size prefix outside of range", res
return -1
else:
trace "got size prefix", res
return int(res)
of Overflow:
trace "size prefix overflow"
return -1
of Incomplete:
continue
proc readMsgBytes(stream: P2PStream,
withResponseCode: bool,
deadline: Future[void]): Future[Bytes] {.async.} =
trace "about to read message bytes", withResponseCode
try:
if withResponseCode:
var responseCode: byte
trace "about to read response code"
var readResponseCode = stream.readExactly(addr responseCode, 1)
await readResponseCode or deadline
if not readResponseCode.finished:
trace "response code not received in time"
return
if responseCode > ResponseCode.high.byte:
trace "invalid response code", responseCode
return
logScope: responseCode = ResponseCode(responseCode)
trace "got response code"
case ResponseCode(responseCode)
of InvalidRequest, ServerError:
let responseErrMsg = await readChunk(stream, string, false, deadline)
debug "P2P request resulted in error", responseErrMsg
return
of Success:
# The response is OK, the execution continues below
discard
var sizePrefix = await readSizePrefix(stream, deadline)
trace "got msg size prefix", sizePrefix
if sizePrefix == -1:
debug "Failed to read an incoming message size prefix", peer = stream.peer
return
if sizePrefix == 0:
debug "Received SSZ with zero size", peer = stream.peer
return
trace "about to read msg bytes", len = sizePrefix
var msgBytes = newSeq[byte](sizePrefix)
var readBody = stream.readExactly(addr msgBytes[0], sizePrefix)
await readBody or deadline
if not readBody.finished:
trace "msg bytes not received in time"
return
trace "got message bytes", len = sizePrefix
return msgBytes
except TransportIncompleteError:
return @[]
proc readChunk(stream: P2PStream,
MsgType: type,
withResponseCode: bool,
deadline: Future[void]): Future[Option[MsgType]] {.gcsafe, async.} =
var msgBytes = await stream.readMsgBytes(withResponseCode, deadline)
try:
if msgBytes.len > 0:
return some SSZ.decode(msgBytes, MsgType)
except SerializationError as err:
debug "Failed to decode a network message",
msgBytes, errMsg = err.formatMsg("<msg>")
return
proc readResponse(
stream: P2PStream,
MsgType: type,
deadline: Future[void]): Future[Option[MsgType]] {.gcsafe, async.} =
when MsgType is seq:
type E = ElemType(MsgType)
var results: MsgType
while true:
let nextRes = await readChunk(stream, E, true, deadline)
if nextRes.isNone: break
results.add nextRes.get
if results.len > 0:
return some(results)
else:
return await readChunk(stream, MsgType, true, deadline)
proc encodeErrorMsg(responseCode: ResponseCode, errMsg: string): Bytes =
var s = init OutputStream
s.append byte(responseCode)
s.appendVarint errMsg.len
s.appendValue SSZ, errMsg
s.getOutput
proc sendErrorResponse(peer: Peer,
stream: P2PStream,
err: ref SerializationError,
msgName: string,
msgBytes: Bytes) {.async.} =
debug "Received an invalid request",
peer, msgName, msgBytes, errMsg = err.formatMsg("<msg>")
let responseBytes = encodeErrorMsg(InvalidRequest, err.formatMsg("msg"))
await stream.writeAllBytes(responseBytes)
await stream.close()
proc sendErrorResponse(peer: Peer,
stream: P2PStream,
responseCode: ResponseCode,
errMsg: string) {.async.} =
debug "Error processing request", peer, responseCode, errMsg
let responseBytes = encodeErrorMsg(ServerError, errMsg)
await stream.writeAllBytes(responseBytes)
await stream.close()
proc sendNotificationMsg(peer: Peer, protocolId: string, requestBytes: Bytes) {.async} =
var deadline = sleepAsync RESP_TIMEOUT
var streamFut = peer.network.openStream(peer, protocolId)
await streamFut or deadline
if not streamFut.finished:
# TODO: we are returning here because the deadline passed, but
# the stream can still be opened eventually a bit later. Who is
# going to close it then?
raise newException(TransmissionError, "Failed to open LibP2P stream")
let stream = streamFut.read
defer:
await safeClose(stream)
var s = init OutputStream
s.appendVarint requestBytes.len.uint64
s.append requestBytes
let bytes = s.getOutput
await stream.writeAllBytes(bytes)
# TODO There is too much duplication in the responder functions, but
# I hope to reduce this when I increse the reliance on output streams.
proc sendResponseChunkBytes(responder: UntypedResponder, payload: Bytes) {.async.} =
var s = init OutputStream
s.append byte(Success)
s.appendVarint payload.len.uint64
s.append payload
let bytes = s.getOutput
await responder.stream.writeAllBytes(bytes)
proc sendResponseChunkObj(responder: UntypedResponder, val: auto) {.async.} =
var s = init OutputStream
s.append byte(Success)
s.appendValue SSZ, sizePrefixed(val)
let bytes = s.getOutput
await responder.stream.writeAllBytes(bytes)
proc sendResponseChunks[T](responder: UntypedResponder, chunks: seq[T]) {.async.} =
var s = init OutputStream
for chunk in chunks:
s.append byte(Success)
s.appendValue SSZ, sizePrefixed(chunk)
let bytes = s.getOutput
await responder.stream.writeAllBytes(bytes)
proc makeEth2Request(peer: Peer, protocolId: string, requestBytes: Bytes,
ResponseMsg: type,
timeout: Duration): Future[Option[ResponseMsg]] {.gcsafe, async.} =
var deadline = sleepAsync timeout
# Open a new LibP2P stream
var streamFut = peer.network.openStream(peer, protocolId)
await streamFut or deadline
if not streamFut.finished:
# TODO: we are returning here because the deadline passed, but
# the stream can still be opened eventually a bit later. Who is
# going to close it then?
return none(ResponseMsg)
let stream = streamFut.read
defer:
await safeClose(stream)
# Send the request
var s = init OutputStream
s.appendVarint requestBytes.len.uint64
s.append requestBytes
let bytes = s.getOutput
await stream.writeAllBytes(bytes)
# Read the response
return await stream.readResponse(ResponseMsg, deadline)
proc init*[MsgType](T: type Responder[MsgType],
peer: Peer, stream: P2PStream): T =
T(UntypedResponder(peer: peer, stream: stream))
template write*[M](r: var Responder[M], val: auto): auto =
mixin send
type Msg = M
type MsgRec = RecType(Msg)
when MsgRec is seq|openarray:
type E = ElemType(MsgRec)
when val is E:
sendResponseChunkObj(UntypedResponder(r), val)
elif val is MsgRec:
sendResponseChunks(UntypedResponder(r), val)
else:
{.fatal: "Unepected message type".}
else:
send(r, val)
proc performProtocolHandshakes*(peer: Peer) {.async.} =
var subProtocolsHandshakes = newSeqOfCap[Future[void]](allProtocols.len)
for protocol in allProtocols:
if protocol.handshake != nil:
subProtocolsHandshakes.add((protocol.handshake)(peer, nil))
await all(subProtocolsHandshakes)
template initializeConnection*(peer: Peer): auto =
performProtocolHandshakes(peer)
proc initProtocol(name: string,
peerInit: PeerStateInitializer,
networkInit: NetworkStateInitializer): ProtocolInfoObj =
result.name = name
result.messages = @[]
result.peerStateInitializer = peerInit
result.networkStateInitializer = networkInit
proc registerProtocol(protocol: ProtocolInfo) =
# TODO: This can be done at compile-time in the future
let pos = lowerBound(gProtocols, protocol)
gProtocols.insert(protocol, pos)
for i in 0 ..< gProtocols.len:
gProtocols[i].index = i
proc setEventHandlers(p: ProtocolInfo,
handshake: HandshakeStep,
disconnectHandler: DisconnectionHandler) =
p.handshake = handshake
p.disconnectHandler = disconnectHandler
proc implementSendProcBody(sendProc: SendProc) =
let
msg = sendProc.msg
UntypedResponder = bindSym "UntypedResponder"
await = ident "await"
proc sendCallGenerator(peer, bytes: NimNode): NimNode =
if msg.kind != msgResponse:
let msgProto = getRequestProtoName(msg.procDef)
case msg.kind
of msgRequest:
let
timeout = msg.timeoutParam[0]
ResponseRecord = msg.response.recName
quote:
makeEth2Request(`peer`, `msgProto`, `bytes`,
`ResponseRecord`, `timeout`)
else:
quote: sendNotificationMsg(`peer`, `msgProto`, `bytes`)
else:
quote: sendResponseChunkBytes(`UntypedResponder`(`peer`), `bytes`)
sendProc.useStandardBody(nil, nil, sendCallGenerator)
proc handleIncomingStream(network: Eth2Node, stream: P2PStream,
MsgType, Format: distinct type) {.async, gcsafe.} =
mixin callUserHandler, RecType
const msgName = typetraits.name(MsgType)
## Uncomment this to enable tracing on all incoming requests
## You can include `msgNameLit` in the condition to select
## more specific requests:
# when chronicles.runtimeFilteringEnabled:
# setLogLevel(LogLevel.TRACE)
# defer: setLogLevel(LogLevel.DEBUG)
# trace "incoming " & `msgNameLit` & " stream"
let peer = peerFromStream(network, stream)
handleIncomingPeer(peer)
defer:
await safeClose(stream)
let
deadline = sleepAsync RESP_TIMEOUT
msgBytes = await readMsgBytes(stream, false, deadline)
if msgBytes.len == 0:
await sendErrorResponse(peer, stream, ServerError, readTimeoutErrorMsg)
return
type MsgRec = RecType(MsgType)
var msg: MsgRec
try:
msg = decode(Format, msgBytes, MsgRec)
except SerializationError as err:
await sendErrorResponse(peer, stream, err, msgName, msgBytes)
return
except Exception as err:
# TODO. This is temporary code that should be removed after interop.
# It can be enabled only in certain diagnostic builds where it should
# re-raise the exception.
debug "Crash during serialization", inputBytes = toHex(msgBytes), msgName
await sendErrorResponse(peer, stream, ServerError, err.msg)
raise err
try:
logReceivedMsg(peer, MsgType(msg))
await callUserHandler(peer, stream, msg)
except CatchableError as err:
await sendErrorResponse(peer, stream, ServerError, err.msg)

View File

@ -1,266 +0,0 @@
import
algorithm, typetraits,
stew/varints, stew/shims/[macros, tables], chronos, chronicles,
libp2p/daemon/daemonapi, faststreams/output_stream, serialization,
json_serialization/std/options, eth/p2p/p2p_protocol_dsl,
libp2p_json_serialization, ssz
export
daemonapi, p2pProtocol, libp2p_json_serialization, ssz
type
Eth2Node* = ref object of RootObj
daemon*: DaemonAPI
peers*: Table[PeerID, Peer]
protocolStates*: seq[RootRef]
EthereumNode = Eth2Node # needed for the definitions in p2p_backends_helpers
Peer* = ref object
network*: Eth2Node
id*: PeerID
wasDialed*: bool
connectionState*: ConnectionState
protocolStates*: seq[RootRef]
maxInactivityAllowed*: Duration
ConnectionState* = enum
None,
Connecting,
Connected,
Disconnecting,
Disconnected
UntypedResponder = object
peer*: Peer
stream*: P2PStream
Responder*[MsgType] = distinct UntypedResponder
MessageInfo* = object
name*: string
# Private fields:
thunk*: ThunkProc
libp2pProtocol: string
printer*: MessageContentPrinter
nextMsgResolver*: NextMsgResolver
ProtocolInfoObj* = object
name*: string
messages*: seq[MessageInfo]
index*: int # the position of the protocol in the
# ordered list of supported protocols
# Private fields:
peerStateInitializer*: PeerStateInitializer
networkStateInitializer*: NetworkStateInitializer
handshake*: HandshakeStep
disconnectHandler*: DisconnectionHandler
ProtocolInfo* = ptr ProtocolInfoObj
PeerStateInitializer* = proc(peer: Peer): RootRef {.gcsafe.}
NetworkStateInitializer* = proc(network: EthereumNode): RootRef {.gcsafe.}
HandshakeStep* = proc(peer: Peer, stream: P2PStream): Future[void] {.gcsafe.}
DisconnectionHandler* = proc(peer: Peer): Future[void] {.gcsafe.}
ThunkProc* = proc(daemon: DaemonAPI, stream: P2PStream): Future[void] {.gcsafe.}
MessageContentPrinter* = proc(msg: pointer): string {.gcsafe.}
NextMsgResolver* = proc(msgData: SszReader, future: FutureBase) {.gcsafe.}
DisconnectionReason* = enum
ClientShutDown
IrrelevantNetwork
FaultOrError
PeerDisconnected* = object of CatchableError
reason*: DisconnectionReason
TransmissionError* = object of CatchableError
template `$`*(peer: Peer): string = $peer.id
chronicles.formatIt(Peer): $it
# TODO: These exists only as a compatibility layer between the daemon
# APIs and the native LibP2P ones. It won't be necessary once the
# daemon is removed.
#
proc writeAllBytes(stream: P2PStream, bytes: seq[byte]) {.async.} =
let sent = await stream.transp.write(bytes)
if sent != bytes.len:
raise newException(TransmissionError, "Failed to deliver msg bytes")
template readExactly(stream: P2PStream, dst: pointer, dstLen: int): untyped =
readExactly(stream.transp, dst, dstLen)
template openStream(node: Eth2Node, peer: Peer, protocolId: string): untyped =
openStream(node.daemon, peer.id, @[protocolId])
#
# End of compatibility layer
proc init*(T: type Peer, network: Eth2Node, id: PeerID): Peer {.gcsafe.}
template remote*(peer: Peer): untyped =
# TODO: Can we get a proper address here?
peer.id
proc getPeer*(node: Eth2Node, peerId: PeerID): Peer {.gcsafe.} =
result = node.peers.getOrDefault(peerId)
if result == nil:
result = Peer.init(node, peerId)
node.peers[peerId] = result
proc getPeer*(node: Eth2Node, peerInfo: PeerInfo): Peer =
node.getPeer(peerInfo.peer)
proc peerFromStream(node: Eth2Node, stream: P2PStream): Peer {.gcsafe.} =
node.getPeer(stream.peer)
proc disconnect*(peer: Peer, reason: DisconnectionReason, notifyOtherPeer = false) {.async.} =
# TODO: How should we notify the other peer?
if peer.connectionState notin {Disconnecting, Disconnected}:
peer.connectionState = Disconnecting
await peer.network.daemon.disconnect(peer.id)
peer.connectionState = Disconnected
peer.network.peers.del(peer.id)
proc safeClose(stream: P2PStream) {.async.} =
if P2PStreamFlags.Closed notin stream.flags:
await close(stream)
proc handleIncomingPeer*(peer: Peer) {.inline.} =
discard
include eth/p2p/p2p_backends_helpers
include eth/p2p/p2p_tracing
include libp2p_backends_common
proc init*(T: type Eth2Node, daemon: DaemonAPI): Future[T] {.async.} =
new result
result.daemon = daemon
result.daemon.userData = result
result.peers = initTable[PeerID, Peer]()
newSeq result.protocolStates, allProtocols.len
for proto in allProtocols:
if proto.networkStateInitializer != nil:
result.protocolStates[proto.index] = proto.networkStateInitializer(result)
for msg in proto.messages:
if msg.libp2pProtocol.len > 0 and msg.thunk != nil:
await daemon.addHandler(@[msg.libp2pProtocol], msg.thunk)
proc init*(T: type Peer, network: Eth2Node, id: PeerID): Peer =
new result
result.id = id
result.network = network
result.connectionState = Connected
result.maxInactivityAllowed = 15.minutes # TODO: Read this from the config
newSeq result.protocolStates, allProtocols.len
for i in 0 ..< allProtocols.len:
let proto = allProtocols[i]
if proto.peerStateInitializer != nil:
result.protocolStates[i] = proto.peerStateInitializer(result)
proc registerMsg(protocol: ProtocolInfo,
name: string,
thunk: ThunkProc,
libp2pProtocol: string,
printer: MessageContentPrinter) =
protocol.messages.add MessageInfo(name: name,
thunk: thunk,
libp2pProtocol: libp2pProtocol,
printer: printer)
proc p2pProtocolBackendImpl*(p: P2PProtocol): Backend =
var
Format = ident "SSZ"
Responder = bindSym "Responder"
DaemonAPI = bindSym "DaemonAPI"
P2PStream = ident "P2PStream"
OutputStream = bindSym "OutputStream"
Peer = bindSym "Peer"
Eth2Node = bindSym "Eth2Node"
messagePrinter = bindSym "messagePrinter"
milliseconds = bindSym "milliseconds"
registerMsg = bindSym "registerMsg"
initProtocol = bindSym "initProtocol"
bindSymOp = bindSym "bindSym"
errVar = ident "err"
msgVar = ident "msg"
msgBytesVar = ident "msgBytes"
daemonVar = ident "daemon"
await = ident "await"
callUserHandler = ident "callUserHandler"
p.useRequestIds = false
p.useSingleRecordInlining = true
new result
result.PeerType = Peer
result.NetworkType = Eth2Node
result.registerProtocol = bindSym "registerProtocol"
result.setEventHandlers = bindSym "setEventHandlers"
result.SerializationFormat = Format
result.ResponderType = Responder
result.afterProtocolInit = proc (p: P2PProtocol) =
p.onPeerConnected.params.add newIdentDefs(streamVar, P2PStream)
result.implementMsg = proc (msg: Message) =
let
protocol = msg.protocol
msgName = $msg.ident
msgNameLit = newLit msgName
MsgRecName = msg.recName
MsgStrongRecName = msg.strongRecName
if msg.procDef.body.kind != nnkEmpty and msg.kind == msgRequest:
# Request procs need an extra param - the stream where the response
# should be written:
msg.userHandler.params.insert(2, newIdentDefs(streamVar, P2PStream))
msg.initResponderCall.add streamVar
##
## Implemenmt Thunk
##
var thunkName: NimNode
if msg.userHandler != nil:
thunkName = ident(msgName & "_thunk")
let userHandlerCall = msg.genUserHandlerCall(msgVar, [peerVar, streamVar])
msg.defineThunk quote do:
template `callUserHandler`(`peerVar`: `Peer`,
`streamVar`: `P2PStream`,
`msgVar`: `MsgRecName`): untyped =
`userHandlerCall`
proc `thunkName`(`daemonVar`: `DaemonAPI`,
`streamVar`: `P2PStream`): Future[void] {.gcsafe.} =
return handleIncomingStream(`Eth2Node`(`daemonVar`.userData), `streamVar`,
`MsgStrongRecName`, `Format`)
else:
thunkName = newNilLit()
##
## Implement Senders and Handshake
##
if msg.kind == msgHandshake:
macros.error "Handshake messages are not supported in LibP2P protocols"
else:
var sendProc = msg.createSendProc()
implementSendProcBody sendProc
protocol.outProcRegistrations.add(
newCall(registerMsg,
protocol.protocolInfoVar,
msgNameLit,
thunkName,
getRequestProtoName(msg.procDef),
newTree(nnkBracketExpr, messagePrinter, MsgRecName)))
result.implementProtocolInit = proc (p: P2PProtocol): NimNode =
return newCall(initProtocol, newLit(p.name), p.peerInit, p.netInit)

View File

@ -33,56 +33,39 @@ proc fetchAncestorBlocksFromPeer(
debug "Error while fetching ancestor blocks", debug "Error while fetching ancestor blocks",
err = err.msg, root = rec.root, peer = peer err = err.msg, root = rec.root, peer = peer
when networkBackend == libp2p: proc fetchAncestorBlocksFromNetwork(
network: Eth2Node,
rec: FetchRecord,
responseHandler: FetchAncestorsResponseHandler) {.async.} =
var peer: Peer
try:
peer = await network.peerPool.acquire()
let blocks = await peer.beaconBlocksByRoot([rec.root])
if blocks.isSome:
for b in blocks.get:
responseHandler(b)
except CatchableError as err:
debug "Error while fetching ancestor blocks",
err = err.msg, root = rec.root, peer = peer
finally:
if not(isNil(peer)):
network.peerPool.release(peer)
proc fetchAncestorBlocksFromNetwork( proc fetchAncestorBlocks*(requestManager: RequestManager,
network: Eth2Node,
rec: FetchRecord,
responseHandler: FetchAncestorsResponseHandler) {.async.} =
var peer: Peer
try:
peer = await network.peerPool.acquire()
let blocks = await peer.beaconBlocksByRoot([rec.root])
if blocks.isSome:
for b in blocks.get:
responseHandler(b)
except CatchableError as err:
debug "Error while fetching ancestor blocks",
err = err.msg, root = rec.root, peer = peer
finally:
if not(isNil(peer)):
network.peerPool.release(peer)
proc fetchAncestorBlocks*(requestManager: RequestManager,
roots: seq[FetchRecord],
responseHandler: FetchAncestorsResponseHandler) =
# TODO: we could have some fancier logic here:
#
# * Keeps track of what was requested
# (this would give a little bit of time for the asked peer to respond)
#
# * Keep track of the average latency of each peer
# (we can give priority to peers with better latency)
#
const ParallelRequests = 2
for i in 0 ..< ParallelRequests:
traceAsyncErrors fetchAncestorBlocksFromNetwork(requestManager.network,
roots.sample(),
responseHandler)
elif networkBackend == libp2pDaemon:
proc fetchAncestorBlocks*(requestManager: RequestManager,
roots: seq[FetchRecord], roots: seq[FetchRecord],
responseHandler: FetchAncestorsResponseHandler) = responseHandler: FetchAncestorsResponseHandler) =
# TODO: we could have some fancier logic here: # TODO: we could have some fancier logic here:
# #
# * Keeps track of what was requested # * Keeps track of what was requested
# (this would give a little bit of time for the asked peer to respond) # (this would give a little bit of time for the asked peer to respond)
# #
# * Keep track of the average latency of each peer # * Keep track of the average latency of each peer
# (we can give priority to peers with better latency) # (we can give priority to peers with better latency)
# #
const ParallelRequests = 2 const ParallelRequests = 2
for i in 0 ..< ParallelRequests:
traceAsyncErrors fetchAncestorBlocksFromNetwork(requestManager.network,
roots.sample(),
responseHandler)
for peer in requestManager.network.randomPeers(ParallelRequests, BeaconSync):
traceAsyncErrors peer.fetchAncestorBlocksFromPeer(roots.sample(), responseHandler)

View File

@ -12,7 +12,7 @@ import
./crypto, ./datatypes, ./digest, ./helpers, ./validator, ./crypto, ./datatypes, ./digest, ./helpers, ./validator,
../../nbench/bench_lab ../../nbench/bench_lab
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#is_valid_merkle_branch # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#is_valid_merkle_branch
func is_valid_merkle_branch*(leaf: Eth2Digest, branch: openarray[Eth2Digest], depth: uint64, index: uint64, root: Eth2Digest): bool {.nbench.}= func is_valid_merkle_branch*(leaf: Eth2Digest, branch: openarray[Eth2Digest], depth: uint64, index: uint64, root: Eth2Digest): bool {.nbench.}=
## Check if ``leaf`` at ``index`` verifies against the Merkle ``root`` and ## Check if ``leaf`` at ``index`` verifies against the Merkle ``root`` and
## ``branch``. ## ``branch``.
@ -30,13 +30,13 @@ func is_valid_merkle_branch*(leaf: Eth2Digest, branch: openarray[Eth2Digest], de
value = eth2hash(buf) value = eth2hash(buf)
value == root value == root
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#increase_balance # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#increase_balance
func increase_balance*( func increase_balance*(
state: var BeaconState, index: ValidatorIndex, delta: Gwei) = state: var BeaconState, index: ValidatorIndex, delta: Gwei) =
# Increase the validator balance at index ``index`` by ``delta``. # Increase the validator balance at index ``index`` by ``delta``.
state.balances[index] += delta state.balances[index] += delta
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#decrease_balance # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#decrease_balance
func decrease_balance*( func decrease_balance*(
state: var BeaconState, index: ValidatorIndex, delta: Gwei) = state: var BeaconState, index: ValidatorIndex, delta: Gwei) =
## Decrease the validator balance at index ``index`` by ``delta``, with ## Decrease the validator balance at index ``index`` by ``delta``, with
@ -47,7 +47,7 @@ func decrease_balance*(
else: else:
state.balances[index] - delta state.balances[index] - delta
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.4/specs/core/0_beacon-chain.md#deposits # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#deposits
proc process_deposit*( proc process_deposit*(
state: var BeaconState, deposit: Deposit, flags: UpdateFlags = {}): bool {.nbench.}= state: var BeaconState, deposit: Deposit, flags: UpdateFlags = {}): bool {.nbench.}=
# Process an Eth1 deposit, registering a validator or increasing its balance. # Process an Eth1 deposit, registering a validator or increasing its balance.
@ -56,7 +56,7 @@ proc process_deposit*(
if skipMerkleValidation notin flags and not is_valid_merkle_branch( if skipMerkleValidation notin flags and not is_valid_merkle_branch(
hash_tree_root(deposit.data), hash_tree_root(deposit.data),
deposit.proof, deposit.proof,
DEPOSIT_CONTRACT_TREE_DEPTH + 1, DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the `List` length mix-in
state.eth1_deposit_index, state.eth1_deposit_index,
state.eth1_data.deposit_root, state.eth1_data.deposit_root,
): ):
@ -72,8 +72,17 @@ proc process_deposit*(
index = validator_pubkeys.find(pubkey) index = validator_pubkeys.find(pubkey)
if index == -1: if index == -1:
# Verify the deposit signature (proof of possession) # Verify the deposit signature (proof of possession) which is not checked
let domain = compute_domain(DOMAIN_DEPOSIT) # by the deposit contract
# Fork-agnostic domain since deposits are valid across forks
#
# TODO zcli/zrnt does use the GENESIS_FORK_VERSION which can
# vary between minimal/mainnet, though, despite the comment,
# which is copied verbatim from the eth2 beacon chain spec.
# https://github.com/protolambda/zrnt/blob/v0.11.0/eth2/phase0/kickstart.go#L58
let domain = compute_domain(DOMAIN_DEPOSIT, GENESIS_FORK_VERSION)
let signing_root = compute_signing_root(deposit.getDepositMessage, domain) let signing_root = compute_signing_root(deposit.getDepositMessage, domain)
if skipBLSValidation notin flags and not bls_verify( if skipBLSValidation notin flags and not bls_verify(
pubkey, signing_root.data, pubkey, signing_root.data,
@ -98,13 +107,13 @@ proc process_deposit*(
true true
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#compute_activation_exit_epoch # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_activation_exit_epoch
func compute_activation_exit_epoch(epoch: Epoch): Epoch = func compute_activation_exit_epoch(epoch: Epoch): Epoch =
## Return the epoch during which validator activations and exits initiated in ## Return the epoch during which validator activations and exits initiated in
## ``epoch`` take effect. ## ``epoch`` take effect.
epoch + 1 + MAX_SEED_LOOKAHEAD epoch + 1 + MAX_SEED_LOOKAHEAD
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#get_validator_churn_limit # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_validator_churn_limit
func get_validator_churn_limit(state: BeaconState): uint64 = func get_validator_churn_limit(state: BeaconState): uint64 =
# Return the validator churn limit for the current epoch. # Return the validator churn limit for the current epoch.
let active_validator_indices = let active_validator_indices =
@ -112,7 +121,7 @@ func get_validator_churn_limit(state: BeaconState): uint64 =
max(MIN_PER_EPOCH_CHURN_LIMIT, max(MIN_PER_EPOCH_CHURN_LIMIT,
len(active_validator_indices) div CHURN_LIMIT_QUOTIENT).uint64 len(active_validator_indices) div CHURN_LIMIT_QUOTIENT).uint64
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#initiate_validator_exit # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#initiate_validator_exit
func initiate_validator_exit*(state: var BeaconState, func initiate_validator_exit*(state: var BeaconState,
index: ValidatorIndex) = index: ValidatorIndex) =
# Initiate the exit of the validator with index ``index``. # Initiate the exit of the validator with index ``index``.
@ -184,8 +193,8 @@ proc slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex,
increase_balance( increase_balance(
state, whistleblower_index, whistleblowing_reward - proposer_reward) state, whistleblower_index, whistleblowing_reward - proposer_reward)
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#genesis # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#genesis
func initialize_beacon_state_from_eth1*( proc initialize_beacon_state_from_eth1*(
eth1_block_hash: Eth2Digest, eth1_block_hash: Eth2Digest,
eth1_timestamp: uint64, eth1_timestamp: uint64,
deposits: openArray[Deposit], deposits: openArray[Deposit],
@ -208,6 +217,10 @@ func initialize_beacon_state_from_eth1*(
const SECONDS_PER_DAY = uint64(60*60*24) const SECONDS_PER_DAY = uint64(60*60*24)
var state = BeaconState( var state = BeaconState(
fork: Fork(
previous_version: GENESIS_FORK_VERSION,
current_version: GENESIS_FORK_VERSION,
epoch: GENESIS_EPOCH),
genesis_time: genesis_time:
eth1_timestamp + 2'u64 * SECONDS_PER_DAY - eth1_timestamp + 2'u64 * SECONDS_PER_DAY -
(eth1_timestamp mod SECONDS_PER_DAY), (eth1_timestamp mod SECONDS_PER_DAY),
@ -248,7 +261,8 @@ func initialize_beacon_state_from_eth1*(
validator.activation_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH
# Set genesis validators root for domain separation and chain versioning # Set genesis validators root for domain separation and chain versioning
state.genesis_validators_root = hash_tree_root(state.validators) state.genesis_validators_root =
hash_tree_root(sszList(state.validators, VALIDATOR_REGISTRY_LIMIT))
state state
@ -272,7 +286,7 @@ func get_initial_beacon_block*(state: BeaconState): SignedBeaconBlock =
# parent_root, randao_reveal, eth1_data, signature, and body automatically # parent_root, randao_reveal, eth1_data, signature, and body automatically
# initialized to default values. # initialized to default values.
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#get_block_root_at_slot # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_block_root_at_slot
func get_block_root_at_slot*(state: BeaconState, func get_block_root_at_slot*(state: BeaconState,
slot: Slot): Eth2Digest = slot: Slot): Eth2Digest =
# Return the block root at a recent ``slot``. # Return the block root at a recent ``slot``.
@ -281,29 +295,29 @@ func get_block_root_at_slot*(state: BeaconState,
doAssert slot < state.slot doAssert slot < state.slot
state.block_roots[slot mod SLOTS_PER_HISTORICAL_ROOT] state.block_roots[slot mod SLOTS_PER_HISTORICAL_ROOT]
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#get_block_root # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_block_root
func get_block_root*(state: BeaconState, epoch: Epoch): Eth2Digest = func get_block_root*(state: BeaconState, epoch: Epoch): Eth2Digest =
# Return the block root at the start of a recent ``epoch``. # Return the block root at the start of a recent ``epoch``.
get_block_root_at_slot(state, compute_start_slot_at_epoch(epoch)) get_block_root_at_slot(state, compute_start_slot_at_epoch(epoch))
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#get_total_balance # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_total_balance
func get_total_balance*(state: BeaconState, validators: auto): Gwei = func get_total_balance*(state: BeaconState, validators: auto): Gwei =
## Return the combined effective balance of the ``indices``. (1 Gwei minimum ## Return the combined effective balance of the ``indices``.
## to avoid divisions by zero.) ## ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
## Math safe up to ~10B ETH, afterwhich this overflows uint64. ## Math safe up to ~10B ETH, afterwhich this overflows uint64.
max(1'u64, max(EFFECTIVE_BALANCE_INCREMENT,
foldl(validators, a + state.validators[b].effective_balance, 0'u64) foldl(validators, a + state.validators[b].effective_balance, 0'u64)
) )
# XXX: Move to state_transition_epoch.nim? # XXX: Move to state_transition_epoch.nim?
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#is_eligible_for_activation_queue # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#is_eligible_for_activation_queue
func is_eligible_for_activation_queue(validator: Validator): bool = func is_eligible_for_activation_queue(validator: Validator): bool =
# Check if ``validator`` is eligible to be placed into the activation queue. # Check if ``validator`` is eligible to be placed into the activation queue.
validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and
validator.effective_balance == MAX_EFFECTIVE_BALANCE validator.effective_balance == MAX_EFFECTIVE_BALANCE
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#is_eligible_for_activation # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#is_eligible_for_activation
func is_eligible_for_activation(state: BeaconState, validator: Validator): func is_eligible_for_activation(state: BeaconState, validator: Validator):
bool = bool =
# Check if ``validator`` is eligible for activation. # Check if ``validator`` is eligible for activation.
@ -365,7 +379,7 @@ proc process_registry_updates*(state: var BeaconState) {.nbench.}=
validator.activation_epoch = validator.activation_epoch =
compute_activation_exit_epoch(get_current_epoch(state)) compute_activation_exit_epoch(get_current_epoch(state))
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.4/specs/core/0_beacon-chain.md#is_valid_indexed_attestation # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#is_valid_indexed_attestation
proc is_valid_indexed_attestation*( proc is_valid_indexed_attestation*(
state: BeaconState, indexed_attestation: IndexedAttestation, state: BeaconState, indexed_attestation: IndexedAttestation,
flags: UpdateFlags): bool = flags: UpdateFlags): bool =
@ -381,7 +395,6 @@ proc is_valid_indexed_attestation*(
return false return false
# Verify indices are sorted and unique # Verify indices are sorted and unique
# TODO but why? this is a local artifact
if indices != sorted(indices, system.cmp): if indices != sorted(indices, system.cmp):
notice "indexed attestation: indices not sorted" notice "indexed attestation: indices not sorted"
return false return false
@ -399,7 +412,7 @@ proc is_valid_indexed_attestation*(
true true
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#get_attesting_indices # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_attesting_indices
func get_attesting_indices*(state: BeaconState, func get_attesting_indices*(state: BeaconState,
data: AttestationData, data: AttestationData,
bits: CommitteeValidatorsBits, bits: CommitteeValidatorsBits,
@ -413,7 +426,7 @@ func get_attesting_indices*(state: BeaconState,
result.incl index result.incl index
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#get_indexed_attestation # https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#get_indexed_attestation
func get_indexed_attestation(state: BeaconState, attestation: Attestation, func get_indexed_attestation*(state: BeaconState, attestation: Attestation,
stateCache: var StateCache): IndexedAttestation = stateCache: var StateCache): IndexedAttestation =
# Return the indexed attestation corresponding to ``attestation``. # Return the indexed attestation corresponding to ``attestation``.
let let
@ -421,14 +434,6 @@ func get_indexed_attestation(state: BeaconState, attestation: Attestation,
get_attesting_indices( get_attesting_indices(
state, attestation.data, attestation.aggregation_bits, stateCache) state, attestation.data, attestation.aggregation_bits, stateCache)
## TODO No fundamental reason to do so many type conversions
## verify_indexed_attestation checks for sortedness but it's
## entirely a local artifact, seemingly; networking uses the
## Attestation data structure, which can't be unsorted. That
## the conversion here otherwise needs sorting is due to the
## usage of HashSet -- order only matters in one place (that
## 0.6.3 highlights and explicates) except in that the spec,
## for no obvious reason, verifies it.
IndexedAttestation( IndexedAttestation(
attesting_indices: attesting_indices:
sorted(mapIt(attesting_indices.toSeq, it.uint64), system.cmp), sorted(mapIt(attesting_indices.toSeq, it.uint64), system.cmp),
@ -436,7 +441,7 @@ func get_indexed_attestation(state: BeaconState, attestation: Attestation,
signature: attestation.signature signature: attestation.signature
) )
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#attestations # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#attestations
proc check_attestation*( proc check_attestation*(
state: BeaconState, attestation: Attestation, flags: UpdateFlags, state: BeaconState, attestation: Attestation, flags: UpdateFlags,
stateCache: var StateCache): bool = stateCache: var StateCache): bool =
@ -566,7 +571,7 @@ func makeAttestationData*(
doAssert slot.compute_epoch_at_slot == current_epoch doAssert slot.compute_epoch_at_slot == current_epoch
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#attestation-data # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#attestation-data
AttestationData( AttestationData(
slot: slot, slot: slot,
index: committee_index, index: committee_index,

View File

@ -104,7 +104,7 @@ func pubKey*(privkey: ValidatorPrivKey): ValidatorPubKey =
else: else:
privkey.getKey privkey.getKey
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#bls-signatures # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#bls-signatures
func aggregate*[T](values: openarray[ValidatorSig]): ValidatorSig = func aggregate*[T](values: openarray[ValidatorSig]): ValidatorSig =
## Aggregate arrays of sequences of Validator Signatures ## Aggregate arrays of sequences of Validator Signatures
## This assumes that they are real signatures ## This assumes that they are real signatures
@ -260,6 +260,10 @@ func initFromBytes*(val: var ValidatorPrivKey, bytes: openarray[byte]) {.inline.
func fromBytes[T](R: type BlsValue[T], bytes: openarray[byte]): R {.inline.}= func fromBytes[T](R: type BlsValue[T], bytes: openarray[byte]): R {.inline.}=
result.initFromBytes(bytes) result.initFromBytes(bytes)
func fromBytes[T](R: var BlsValue[T], bytes: openarray[byte]) {.inline.}=
# This version is only to support tests/test_interop.nim
R.initFromBytes(bytes)
func fromHex*[T](R: var BlsValue[T], hexStr: string) {.inline.} = func fromHex*[T](R: var BlsValue[T], hexStr: string) {.inline.} =
## Initialize a BLSValue from its hex representation ## Initialize a BLSValue from its hex representation
R.fromBytes(hexStr.hexToSeqByte()) R.fromBytes(hexStr.hexToSeqByte())

View File

@ -57,7 +57,7 @@ else:
loadCustomPreset const_preset loadCustomPreset const_preset
const const
SPEC_VERSION* = "0.11.0" ## \ SPEC_VERSION* = "0.11.1" ## \
## Spec version we're aiming to be compatible with, right now ## Spec version we're aiming to be compatible with, right now
GENESIS_EPOCH* = (GENESIS_SLOT.uint64 div SLOTS_PER_EPOCH).Epoch ##\ GENESIS_EPOCH* = (GENESIS_SLOT.uint64 div SLOTS_PER_EPOCH).Epoch ##\
@ -74,6 +74,9 @@ const
# TODO: This needs revisiting. # TODO: This needs revisiting.
# Why was the validator WITHDRAWAL_PERIOD altered in the spec? # Why was the validator WITHDRAWAL_PERIOD altered in the spec?
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/p2p-interface.md#configuration
ATTESTATION_PROPAGATION_SLOT_RANGE* = 32
template maxSize*(n: int) {.pragma.} template maxSize*(n: int) {.pragma.}
type type
@ -81,7 +84,7 @@ type
# Domains # Domains
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#domain-types # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#domain-types
DomainType* = enum DomainType* = enum
DOMAIN_BEACON_PROPOSER = 0 DOMAIN_BEACON_PROPOSER = 0
DOMAIN_BEACON_ATTESTER = 1 DOMAIN_BEACON_ATTESTER = 1
@ -99,7 +102,7 @@ type
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase1/custody-game.md#signature-domain-types # https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase1/custody-game.md#signature-domain-types
DOMAIN_CUSTODY_BIT_SLASHING = 0x83 DOMAIN_CUSTODY_BIT_SLASHING = 0x83
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#custom-types # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#custom-types
Domain* = array[32, byte] Domain* = array[32, byte]
# https://github.com/nim-lang/Nim/issues/574 and be consistent across # https://github.com/nim-lang/Nim/issues/574 and be consistent across
@ -114,17 +117,17 @@ type
BitList*[maxLen: static int] = distinct BitSeq BitList*[maxLen: static int] = distinct BitSeq
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#proposerslashing # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#proposerslashing
ProposerSlashing* = object ProposerSlashing* = object
signed_header_1*: SignedBeaconBlockHeader signed_header_1*: SignedBeaconBlockHeader
signed_header_2*: SignedBeaconBlockHeader signed_header_2*: SignedBeaconBlockHeader
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#attesterslashing # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#attesterslashing
AttesterSlashing* = object AttesterSlashing* = object
attestation_1*: IndexedAttestation attestation_1*: IndexedAttestation
attestation_2*: IndexedAttestation attestation_2*: IndexedAttestation
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#indexedattestation # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#indexedattestation
IndexedAttestation* = object IndexedAttestation* = object
# TODO ValidatorIndex, but that doesn't serialize properly # TODO ValidatorIndex, but that doesn't serialize properly
attesting_indices*: List[uint64, MAX_VALIDATORS_PER_COMMITTEE] attesting_indices*: List[uint64, MAX_VALIDATORS_PER_COMMITTEE]
@ -133,24 +136,24 @@ type
CommitteeValidatorsBits* = BitList[MAX_VALIDATORS_PER_COMMITTEE] CommitteeValidatorsBits* = BitList[MAX_VALIDATORS_PER_COMMITTEE]
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#attestation # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#attestation
Attestation* = object Attestation* = object
aggregation_bits*: CommitteeValidatorsBits aggregation_bits*: CommitteeValidatorsBits
data*: AttestationData data*: AttestationData
signature*: ValidatorSig signature*: ValidatorSig
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#forkdata # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#forkdata
ForkData* = object ForkData* = object
# TODO: Spec introduced an alias for Version = array[4, byte] # TODO: Spec introduced an alias for Version = array[4, byte]
current_version*: array[4, byte] current_version*: array[4, byte]
genesis_validators_root*: Eth2Digest genesis_validators_root*: Eth2Digest
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#checkpoint # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#checkpoint
Checkpoint* = object Checkpoint* = object
epoch*: Epoch epoch*: Epoch
root*: Eth2Digest root*: Eth2Digest
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#AttestationData # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#AttestationData
AttestationData* = object AttestationData* = object
slot*: Slot slot*: Slot
index*: uint64 index*: uint64
@ -162,34 +165,34 @@ type
source*: Checkpoint source*: Checkpoint
target*: Checkpoint target*: Checkpoint
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#deposit # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#deposit
Deposit* = object Deposit* = object
proof*: array[DEPOSIT_CONTRACT_TREE_DEPTH + 1, Eth2Digest] ##\ proof*: array[DEPOSIT_CONTRACT_TREE_DEPTH + 1, Eth2Digest] ##\
## Merkle path to deposit root ## Merkle path to deposit root
data*: DepositData data*: DepositData
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#depositmessage # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#depositmessage
DepositMessage* = object DepositMessage* = object
pubkey*: ValidatorPubKey pubkey*: ValidatorPubKey
withdrawal_credentials*: Eth2Digest withdrawal_credentials*: Eth2Digest
amount*: Gwei amount*: Gwei
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#depositdata # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#depositdata
DepositData* = object DepositData* = object
pubkey*: ValidatorPubKey pubkey*: ValidatorPubKey
withdrawal_credentials*: Eth2Digest withdrawal_credentials*: Eth2Digest
amount*: uint64 amount*: uint64
signature*: ValidatorSig # Signing over DepositMessage signature*: ValidatorSig # Signing over DepositMessage
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#voluntaryexit # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#voluntaryexit
VoluntaryExit* = object VoluntaryExit* = object
epoch*: Epoch ##\ epoch*: Epoch ##\
## Earliest epoch when voluntary exit can be processed ## Earliest epoch when voluntary exit can be processed
validator_index*: uint64 validator_index*: uint64
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#beaconblock # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#beaconblock
BeaconBlock* = object BeaconBlock* = object
## For each slot, a proposer is chosen from the validator pool to propose ## For each slot, a proposer is chosen from the validator pool to propose
## a new block. Once the block as been proposed, it is transmitted to ## a new block. Once the block as been proposed, it is transmitted to
@ -208,7 +211,7 @@ type
body*: BeaconBlockBody body*: BeaconBlockBody
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#beaconblockheader # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#beaconblockheader
BeaconBlockHeader* = object BeaconBlockHeader* = object
slot*: Slot slot*: Slot
proposer_index*: uint64 proposer_index*: uint64
@ -216,7 +219,7 @@ type
state_root*: Eth2Digest state_root*: Eth2Digest
body_root*: Eth2Digest body_root*: Eth2Digest
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#beaconblockbody # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#beaconblockbody
BeaconBlockBody* = object BeaconBlockBody* = object
randao_reveal*: ValidatorSig randao_reveal*: ValidatorSig
eth1_data*: Eth1Data eth1_data*: Eth1Data
@ -229,7 +232,7 @@ type
deposits*: List[Deposit, MAX_DEPOSITS] deposits*: List[Deposit, MAX_DEPOSITS]
voluntary_exits*: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] voluntary_exits*: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#beaconstate # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#beaconstate
BeaconState* = object BeaconState* = object
# Versioning # Versioning
genesis_time*: uint64 genesis_time*: uint64
@ -254,8 +257,7 @@ type
eth1_deposit_index*: uint64 eth1_deposit_index*: uint64
# Registry # Registry
# TODO List[] won't construct due to VALIDATOR_REGISTRY_LIMIT > high(int) validators*: List[Validator, VALIDATOR_REGISTRY_LIMIT]
validators*: seq[Validator]
balances*: seq[uint64] balances*: seq[uint64]
# Randomness # Randomness
@ -283,7 +285,7 @@ type
current_justified_checkpoint*: Checkpoint current_justified_checkpoint*: Checkpoint
finalized_checkpoint*: Checkpoint finalized_checkpoint*: Checkpoint
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#validator # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#validator
Validator* = object Validator* = object
pubkey*: ValidatorPubKey pubkey*: ValidatorPubKey
@ -305,7 +307,7 @@ type
withdrawable_epoch*: Epoch ##\ withdrawable_epoch*: Epoch ##\
## When validator can withdraw or transfer funds ## When validator can withdraw or transfer funds
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#pendingattestation # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#pendingattestation
PendingAttestation* = object PendingAttestation* = object
aggregation_bits*: CommitteeValidatorsBits aggregation_bits*: CommitteeValidatorsBits
data*: AttestationData data*: AttestationData
@ -315,12 +317,12 @@ type
proposer_index*: uint64 proposer_index*: uint64
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#historicalbatch # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#historicalbatch
HistoricalBatch* = object HistoricalBatch* = object
block_roots* : array[SLOTS_PER_HISTORICAL_ROOT, Eth2Digest] block_roots* : array[SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
state_roots* : array[SLOTS_PER_HISTORICAL_ROOT, Eth2Digest] state_roots* : array[SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#fork # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#fork
Fork* = object Fork* = object
# TODO: Spec introduced an alias for Version = array[4, byte] # TODO: Spec introduced an alias for Version = array[4, byte]
# and a default parameter to compute_domain # and a default parameter to compute_domain
@ -330,33 +332,33 @@ type
epoch*: Epoch ##\ epoch*: Epoch ##\
## Epoch of latest fork ## Epoch of latest fork
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#eth1data # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#eth1data
Eth1Data* = object Eth1Data* = object
deposit_root*: Eth2Digest deposit_root*: Eth2Digest
deposit_count*: uint64 deposit_count*: uint64
block_hash*: Eth2Digest block_hash*: Eth2Digest
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#signingroot # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#signingroot
SigningRoot* = object SigningRoot* = object
object_root*: Eth2Digest object_root*: Eth2Digest
domain*: Domain domain*: Domain
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#signedvoluntaryexit # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#signedvoluntaryexit
SignedVoluntaryExit* = object SignedVoluntaryExit* = object
message*: VoluntaryExit message*: VoluntaryExit
signature*: ValidatorSig signature*: ValidatorSig
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#signedbeaconblock # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#signedbeaconblock
SignedBeaconBlock* = object SignedBeaconBlock* = object
message*: BeaconBlock message*: BeaconBlock
signature*: ValidatorSig signature*: ValidatorSig
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#signedbeaconblockheader # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#signedbeaconblockheader
SignedBeaconBlockHeader* = object SignedBeaconBlockHeader* = object
message*: BeaconBlockHeader message*: BeaconBlockHeader
signature*: ValidatorSig signature*: ValidatorSig
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#aggregateandproof # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#aggregateandproof
AggregateAndProof* = object AggregateAndProof* = object
aggregator_index*: uint64 aggregator_index*: uint64
aggregate*: Attestation aggregate*: Attestation
@ -367,7 +369,7 @@ type
message*: AggregateAndProof message*: AggregateAndProof
signature*: ValidatorSig signature*: ValidatorSig
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#eth1block # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#eth1block
Eth1Block* = object Eth1Block* = object
timestamp*: uint64 timestamp*: uint64
# All other eth1 block fields # All other eth1 block fields

View File

@ -15,7 +15,7 @@ import
# Internal # Internal
./datatypes, ./digest, ../ssz ./datatypes, ./digest, ../ssz
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#integer_squareroot # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#integer_squareroot
func integer_squareroot*(n: SomeInteger): SomeInteger = func integer_squareroot*(n: SomeInteger): SomeInteger =
# Return the largest integer ``x`` such that ``x**2 <= n``. # Return the largest integer ``x`` such that ``x**2 <= n``.
doAssert n >= 0'u64 doAssert n >= 0'u64
@ -28,7 +28,7 @@ func integer_squareroot*(n: SomeInteger): SomeInteger =
y = (x + n div x) div 2 y = (x + n div x) div 2
x x
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#compute_epoch_at_slot # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_epoch_at_slot
func compute_epoch_at_slot*(slot: Slot|uint64): Epoch = func compute_epoch_at_slot*(slot: Slot|uint64): Epoch =
# Return the epoch number at ``slot``. # Return the epoch number at ``slot``.
(slot div SLOTS_PER_EPOCH).Epoch (slot div SLOTS_PER_EPOCH).Epoch
@ -36,17 +36,17 @@ func compute_epoch_at_slot*(slot: Slot|uint64): Epoch =
template epoch*(slot: Slot): Epoch = template epoch*(slot: Slot): Epoch =
compute_epoch_at_slot(slot) compute_epoch_at_slot(slot)
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#compute_start_slot_at_epoch # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_start_slot_at_epoch
func compute_start_slot_at_epoch*(epoch: Epoch): Slot = func compute_start_slot_at_epoch*(epoch: Epoch): Slot =
# Return the start slot of ``epoch``. # Return the start slot of ``epoch``.
(epoch * SLOTS_PER_EPOCH).Slot (epoch * SLOTS_PER_EPOCH).Slot
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#is_active_validator # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#is_active_validator
func is_active_validator*(validator: Validator, epoch: Epoch): bool = func is_active_validator*(validator: Validator, epoch: Epoch): bool =
### Check if ``validator`` is active ### Check if ``validator`` is active
validator.activation_epoch <= epoch and epoch < validator.exit_epoch validator.activation_epoch <= epoch and epoch < validator.exit_epoch
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#get_active_validator_indices # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_active_validator_indices
func get_active_validator_indices*(state: BeaconState, epoch: Epoch): func get_active_validator_indices*(state: BeaconState, epoch: Epoch):
seq[ValidatorIndex] = seq[ValidatorIndex] =
# Return the sequence of active validator indices at ``epoch``. # Return the sequence of active validator indices at ``epoch``.
@ -54,7 +54,7 @@ func get_active_validator_indices*(state: BeaconState, epoch: Epoch):
if is_active_validator(val, epoch): if is_active_validator(val, epoch):
result.add idx.ValidatorIndex result.add idx.ValidatorIndex
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#get_committee_count_at_slot # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_committee_count_at_slot
func get_committee_count_at_slot*(state: BeaconState, slot: Slot): uint64 = func get_committee_count_at_slot*(state: BeaconState, slot: Slot): uint64 =
# Return the number of committees at ``slot``. # Return the number of committees at ``slot``.
let epoch = compute_epoch_at_slot(slot) let epoch = compute_epoch_at_slot(slot)
@ -67,13 +67,13 @@ func get_committee_count_at_slot*(state: BeaconState, slot: Slot): uint64 =
# Otherwise, get_beacon_committee(...) cannot access some committees. # Otherwise, get_beacon_committee(...) cannot access some committees.
doAssert (SLOTS_PER_EPOCH * MAX_COMMITTEES_PER_SLOT).uint64 >= result doAssert (SLOTS_PER_EPOCH * MAX_COMMITTEES_PER_SLOT).uint64 >= result
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#get_current_epoch # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_current_epoch
func get_current_epoch*(state: BeaconState): Epoch = func get_current_epoch*(state: BeaconState): Epoch =
# Return the current epoch. # Return the current epoch.
doAssert state.slot >= GENESIS_SLOT, $state.slot doAssert state.slot >= GENESIS_SLOT, $state.slot
compute_epoch_at_slot(state.slot) compute_epoch_at_slot(state.slot)
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#get_randao_mix # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_randao_mix
func get_randao_mix*(state: BeaconState, func get_randao_mix*(state: BeaconState,
epoch: Epoch): Eth2Digest = epoch: Epoch): Eth2Digest =
## Returns the randao mix at a recent ``epoch``. ## Returns the randao mix at a recent ``epoch``.
@ -114,7 +114,7 @@ func int_to_bytes4*(x: uint64): array[4, byte] =
result[2] = ((x shr 16) and 0xff).byte result[2] = ((x shr 16) and 0xff).byte
result[3] = ((x shr 24) and 0xff).byte result[3] = ((x shr 24) and 0xff).byte
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#compute_fork_data_root # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_fork_data_root
func compute_fork_data_root(current_version: array[4, byte], func compute_fork_data_root(current_version: array[4, byte],
genesis_validators_root: Eth2Digest): Eth2Digest = genesis_validators_root: Eth2Digest): Eth2Digest =
# Return the 32-byte fork data root for the ``current_version`` and # Return the 32-byte fork data root for the ``current_version`` and
@ -126,7 +126,7 @@ func compute_fork_data_root(current_version: array[4, byte],
genesis_validators_root: genesis_validators_root genesis_validators_root: genesis_validators_root
)) ))
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#compute_fork_digest # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_fork_digest
func compute_fork_digest(current_version: array[4, byte], func compute_fork_digest(current_version: array[4, byte],
genesis_validators_root: Eth2Digest): array[4, byte] = genesis_validators_root: Eth2Digest): array[4, byte] =
# Return the 4-byte fork digest for the ``current_version`` and # Return the 4-byte fork digest for the ``current_version`` and
@ -136,7 +136,7 @@ func compute_fork_digest(current_version: array[4, byte],
result[0..3] = result[0..3] =
compute_fork_data_root(current_version, genesis_validators_root).data[0..3] compute_fork_data_root(current_version, genesis_validators_root).data[0..3]
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#compute_domain # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_domain
func compute_domain*( func compute_domain*(
domain_type: DomainType, domain_type: DomainType,
fork_version: array[4, byte] = [0'u8, 0, 0, 0], fork_version: array[4, byte] = [0'u8, 0, 0, 0],
@ -147,29 +147,25 @@ func compute_domain*(
result[0..3] = int_to_bytes4(domain_type.uint64) result[0..3] = int_to_bytes4(domain_type.uint64)
result[4..31] = fork_data_root.data[0..27] result[4..31] = fork_data_root.data[0..27]
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#get_domain # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_domain
func get_domain*( func get_domain*(
fork: Fork, domain_type: DomainType, epoch: Epoch): Domain = fork: Fork, domain_type: DomainType, epoch: Epoch, genesis_validators_root: Eth2Digest): Domain =
## Return the signature domain (fork version concatenated with domain type) ## Return the signature domain (fork version concatenated with domain type)
## of a message. ## of a message.
let let fork_version =
fork_version = if epoch < fork.epoch:
if epoch < fork.epoch: fork.previous_version
fork.previous_version else:
else: fork.current_version
fork.current_version compute_domain(domain_type, fork_version, genesis_validators_root)
compute_domain(domain_type, fork_version)
func get_domain*( func get_domain*(
state: BeaconState, domain_type: DomainType, message_epoch: Epoch): Domain = state: BeaconState, domain_type: DomainType, epoch: Epoch): Domain =
## Return the signature domain (fork version concatenated with domain type) ## Return the signature domain (fork version concatenated with domain type)
## of a message. ## of a message.
get_domain(state.fork, domain_type, message_epoch) get_domain(state.fork, domain_type, epoch, state. genesis_validators_root)
func get_domain*(state: BeaconState, domain_type: DomainType): Domain = # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_signing_root
get_domain(state, domain_type, get_current_epoch(state))
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#compute_signing_root
func compute_signing_root*(ssz_object: auto, domain: Domain): Eth2Digest = func compute_signing_root*(ssz_object: auto, domain: Domain): Eth2Digest =
# Return the signing root of an object by calculating the root of the # Return the signing root of an object by calculating the root of the
# object-domain tree. # object-domain tree.
@ -179,7 +175,7 @@ func compute_signing_root*(ssz_object: auto, domain: Domain): Eth2Digest =
) )
hash_tree_root(domain_wrapped_object) hash_tree_root(domain_wrapped_object)
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#get_seed # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_seed
func get_seed*(state: BeaconState, epoch: Epoch, domain_type: DomainType): Eth2Digest = func get_seed*(state: BeaconState, epoch: Epoch, domain_type: DomainType): Eth2Digest =
# Return the seed at ``epoch``. # Return the seed at ``epoch``.

View File

@ -13,6 +13,7 @@ const
topicVoluntaryExits* = "/eth2/voluntary_exit/ssz" topicVoluntaryExits* = "/eth2/voluntary_exit/ssz"
topicProposerSlashings* = "/eth2/proposer_slashing/ssz" topicProposerSlashings* = "/eth2/proposer_slashing/ssz"
topicAttesterSlashings* = "/eth2/attester_slashing/ssz" topicAttesterSlashings* = "/eth2/attester_slashing/ssz"
topicAggregateAndProof* = "/eth2/beacon_aggregate_and_proof/ssz"
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/p2p-interface.md#configuration # https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/p2p-interface.md#configuration
ATTESTATION_SUBNET_COUNT* = 64 ATTESTATION_SUBNET_COUNT* = 64

View File

@ -20,7 +20,7 @@ type
const const
# Misc # Misc
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/mainnet.yaml#L6 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/configs/mainnet.yaml#L6
MAX_COMMITTEES_PER_SLOT* {.intdefine.} = 64 MAX_COMMITTEES_PER_SLOT* {.intdefine.} = 64
@ -49,14 +49,14 @@ const
HYSTERESIS_UPWARD_MULTIPLIER* = 5 HYSTERESIS_UPWARD_MULTIPLIER* = 5
# Constants (TODO: not actually configurable) # Constants (TODO: not actually configurable)
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#constants # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#constants
BASE_REWARDS_PER_EPOCH* = 4 BASE_REWARDS_PER_EPOCH* = 4
DEPOSIT_CONTRACT_TREE_DEPTH* = 32 DEPOSIT_CONTRACT_TREE_DEPTH* = 32
# Gwei values # Gwei values
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/mainnet.yaml#L52 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/configs/mainnet.yaml#L58
MIN_DEPOSIT_AMOUNT* = 2'u64^0 * 10'u64^9 ##\ MIN_DEPOSIT_AMOUNT* = 2'u64^0 * 10'u64^9 ##\
## Minimum amounth of ETH that can be deposited in one call - deposits can ## Minimum amounth of ETH that can be deposited in one call - deposits can
@ -73,9 +73,9 @@ const
# Initial values # Initial values
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/mainnet.yaml#L64 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/configs/mainnet.yaml#L70
GENESIS_SLOT* = 0.Slot GENESIS_SLOT* = 0.Slot
GENESIS_FORK_VERSION* = 0x00000000 GENESIS_FORK_VERSION* = [0'u8, 0'u8, 0'u8, 0'u8]
BLS_WITHDRAWAL_PREFIX* = 0'u8 BLS_WITHDRAWAL_PREFIX* = 0'u8
# Time parameters # Time parameters
@ -130,15 +130,22 @@ const
# State vector lengths # State vector lengths
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/mainnet.yaml#L102 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/configs/mainnet.yaml#L105
EPOCHS_PER_HISTORICAL_VECTOR* = 65536
EPOCHS_PER_SLASHINGS_VECTOR* = 8192 EPOCHS_PER_HISTORICAL_VECTOR* = 65536 ##\
HISTORICAL_ROOTS_LIMIT* = 16777216 ## epochs (~0.8 years)
EPOCHS_PER_SLASHINGS_VECTOR* = 8192 ##\
## epochs (~36 days)
HISTORICAL_ROOTS_LIMIT* = 16777216 ##\
## epochs (~26,131 years)
VALIDATOR_REGISTRY_LIMIT* = 1099511627776 VALIDATOR_REGISTRY_LIMIT* = 1099511627776
# Reward and penalty quotients # Reward and penalty quotients
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/mainnet.yaml#L114 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/configs/mainnet.yaml#L117
BASE_REWARD_FACTOR* = 2'u64^6 BASE_REWARD_FACTOR* = 2'u64^6
WHISTLEBLOWER_REWARD_QUOTIENT* = 2'u64^9 WHISTLEBLOWER_REWARD_QUOTIENT* = 2'u64^9
PROPOSER_REWARD_QUOTIENT* = 2'u64^3 PROPOSER_REWARD_QUOTIENT* = 2'u64^3
@ -156,7 +163,7 @@ const
# Fork choice # Fork choice
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/mainnet.yaml#L26 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/configs/mainnet.yaml#L32
SAFE_SLOTS_TO_UPDATE_JUSTIFIED* = 8 # 96 seconds SAFE_SLOTS_TO_UPDATE_JUSTIFIED* = 8 # 96 seconds
# Validators # Validators

View File

@ -20,7 +20,7 @@ type
const const
# Misc # Misc
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/minimal.yaml#L4 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/configs/minimal.yaml#L4
# Changed # Changed
MAX_COMMITTEES_PER_SLOT* = 4 MAX_COMMITTEES_PER_SLOT* = 4
@ -43,7 +43,7 @@ const
# Constants # Constants
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#constants # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#constants
# TODO "The following values are (non-configurable) constants" ... # TODO "The following values are (non-configurable) constants" ...
# Unchanged # Unchanged
BASE_REWARDS_PER_EPOCH* = 4 BASE_REWARDS_PER_EPOCH* = 4
@ -52,7 +52,7 @@ const
# Gwei values # Gwei values
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/minimal.yaml#L52 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/configs/minimal.yaml#L58
# Unchanged # Unchanged
MIN_DEPOSIT_AMOUNT* = 2'u64^0 * 10'u64^9 MIN_DEPOSIT_AMOUNT* = 2'u64^0 * 10'u64^9
@ -66,12 +66,12 @@ const
# Unchanged # Unchanged
GENESIS_SLOT* = 0.Slot GENESIS_SLOT* = 0.Slot
GENESIS_FORK_VERSION* = 0x01000000 GENESIS_FORK_VERSION* = [0'u8, 0'u8, 0'u8, 1'u8]
BLS_WITHDRAWAL_PREFIX* = 0'u8 BLS_WITHDRAWAL_PREFIX* = 0'u8
# Time parameters # Time parameters
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/minimal.yaml#L71 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/configs/minimal.yaml#L77
# Changed: Faster to spin up testnets, but does not give validator # Changed: Faster to spin up testnets, but does not give validator
# reasonable warning time for genesis # reasonable warning time for genesis
MIN_GENESIS_DELAY* = 300 MIN_GENESIS_DELAY* = 300
@ -117,7 +117,7 @@ const
# Reward and penalty quotients # Reward and penalty quotients
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/minimal.yaml#L117 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/configs/minimal.yaml#L117
BASE_REWARD_FACTOR* = 2'u64^6 BASE_REWARD_FACTOR* = 2'u64^6
WHISTLEBLOWER_REWARD_QUOTIENT* = 2'u64^9 WHISTLEBLOWER_REWARD_QUOTIENT* = 2'u64^9
@ -127,7 +127,7 @@ const
# Max operations per block # Max operations per block
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/minimal.yaml#L131 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/configs/minimal.yaml#L131
MAX_PROPOSER_SLASHINGS* = 2^4 MAX_PROPOSER_SLASHINGS* = 2^4
MAX_ATTESTER_SLASHINGS* = 2^0 MAX_ATTESTER_SLASHINGS* = 2^0
@ -144,7 +144,7 @@ const
# Validators # Validators
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/minimal.yaml#L32 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/configs/minimal.yaml#L38
# Changed # Changed
ETH1_FOLLOW_DISTANCE* = 16 # blocks ETH1_FOLLOW_DISTANCE* = 16 # blocks
@ -178,16 +178,6 @@ const
MIN_GASPRICE* = 32 # Gwei MIN_GASPRICE* = 32 # Gwei
GASPRICE_ADJUSTMENT_COEFFICIENT* = 8 GASPRICE_ADJUSTMENT_COEFFICIENT* = 8
# Phase 1 - Sharding
# ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/configs/minimal.yaml#L157
# TODO those are included in minimal.yaml but not mainnet.yaml
# Why?
SHARD_SLOTS_PER_BEACON_SLOT* = 2 # spec: SHARD_SLOTS_PER_EPOCH
EPOCHS_PER_SHARD_PERIOD* = 4
PHASE_1_FORK_EPOCH* = 8
PHASE_1_FORK_SLOT* = 64
# Phase 1 - Custody game # Phase 1 - Custody game
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase1/custody-game.md#constants # https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase1/custody-game.md#constants

View File

@ -44,7 +44,7 @@ declareGauge beacon_previous_live_validators, "Number of active validators that
declareGauge beacon_pending_deposits, "Number of pending deposits (state.eth1_data.deposit_count - state.eth1_deposit_index)" # On block declareGauge beacon_pending_deposits, "Number of pending deposits (state.eth1_data.deposit_count - state.eth1_deposit_index)" # On block
declareGauge beacon_processed_deposits_total, "Number of total deposits included on chain" # On block declareGauge beacon_processed_deposits_total, "Number of total deposits included on chain" # On block
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#block-header # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#block-header
proc process_block_header*( proc process_block_header*(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags, state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
stateCache: var StateCache): bool {.nbench.}= stateCache: var StateCache): bool {.nbench.}=
@ -108,7 +108,8 @@ proc process_randao(
let proposer = addr state.validators[proposer_index.get] let proposer = addr state.validators[proposer_index.get]
# Verify that the provided randao value is valid # Verify that the provided randao value is valid
let signing_root = compute_signing_root(epoch, get_domain(state, DOMAIN_RANDAO)) let signing_root = compute_signing_root(
epoch, get_domain(state, DOMAIN_RANDAO, get_current_epoch(state)))
if skipBLSValidation notin flags: if skipBLSValidation notin flags:
if not blsVerify(proposer.pubkey, signing_root.data, body.randao_reveal): if not blsVerify(proposer.pubkey, signing_root.data, body.randao_reveal):
notice "Randao mismatch", proposer_pubkey = shortLog(proposer.pubkey), notice "Randao mismatch", proposer_pubkey = shortLog(proposer.pubkey),
@ -127,21 +128,21 @@ proc process_randao(
true true
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#eth1-data # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#eth1-data
func process_eth1_data(state: var BeaconState, body: BeaconBlockBody) {.nbench.}= func process_eth1_data(state: var BeaconState, body: BeaconBlockBody) {.nbench.}=
state.eth1_data_votes.add body.eth1_data state.eth1_data_votes.add body.eth1_data
if state.eth1_data_votes.count(body.eth1_data) * 2 > if state.eth1_data_votes.count(body.eth1_data) * 2 >
EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH: EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH:
state.eth1_data = body.eth1_data state.eth1_data = body.eth1_data
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#is_slashable_validator # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#is_slashable_validator
func is_slashable_validator(validator: Validator, epoch: Epoch): bool = func is_slashable_validator(validator: Validator, epoch: Epoch): bool =
# Check if ``validator`` is slashable. # Check if ``validator`` is slashable.
(not validator.slashed) and (not validator.slashed) and
(validator.activation_epoch <= epoch) and (validator.activation_epoch <= epoch) and
(epoch < validator.withdrawable_epoch) (epoch < validator.withdrawable_epoch)
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#proposer-slashings # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#proposer-slashings
proc process_proposer_slashing*( proc process_proposer_slashing*(
state: var BeaconState, proposer_slashing: ProposerSlashing, state: var BeaconState, proposer_slashing: ProposerSlashing,
flags: UpdateFlags, stateCache: var StateCache): bool {.nbench.}= flags: UpdateFlags, stateCache: var StateCache): bool {.nbench.}=
@ -378,7 +379,7 @@ proc processVoluntaryExits(state: var BeaconState, blck: BeaconBlock, flags: Upd
return false return false
return true return true
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#block-processing # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#block-processing
proc process_block*( proc process_block*(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags, state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
stateCache: var StateCache): bool {.nbench.}= stateCache: var StateCache): bool {.nbench.}=
@ -414,7 +415,7 @@ proc process_block*(
# TODO, everything below is now in process_operations # TODO, everything below is now in process_operations
# and implementation is per element instead of the whole seq # and implementation is per element instead of the whole seq
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#operations # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#operations
if not processProposerSlashings(state, blck, flags, stateCache): if not processProposerSlashings(state, blck, flags, stateCache):
debug "[Block processing] Proposer slashing failure", slot = shortLog(state.slot) debug "[Block processing] Proposer slashing failure", slot = shortLog(state.slot)
return false return false
@ -481,42 +482,47 @@ proc makeBeaconBlock*(
some(blck) some(blck)
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/validator.md # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#aggregation-selection
func get_slot_signature*( func get_slot_signature*(
fork: Fork, slot: Slot, privkey: ValidatorPrivKey): ValidatorSig = fork: Fork, genesis_validators_root: Eth2Digest, slot: Slot,
privkey: ValidatorPrivKey): ValidatorSig =
let let
domain = domain = get_domain(fork, DOMAIN_SELECTION_PROOF,
get_domain(fork, DOMAIN_SELECTION_PROOF, compute_epoch_at_slot(slot)) compute_epoch_at_slot(slot), genesis_validators_root)
signing_root = compute_signing_root(slot, domain) signing_root = compute_signing_root(slot, domain)
blsSign(privKey, signing_root.data) blsSign(privKey, signing_root.data)
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/validator.md # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#randao-reveal
func get_epoch_signature*( func get_epoch_signature*(
fork: Fork, slot: Slot, privkey: ValidatorPrivKey): ValidatorSig = fork: Fork, genesis_validators_root: Eth2Digest, slot: Slot,
privkey: ValidatorPrivKey): ValidatorSig =
let let
domain = domain = get_domain(fork, DOMAIN_RANDAO, compute_epoch_at_slot(slot),
get_domain(fork, DOMAIN_RANDAO, compute_epoch_at_slot(slot)) genesis_validators_root)
signing_root = compute_signing_root(compute_epoch_at_slot(slot), domain) signing_root = compute_signing_root(compute_epoch_at_slot(slot), domain)
blsSign(privKey, signing_root.data) blsSign(privKey, signing_root.data)
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/validator.md # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#signature
func get_block_signature*( func get_block_signature*(
fork: Fork, slot: Slot, root: Eth2Digest, privkey: ValidatorPrivKey): ValidatorSig = fork: Fork, genesis_validators_root: Eth2Digest, slot: Slot,
root: Eth2Digest, privkey: ValidatorPrivKey): ValidatorSig =
let let
domain = domain = get_domain(fork, DOMAIN_BEACON_PROPOSER,
get_domain(fork, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(slot)) compute_epoch_at_slot(slot), genesis_validators_root)
signing_root = compute_signing_root(root, domain) signing_root = compute_signing_root(root, domain)
blsSign(privKey, signing_root.data) blsSign(privKey, signing_root.data)
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/validator.md # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#aggregate-signature
func get_attestation_signature*( func get_attestation_signature*(
fork: Fork, attestation: AttestationData, privkey: ValidatorPrivKey): ValidatorSig = fork: Fork, genesis_validators_root: Eth2Digest, attestation: AttestationData,
privkey: ValidatorPrivKey): ValidatorSig =
let let
attestationRoot = hash_tree_root(attestation) attestationRoot = hash_tree_root(attestation)
domain = get_domain(fork, DOMAIN_BEACON_ATTESTER, attestation.target.epoch) domain = get_domain(fork, DOMAIN_BEACON_ATTESTER,
attestation.target.epoch, genesis_validators_root)
signing_root = compute_signing_root(attestationRoot, domain) signing_root = compute_signing_root(attestationRoot, domain)
blsSign(privKey, signing_root.data) blsSign(privKey, signing_root.data)

View File

@ -63,15 +63,17 @@ declareGauge epoch_transition_final_updates, "Epoch transition final updates tim
# Spec # Spec
# -------------------------------------------------------- # --------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#get_total_active_balance # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_total_active_balance
func get_total_active_balance*(state: BeaconState): Gwei = func get_total_active_balance*(state: BeaconState): Gwei =
# Return the combined effective balance of the active validators. # Return the combined effective balance of the active validators.
# Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei
# minimum to avoid divisions by zero.
# TODO it calls get_total_balance with set(g_a_v_i(...)) # TODO it calls get_total_balance with set(g_a_v_i(...))
get_total_balance( get_total_balance(
state, state,
get_active_validator_indices(state, get_current_epoch(state))) get_active_validator_indices(state, get_current_epoch(state)))
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#helper-functions-1 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#helper-functions-1
func get_matching_source_attestations(state: BeaconState, epoch: Epoch): func get_matching_source_attestations(state: BeaconState, epoch: Epoch):
seq[PendingAttestation] = seq[PendingAttestation] =
doAssert epoch in [get_current_epoch(state), get_previous_epoch(state)] doAssert epoch in [get_current_epoch(state), get_previous_epoch(state)]
@ -98,6 +100,10 @@ func get_matching_head_attestations(state: BeaconState, epoch: Epoch):
func get_attesting_balance( func get_attesting_balance(
state: BeaconState, attestations: seq[PendingAttestation], state: BeaconState, attestations: seq[PendingAttestation],
stateCache: var StateCache): Gwei = stateCache: var StateCache): Gwei =
# Return the combined effective balance of the set of unslashed validators
# participating in ``attestations``.
# Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei
# minimum to avoid divisions by zero.
get_total_balance(state, get_unslashed_attesting_indices( get_total_balance(state, get_unslashed_attesting_indices(
state, attestations, stateCache)) state, attestations, stateCache))
@ -144,7 +150,7 @@ proc process_justification_and_finalization*(
## and `get_matching_source_attestations(...)` via ## and `get_matching_source_attestations(...)` via
## https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#helper-functions-1 ## https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#helper-functions-1
## and ## and
## https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#final-updates ## https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#final-updates
## after which the state.previous_epoch_attestations is replaced. ## after which the state.previous_epoch_attestations is replaced.
trace "Non-attesting indices in previous epoch", trace "Non-attesting indices in previous epoch",
missing_all_validators= missing_all_validators=
@ -233,7 +239,7 @@ proc process_justification_and_finalization*(
checkpoint = shortLog(state.finalized_checkpoint), checkpoint = shortLog(state.finalized_checkpoint),
cat = "finalization" cat = "finalization"
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#rewards-and-penalties-1 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#rewards-and-penalties-1
func get_base_reward(state: BeaconState, index: ValidatorIndex, func get_base_reward(state: BeaconState, index: ValidatorIndex,
total_balance: auto): Gwei = total_balance: auto): Gwei =
# Spec function recalculates total_balance every time, which creates an # Spec function recalculates total_balance every time, which creates an
@ -242,7 +248,7 @@ func get_base_reward(state: BeaconState, index: ValidatorIndex,
effective_balance * BASE_REWARD_FACTOR div effective_balance * BASE_REWARD_FACTOR div
integer_squareroot(total_balance) div BASE_REWARDS_PER_EPOCH integer_squareroot(total_balance) div BASE_REWARDS_PER_EPOCH
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#rewards-and-penalties-1 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#rewards-and-penalties-1
func get_attestation_deltas(state: BeaconState, stateCache: var StateCache): func get_attestation_deltas(state: BeaconState, stateCache: var StateCache):
tuple[a: seq[Gwei], b: seq[Gwei]] {.nbench.}= tuple[a: seq[Gwei], b: seq[Gwei]] {.nbench.}=
let let
@ -280,7 +286,7 @@ func get_attestation_deltas(state: BeaconState, stateCache: var StateCache):
const increment = EFFECTIVE_BALANCE_INCREMENT const increment = EFFECTIVE_BALANCE_INCREMENT
let reward_numerator = get_base_reward(state, index, total_balance) * let reward_numerator = get_base_reward(state, index, total_balance) *
(attesting_balance div increment) (attesting_balance div increment)
rewards[index] = reward_numerator div (total_balance div increment) rewards[index] += reward_numerator div (total_balance div increment)
else: else:
penalties[index] += get_base_reward(state, index, total_balance) penalties[index] += get_base_reward(state, index, total_balance)
@ -367,7 +373,7 @@ func process_slashings*(state: var BeaconState) {.nbench.}=
let penalty = penalty_numerator div total_balance * increment let penalty = penalty_numerator div total_balance * increment
decrease_balance(state, index.ValidatorIndex, penalty) decrease_balance(state, index.ValidatorIndex, penalty)
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#final-updates # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#final-updates
func process_final_updates*(state: var BeaconState) {.nbench.}= func process_final_updates*(state: var BeaconState) {.nbench.}=
let let
current_epoch = get_current_epoch(state) current_epoch = get_current_epoch(state)
@ -425,7 +431,7 @@ proc process_epoch*(state: var BeaconState) {.nbench.}=
trace "ran process_justification_and_finalization", trace "ran process_justification_and_finalization",
current_epoch = get_current_epoch(state) current_epoch = get_current_epoch(state)
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#rewards-and-penalties-1 # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#rewards-and-penalties-1
process_rewards_and_penalties(state, per_epoch_cache) process_rewards_and_penalties(state, per_epoch_cache)
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#registry-updates # https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#registry-updates
@ -439,7 +445,7 @@ proc process_epoch*(state: var BeaconState) {.nbench.}=
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#slashings # https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#slashings
process_slashings(state) process_slashings(state)
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#final-updates # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#final-updates
process_final_updates(state) process_final_updates(state)
# Once per epoch metrics # Once per epoch metrics

View File

@ -10,8 +10,8 @@ import
options, nimcrypto, sequtils, math, tables, options, nimcrypto, sequtils, math, tables,
./datatypes, ./digest, ./helpers ./datatypes, ./digest, ./helpers
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#compute_shuffled_index # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_shuffled_index
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#compute_committee # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_committee
func get_shuffled_seq*(seed: Eth2Digest, func get_shuffled_seq*(seed: Eth2Digest,
list_size: uint64, list_size: uint64,
): seq[ValidatorIndex] = ): seq[ValidatorIndex] =
@ -145,7 +145,7 @@ func get_empty_per_epoch_cache*(): StateCache =
initTable[Epoch, seq[ValidatorIndex]]() initTable[Epoch, seq[ValidatorIndex]]()
result.committee_count_cache = initTable[Epoch, uint64]() result.committee_count_cache = initTable[Epoch, uint64]()
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#compute_proposer_index # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_proposer_index
func compute_proposer_index(state: BeaconState, indices: seq[ValidatorIndex], func compute_proposer_index(state: BeaconState, indices: seq[ValidatorIndex],
seed: Eth2Digest, stateCache: var StateCache): Option[ValidatorIndex] = seed: Eth2Digest, stateCache: var StateCache): Option[ValidatorIndex] =
# Return from ``indices`` a random index sampled by effective balance. # Return from ``indices`` a random index sampled by effective balance.
@ -176,7 +176,7 @@ func compute_proposer_index(state: BeaconState, indices: seq[ValidatorIndex],
return some(candidate_index) return some(candidate_index)
i += 1 i += 1
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/beacon-chain.md#get_beacon_proposer_index # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#get_beacon_proposer_index
func get_beacon_proposer_index*(state: BeaconState, stateCache: var StateCache): func get_beacon_proposer_index*(state: BeaconState, stateCache: var StateCache):
Option[ValidatorIndex] = Option[ValidatorIndex] =
# Return the beacon proposer index at the current slot. # Return the beacon proposer index at the current slot.

View File

@ -62,9 +62,9 @@ type
discard discard
when useListType: when useListType:
type List*[T; maxLen: static int] = distinct seq[T] type List*[T; maxLen: static int64] = distinct seq[T]
else: else:
type List*[T; maxLen: static int] = seq[T] type List*[T; maxLen: static int64] = seq[T]
macro unsupported*(T: typed): untyped = macro unsupported*(T: typed): untyped =
# TODO: {.fatal.} breaks compilation even in `compiles()` context, # TODO: {.fatal.} breaks compilation even in `compiles()` context,

View File

@ -30,8 +30,8 @@ type
slots*: seq[PeerSlot[A, B]] slots*: seq[PeerSlot[A, B]]
man: SyncManager[A, B] man: SyncManager[A, B]
GetLocalHeadSlotCallback* = proc(): Slot GetLocalHeadSlotCallback* = proc(): Slot {.gcsafe.}
UpdateLocalBlocksCallback* = proc(list: openarray[SignedBeaconBlock]): bool UpdateLocalBlocksCallback* = proc(list: openarray[SignedBeaconBlock]): bool {.gcsafe.}
SyncManager*[A, B] = ref object SyncManager*[A, B] = ref object
groups*: seq[PeerGroup[A, B]] groups*: seq[PeerGroup[A, B]]
@ -128,7 +128,7 @@ proc updateLastSlot*(sq: SyncQueue, last: Slot) {.inline.} =
sq.lastSlot = last sq.lastSlot = last
proc push*(sq: SyncQueue, sr: SyncRequest, proc push*(sq: SyncQueue, sr: SyncRequest,
data: seq[SignedBeaconBlock]) {.async.} = data: seq[SignedBeaconBlock]) {.async, gcsafe.} =
## Push successfull result to queue ``sq``. ## Push successfull result to queue ``sq``.
while true: while true:
if (sq.queueSize > 0) and (sr.slot >= sq.outSlot + uint64(sq.queueSize)): if (sq.queueSize > 0) and (sr.slot >= sq.outSlot + uint64(sq.queueSize)):
@ -888,7 +888,7 @@ proc updateStatus*[A, B](sman: SyncManager[A, B]) {.async.} =
pending[i].cancel() pending[i].cancel()
raise exc raise exc
proc synchronize*[A, B](sman: SyncManager[A, B]) {.async.} = proc synchronize*[A, B](sman: SyncManager[A, B]) {.async, gcsafe.} =
## TODO: This synchronization procedure is not optimal, we can do it better ## TODO: This synchronization procedure is not optimal, we can do it better
## if spawn N parallel tasks, where N is number of peer groups. ## if spawn N parallel tasks, where N is number of peer groups.
var var

View File

@ -1,12 +1,9 @@
import import
options, tables, sets, macros, options, tables, sets, macros,
chronicles, chronos, stew/ranges/bitranges, chronicles, chronos, stew/ranges/bitranges, libp2p/switch,
spec/[datatypes, crypto, digest, helpers], spec/[datatypes, crypto, digest, helpers],
beacon_node_types, eth2_network, block_pool, ssz beacon_node_types, eth2_network, block_pool, ssz
when networkBackend == libp2p:
import libp2p/switch
logScope: logScope:
topics = "sync" topics = "sync"

View File

@ -14,7 +14,7 @@ type
## which blocks are valid - in particular, blocks are not valid if they ## which blocks are valid - in particular, blocks are not valid if they
## come from the future as seen from the local clock. ## come from the future as seen from the local clock.
## ##
## https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/fork-choice.md#fork-choice ## https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/fork-choice.md#fork-choice
## ##
# TODO replace time in chronos with a proper unit type, then this code can # TODO replace time in chronos with a proper unit type, then this code can
# follow: # follow:

View File

@ -60,7 +60,7 @@ proc sendDeposits*(
var web3 = await newWeb3(depositWeb3Url) var web3 = await newWeb3(depositWeb3Url)
if privateKey.len != 0: if privateKey.len != 0:
web3.privateKey = initPrivateKey(privateKey) web3.privateKey = PrivateKey.fromHex(privateKey).tryGet()
else: else:
let accounts = await web3.provider.eth_accounts() let accounts = await web3.provider.eth_accounts()
if accounts.len == 0: if accounts.len == 0:

View File

@ -25,7 +25,8 @@ func getValidator*(pool: ValidatorPool,
pool.validators.getOrDefault(validatorKey) pool.validators.getOrDefault(validatorKey)
# TODO: Honest validator - https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md # TODO: Honest validator - https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md
proc signBlockProposal*(v: AttachedValidator, fork: Fork, slot: Slot, proc signBlockProposal*(v: AttachedValidator, fork: Fork,
genesis_validators_root: Eth2Digest, slot: Slot,
blockRoot: Eth2Digest): Future[ValidatorSig] {.async.} = blockRoot: Eth2Digest): Future[ValidatorSig] {.async.} =
if v.kind == inProcess: if v.kind == inProcess:
@ -34,30 +35,33 @@ proc signBlockProposal*(v: AttachedValidator, fork: Fork, slot: Slot,
# replaced by something more sensible # replaced by something more sensible
await sleepAsync(chronos.milliseconds(1)) await sleepAsync(chronos.milliseconds(1))
result = get_block_signature(fork, slot, blockRoot, v.privKey) result = get_block_signature(
fork, genesis_validators_root, slot, blockRoot, v.privKey)
else: else:
error "Unimplemented" error "Unimplemented"
quit 1 quit 1
proc signAttestation*(v: AttachedValidator, proc signAttestation*(v: AttachedValidator,
attestation: AttestationData, attestation: AttestationData,
fork: Fork): Future[ValidatorSig] {.async.} = fork: Fork, genesis_validators_root: Eth2Digest):
Future[ValidatorSig] {.async.} =
if v.kind == inProcess: if v.kind == inProcess:
# TODO this is an ugly hack to fake a delay and subsequent async reordering # TODO this is an ugly hack to fake a delay and subsequent async reordering
# for the purpose of testing the external validator delay - to be # for the purpose of testing the external validator delay - to be
# replaced by something more sensible # replaced by something more sensible
await sleepAsync(chronos.milliseconds(1)) await sleepAsync(chronos.milliseconds(1))
result = get_attestation_signature(fork, attestation, v.privKey) result = get_attestation_signature(
fork, genesis_validators_root, attestation, v.privKey)
else: else:
error "Unimplemented" error "Unimplemented"
quit 1 quit 1
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#randao-reveal # https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#randao-reveal
func genRandaoReveal*(k: ValidatorPrivKey, fork: Fork, slot: Slot): func genRandaoReveal*(k: ValidatorPrivKey, fork: Fork,
ValidatorSig = genesis_validators_root: Eth2Digest, slot: Slot): ValidatorSig =
get_epoch_signature(fork, slot, k) get_epoch_signature(fork, genesis_validators_root, slot, k)
func genRandaoReveal*(v: AttachedValidator, fork: Fork, slot: Slot): func genRandaoReveal*(v: AttachedValidator, fork: Fork,
ValidatorSig = genesis_validators_root: Eth2Digest, slot: Slot): ValidatorSig =
genRandaoReveal(v.privKey, fork, slot) genRandaoReveal(v.privKey, fork, genesis_validators_root, slot)

View File

@ -1,15 +1,3 @@
type
NetworkBackendType* = enum
libp2p
libp2pDaemon
const
NETWORK_TYPE {.strdefine.} = "libp2p_daemon"
networkBackend* = when NETWORK_TYPE == "libp2p": libp2p
elif NETWORK_TYPE == "libp2p_daemon": libp2pDaemon
else: {.fatal: "The 'NETWORK_TYPE' should be either 'libp2p', 'libp2p_daemon'" .}
const const
copyrights* = "Copyright (c) 2019 Status Research & Development GmbH" copyrights* = "Copyright (c) 2019 Status Research & Development GmbH"
@ -30,5 +18,5 @@ const
$versionMajor & "." & $versionMinor & "." & $versionBuild $versionMajor & "." & $versionMinor & "." & $versionBuild
fullVersionStr* = fullVersionStr* =
versionAsStr & " (" & gitRevision & ", " & NETWORK_TYPE & ")" versionAsStr & " (" & gitRevision & ")"

View File

@ -38,6 +38,8 @@ else:
# enable metric collection # enable metric collection
--define:metrics --define:metrics
--define:chronicles_line_numbers --define:chronicles_line_numbers
# for heap-usage-by-instance-type metrics and object base-type strings
--define:nimTypeNames
# the default open files limit is too low on macOS (512), breaking the # the default open files limit is too low on macOS (512), breaking the
# "--debugger:native" build. It can be increased with `ulimit -n 1024`. # "--debugger:native" build. It can be increased with `ulimit -n 1024`.
@ -47,8 +49,7 @@ if not defined(macosx):
if not (defined(windows) and defined(i386)) and not defined(disable_libbacktrace): if not (defined(windows) and defined(i386)) and not defined(disable_libbacktrace):
# light-weight stack traces using libbacktrace and libunwind # light-weight stack traces using libbacktrace and libunwind
--define:nimStackTraceOverride --define:nimStackTraceOverride
# "--import:libbacktrace" is added to NIM_PARAMS inside the Makefile, switch("import", "libbacktrace")
# because it doesn't work in here ("Error: undeclared identifier: 'copyMem'", like it kicks in in some other NimScript file)
--define:nimOldCaseObjects # https://github.com/status-im/nim-confutils/issues/9 --define:nimOldCaseObjects # https://github.com/status-im/nim-confutils/issues/9

View File

@ -15,11 +15,11 @@ RUN cd /root \
&& make -j$(nproc) update \ && make -j$(nproc) update \
&& make deps && make deps
# Please note that the commands above have the goal of caching the compilation # Please note that the commands above have the goal of caching the
# of Nim and p2pd, but don't depend on the current git revision. This means # compilation of Nim, but don't depend on the current git revision.
# that the cache can become outdated over time and you'll start seeing Nim # This means that the cache can become outdated over time and you'll
# being compiled on every run. If this happens, just prune your docker cache # start seeing Nim being compiled on every run. If this happens, just
# to get a fresh up-to-date version of Nim and p2pd. # prune your docker cache to get a fresh up-to-date version of Nim.
ARG GIT_REVISION ARG GIT_REVISION
ARG NETWORK_NIM_FLAGS ARG NETWORK_NIM_FLAGS
ARG MARCH_NIM_FLAGS ARG MARCH_NIM_FLAGS
@ -43,13 +43,10 @@ RUN apt-get -qq update \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# "COPY" creates new image layers, so we cram all we can into one command # "COPY" creates new image layers, so we cram all we can into one command
COPY --from=build /root/nim-beacon-chain/docker/run_in_docker.sh /root/nim-beacon-chain/build/beacon_node /root/nim-beacon-chain/vendor/go/bin/p2pd /usr/bin/ COPY --from=build /root/nim-beacon-chain/build/beacon_node /usr/bin/
MAINTAINER Zahary Karadjov <zahary@status.im> MAINTAINER Zahary Karadjov <zahary@status.im>
LABEL description="Nimbus installation that can act as an ETH2 network bootstrap node." LABEL description="Nimbus installation that can act as an ETH2 network bootstrap node."
# TODO: This custom entry script is necessary only because we must clean up ENTRYPOINT ["/usr/bin/beacon_node"]
# temporary files left by previous executions of the Go daeamon.
# We should be able to remove it once we have a native LibP2P impl.
ENTRYPOINT ["/usr/bin/run_in_docker.sh"]

View File

@ -103,7 +103,7 @@ of restart_nodes:
echo &"ssh {n.server} docker pull -q statusteam/nimbus_beacon_node:{conf.network}" echo &"ssh {n.server} docker pull -q statusteam/nimbus_beacon_node:{conf.network}"
# docker-compose will rebuild the container if it detects a newer image. # docker-compose will rebuild the container if it detects a newer image.
# Prints: "Recreating beacon-node-testnet1-1 ... done". # Prints: "Recreating beacon-node-testnet1-1 ... done".
echo &"ssh {n.server} 'cd /docker/{n.container} && docker-compose up -d'" echo &"ssh {n.server} 'cd /docker/{n.container} && docker-compose --compatibility up -d'"
of reset_network: of reset_network:
for n, firstValidator, lastValidator in validatorAssignments(): for n, firstValidator, lastValidator in validatorAssignments():

View File

@ -1,13 +0,0 @@
#!/bin/bash
# TODO This script will no longer be necessary once we switch
# to the native LibP2P
# Deal with previous execution of the deamon leaving behind
# socket files that prevent the deamon from launching again
# inside the container:
killall p2pd
rm -rf /tmp/*
beacon_node "$@"

View File

@ -100,8 +100,6 @@ cli do (skipGoerliKey {.
rmDir dataDir rmDir dataDir
cd rootDir cd rootDir
if testnet == "testnet1":
nimFlags &= " -d:NETWORK_TYPE=libp2p"
exec &"""nim c {nimFlags} -d:"const_preset={preset}" -o:"{beaconNodeBinary}" beacon_chain/beacon_node.nim""" exec &"""nim c {nimFlags} -d:"const_preset={preset}" -o:"{beaconNodeBinary}" beacon_chain/beacon_node.nim"""
mkDir dumpDir mkDir dumpDir

View File

@ -141,10 +141,9 @@ BOOTSTRAP_IP="127.0.0.1"
--genesis-offset=5 # Delay in seconds --genesis-offset=5 # Delay in seconds
cleanup() { cleanup() {
killall beacon_node p2pd &>/dev/null || true killall beacon_node &>/dev/null || true
sleep 2 sleep 2
killall -9 beacon_node p2pd &>/dev/null || true killall -9 beacon_node &>/dev/null || true
rm -f /tmp/nim-p2pd-*.sock || true
} }
cleanup cleanup
@ -152,9 +151,6 @@ PIDS=""
NODES_WITH_VALIDATORS=${NODES_WITH_VALIDATORS:-4} NODES_WITH_VALIDATORS=${NODES_WITH_VALIDATORS:-4}
VALIDATORS_PER_NODE=$(( $RANDOM_VALIDATORS / $NODES_WITH_VALIDATORS )) VALIDATORS_PER_NODE=$(( $RANDOM_VALIDATORS / $NODES_WITH_VALIDATORS ))
# for the p2pd path
source env.sh
for NUM_NODE in $(seq 0 $(( ${NUM_NODES} - 1 ))); do for NUM_NODE in $(seq 0 $(( ${NUM_NODES} - 1 ))); do
if [[ ${NUM_NODE} == 0 ]]; then if [[ ${NUM_NODE} == 0 ]]; then
BOOTSTRAP_ARG="" BOOTSTRAP_ARG=""

View File

@ -16,7 +16,6 @@ add_var () {
} }
add_var CONST_PRESET add_var CONST_PRESET
add_var NETWORK_TYPE
add_var SLOTS_PER_EPOCH add_var SLOTS_PER_EPOCH
add_var MAX_COMMITTEES_PER_SLOT add_var MAX_COMMITTEES_PER_SLOT

View File

@ -1,5 +1,4 @@
CONST_PRESET=minimal CONST_PRESET=minimal
NETWORK_TYPE=libp2p_daemon
QUICKSTART_VALIDATORS=8 QUICKSTART_VALIDATORS=8
RANDOM_VALIDATORS=120 RANDOM_VALIDATORS=120
BOOTSTRAP_PORT=9000 BOOTSTRAP_PORT=9000

View File

@ -1,5 +1,4 @@
CONST_PRESET=minimal CONST_PRESET=minimal
NETWORK_TYPE=libp2p
QUICKSTART_VALIDATORS=8 QUICKSTART_VALIDATORS=8
RANDOM_VALIDATORS=120 RANDOM_VALIDATORS=120
BOOTSTRAP_PORT=9100 BOOTSTRAP_PORT=9100

View File

@ -19,6 +19,7 @@ import # Unit test
./test_discovery_helpers, ./test_discovery_helpers,
./test_helpers, ./test_helpers,
./test_kvstore, ./test_kvstore,
./test_mocking,
./test_kvstore_sqlite3, ./test_kvstore_sqlite3,
./test_ssz, ./test_ssz,
./test_state_transition, ./test_state_transition,
@ -27,12 +28,8 @@ import # Unit test
./test_zero_signature, ./test_zero_signature,
./test_peer_pool, ./test_peer_pool,
./test_sync_manager, ./test_sync_manager,
./test_honest_validator ./test_honest_validator,
./test_interop
# ./test_interop
# TODO: BLS changes in v0.10.1 will generate different interop signatures
# Requires an update of the interop mocked start: https://github.com/ethereum/eth2.0-pm/tree/master/interop/mocked_start
# or of ZRNT / ZCLI to v0.10.1
import # Refactor state transition unit tests import # Refactor state transition unit tests
# TODO re-enable when useful # TODO re-enable when useful

View File

@ -1,16 +1,19 @@
# beacon_chain # beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH # Copyright (c) 2018-2020 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms. # at your option. This file may not be copied, modified, or distributed except according to those terms.
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/tests/core/pyspec/eth2spec/utils/merkle_minimal.py
# Merkle tree helpers # Merkle tree helpers
# --------------------------------------------------------------- # ---------------------------------------------------------------
import import
strutils, macros, bitops,
# Specs # Specs
../../beacon_chain/spec/[datatypes, digest], ../../beacon_chain/spec/[beaconstate, datatypes, digest],
../../beacon_chain/ssz ../../beacon_chain/ssz
func round_step_down*(x: Natural, step: static Natural): int {.inline.} = func round_step_down*(x: Natural, step: static Natural): int {.inline.} =
@ -82,9 +85,7 @@ proc getMerkleProof*[Depth: static int](
else: else:
result[depth] = ZeroHashes[depth] result[depth] = ZeroHashes[depth]
when isMainModule: # Checks proc testMerkleMinimal*(): bool =
import strutils, macros, bitops
proc toDigest[N: static int](x: array[N, byte]): Eth2Digest = proc toDigest[N: static int](x: array[N, byte]): Eth2Digest =
result.data[0 .. N-1] = x result.data[0 .. N-1] = x
@ -122,63 +123,64 @@ when isMainModule: # Checks
# Running tests with hash_tree_root([a, b, c]) # Running tests with hash_tree_root([a, b, c])
# works for depth 2 (3 or 4 leaves) # works for depth 2 (3 or 4 leaves)
when false: macro roundTrips(): untyped =
macro roundTrips(): untyped = result = newStmtList()
result = newStmtList()
# Unsure why sszList ident is undeclared in "quote do" # Unsure why sszList ident is undeclared in "quote do"
let list = bindSym"sszList" let list = bindSym"sszList"
# compile-time unrolled test # compile-time unrolled test
for nleaves in [3, 4, 5, 7, 8, 1 shl 10, 1 shl 32]: for nleaves in [3, 4, 5, 7, 8, 1 shl 10, 1 shl 32]:
let depth = fastLog2(nleaves-1) + 1 let depth = fastLog2(nleaves-1) + 1
result.add quote do: result.add quote do:
block: block:
let tree = merkleTreeFromLeaves([a, b, c], Depth = `depth`) let tree = merkleTreeFromLeaves([a, b, c], Depth = `depth`)
echo "Tree: ", tree #echo "Tree: ", tree
let leaves = `list`(@[a, b, c], int64(`nleaves`)) doAssert tree.nnznodes[`depth`].len == 1
let root = hash_tree_root(leaves) let root = tree.nnznodes[`depth`][0]
echo "Root: ", root #echo "Root: ", root
block: # proof for a block: # proof for a
let index = 0 let index = 0
let proof = getMerkleProof(tree, index) let proof = getMerkleProof(tree, index)
echo "Proof: ", proof #echo "Proof: ", proof
doAssert is_valid_merkle_branch( doAssert is_valid_merkle_branch(
a, get_merkle_proof(tree, index = index), a, get_merkle_proof(tree, index = index),
depth = `depth`, depth = `depth`,
index = index.uint64, index = index.uint64,
root = root root = root
), "Failed (depth: " & $`depth` & ), "Failed (depth: " & $`depth` &
", nleaves: " & $`nleaves` & ')' ", nleaves: " & $`nleaves` & ')'
block: # proof for b block: # proof for b
let index = 1 let index = 1
let proof = getMerkleProof(tree, index) let proof = getMerkleProof(tree, index)
# echo "Proof: ", proof
doAssert is_valid_merkle_branch( doAssert is_valid_merkle_branch(
b, get_merkle_proof(tree, index = index), b, get_merkle_proof(tree, index = index),
depth = `depth`, depth = `depth`,
index = index.uint64, index = index.uint64,
root = root root = root
), "Failed (depth: " & $`depth` & ), "Failed (depth: " & $`depth` &
", nleaves: " & $`nleaves` & ')' ", nleaves: " & $`nleaves` & ')'
block: # proof for c block: # proof for c
let index = 2 let index = 2
let proof = getMerkleProof(tree, index) let proof = getMerkleProof(tree, index)
# echo "Proof: ", proof
doAssert is_valid_merkle_branch( doAssert is_valid_merkle_branch(
c, get_merkle_proof(tree, index = index), c, get_merkle_proof(tree, index = index),
depth = `depth`, depth = `depth`,
index = index.uint64, index = index.uint64,
root = root root = root
), "Failed (depth: " & $`depth` & ), "Failed (depth: " & $`depth` &
", nleaves: " & $`nleaves` & ')' ", nleaves: " & $`nleaves` & ')'
roundTrips() roundTrips()
true
when isMainModule:
discard testMerkleMinimal()

View File

@ -66,7 +66,8 @@ proc signMockAttestation*(state: BeaconState, attestation: var Attestation) =
var first_iter = true # Can't do while loop on hashset var first_iter = true # Can't do while loop on hashset
for validator_index in participants: for validator_index in participants:
let sig = get_attestation_signature( let sig = get_attestation_signature(
state.fork, attestation.data, MockPrivKeys[validator_index] state.fork, state.genesis_validators_root, attestation.data,
MockPrivKeys[validator_index]
) )
if first_iter: if first_iter:
attestation.signature = sig attestation.signature = sig

View File

@ -28,9 +28,10 @@ proc signMockBlockImpl(
let privkey = MockPrivKeys[proposer_index] let privkey = MockPrivKeys[proposer_index]
signedBlock.message.body.randao_reveal = get_epoch_signature( signedBlock.message.body.randao_reveal = get_epoch_signature(
state.fork, block_slot, privkey) state.fork, state.genesis_validators_root, block_slot, privkey)
signedBlock.signature = get_block_signature( signedBlock.signature = get_block_signature(
state.fork, block_slot, hash_tree_root(signedBlock.message), privkey) state.fork, state.genesis_validators_root, block_slot,
hash_tree_root(signedBlock.message), privkey)
proc signMockBlock*( proc signMockBlock*(
state: BeaconState, state: BeaconState,

View File

@ -36,7 +36,7 @@ proc readValue*(r: var JsonReader, a: var seq[byte]) {.inline.} =
const const
FixturesDir* = currentSourcePath.rsplit(DirSep, 1)[0] / ".." / ".." / "vendor" / "nim-eth2-scenarios" FixturesDir* = currentSourcePath.rsplit(DirSep, 1)[0] / ".." / ".." / "vendor" / "nim-eth2-scenarios"
SszTestsDir* = FixturesDir/"tests-v0.11.0" SszTestsDir* = FixturesDir/"tests-v0.11.1"
proc parseTest*(path: string, Format: typedesc[Json or SSZ], T: typedesc): T = proc parseTest*(path: string, Format: typedesc[Json or SSZ], T: typedesc): T =
try: try:

View File

@ -19,7 +19,7 @@ import
const const
SpecDir = currentSourcePath.rsplit(DirSep, 1)[0] / SpecDir = currentSourcePath.rsplit(DirSep, 1)[0] /
".."/".."/"beacon_chain"/"spec" ".."/".."/"beacon_chain"/"spec"
Config = FixturesDir/"tests-v0.11.0"/const_preset/"config.yaml" Config = FixturesDir/"tests-v0.11.1"/const_preset/"config.yaml"
type type
CheckedType = SomeInteger or Slot or Epoch CheckedType = SomeInteger or Slot or Epoch
@ -88,6 +88,7 @@ const
const IgnoreKeys = [ const IgnoreKeys = [
# Ignore all non-numeric types # Ignore all non-numeric types
"DEPOSIT_CONTRACT_ADDRESS", "DEPOSIT_CONTRACT_ADDRESS",
"GENESIS_FORK_VERSION",
"SHARD_BLOCK_OFFSETS" "SHARD_BLOCK_OFFSETS"
] ]
@ -122,5 +123,5 @@ proc checkConfig() =
else: else:
check: ConstsToCheck[constant] == value.getBiggestInt().uint64() check: ConstsToCheck[constant] == value.getBiggestInt().uint64()
suiteReport "Official - 0.11.0 - constants & config " & preset(): suiteReport "Official - 0.11.1 - constants & config " & preset():
checkConfig() checkConfig()

View File

@ -30,10 +30,7 @@ proc runTest(identifier: string) =
proc `testImpl _ operations_attestations _ identifier`() = proc `testImpl _ operations_attestations _ identifier`() =
var flags: UpdateFlags
var prefix: string var prefix: string
if not existsFile(testDir/"meta.yaml"):
flags.incl skipBlsValidation
if existsFile(testDir/"post.ssz"): if existsFile(testDir/"post.ssz"):
prefix = "[Valid] " prefix = "[Valid] "
else: else:
@ -55,10 +52,10 @@ proc runTest(identifier: string) =
postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState) postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState)
if postRef.isNil: if postRef.isNil:
let done = process_attestation(stateRef[], attestationRef[], flags, cache) let done = process_attestation(stateRef[], attestationRef[], {}, cache)
doAssert done == false, "We didn't expect this invalid attestation to be processed." doAssert done == false, "We didn't expect this invalid attestation to be processed."
else: else:
let done = process_attestation(stateRef[], attestationRef[], flags, cache) let done = process_attestation(stateRef[], attestationRef[], {}, cache)
doAssert done, "Valid attestation not processed" doAssert done, "Valid attestation not processed"
check: stateRef.hash_tree_root() == postRef.hash_tree_root() check: stateRef.hash_tree_root() == postRef.hash_tree_root()
reportDiff(stateRef, postRef) reportDiff(stateRef, postRef)

View File

@ -30,10 +30,7 @@ proc runTest(identifier: string) =
proc `testImpl _ operations_attester_slashing _ identifier`() = proc `testImpl _ operations_attester_slashing _ identifier`() =
var flags: UpdateFlags
var prefix: string var prefix: string
if not existsFile(testDir/"meta.yaml"):
flags.incl skipBlsValidation
if existsFile(testDir/"post.ssz"): if existsFile(testDir/"post.ssz"):
prefix = "[Valid] " prefix = "[Valid] "
else: else:
@ -56,11 +53,11 @@ proc runTest(identifier: string) =
if postRef.isNil: if postRef.isNil:
let done = process_attester_slashing(stateRef[], attesterSlashingRef[], let done = process_attester_slashing(stateRef[], attesterSlashingRef[],
flags, cache) {}, cache)
doAssert done == false, "We didn't expect this invalid attester slashing to be processed." doAssert done == false, "We didn't expect this invalid attester slashing to be processed."
else: else:
let done = process_attester_slashing(stateRef[], attesterSlashingRef[], let done = process_attester_slashing(stateRef[], attesterSlashingRef[],
flags, cache) {}, cache)
doAssert done, "Valid attestater slashing not processed" doAssert done, "Valid attestater slashing not processed"
check: stateRef.hash_tree_root() == postRef.hash_tree_root() check: stateRef.hash_tree_root() == postRef.hash_tree_root()
reportDiff(stateRef, postRef) reportDiff(stateRef, postRef)

View File

@ -30,10 +30,7 @@ proc runTest(identifier: string) =
proc `testImpl_proposer_slashing _ identifier`() = proc `testImpl_proposer_slashing _ identifier`() =
var flags: UpdateFlags
var prefix: string var prefix: string
if not existsFile(testDir/"meta.yaml"):
flags.incl skipBlsValidation
if existsFile(testDir/"post.ssz"): if existsFile(testDir/"post.ssz"):
prefix = "[Valid] " prefix = "[Valid] "
else: else:
@ -55,10 +52,10 @@ proc runTest(identifier: string) =
var cache = get_empty_per_epoch_cache() var cache = get_empty_per_epoch_cache()
if postRef.isNil: if postRef.isNil:
let done = process_proposer_slashing(stateRef[], proposerSlashing[], flags, cache) let done = process_proposer_slashing(stateRef[], proposerSlashing[], {}, cache)
doAssert done == false, "We didn't expect this invalid proposer slashing to be processed." doAssert done == false, "We didn't expect this invalid proposer slashing to be processed."
else: else:
let done = process_proposer_slashing(stateRef[], proposerSlashing[], flags, cache) let done = process_proposer_slashing(stateRef[], proposerSlashing[], {}, cache)
doAssert done, "Valid proposer slashing not processed" doAssert done, "Valid proposer slashing not processed"
check: stateRef.hash_tree_root() == postRef.hash_tree_root() check: stateRef.hash_tree_root() == postRef.hash_tree_root()
reportDiff(stateRef, postRef) reportDiff(stateRef, postRef)

View File

@ -30,10 +30,7 @@ proc runTest(identifier: string) =
proc `testImpl _ voluntary_exit _ identifier`() = proc `testImpl _ voluntary_exit _ identifier`() =
var flags: UpdateFlags
var prefix: string var prefix: string
if not existsFile(testDir/"meta.yaml"):
flags.incl skipBlsValidation
if existsFile(testDir/"post.ssz"): if existsFile(testDir/"post.ssz"):
prefix = "[Valid] " prefix = "[Valid] "
else: else:
@ -53,10 +50,10 @@ proc runTest(identifier: string) =
postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState) postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState)
if postRef.isNil: if postRef.isNil:
let done = process_voluntary_exit(stateRef[], voluntaryExit[], flags) let done = process_voluntary_exit(stateRef[], voluntaryExit[], {})
doAssert done == false, "We didn't expect this invalid voluntary exit to be processed." doAssert done == false, "We didn't expect this invalid voluntary exit to be processed."
else: else:
let done = process_voluntary_exit(stateRef[], voluntaryExit[], flags) let done = process_voluntary_exit(stateRef[], voluntaryExit[], {})
doAssert done, "Valid voluntary exit not processed" doAssert done, "Valid voluntary exit not processed"
check: stateRef.hash_tree_root() == postRef.hash_tree_root() check: stateRef.hash_tree_root() == postRef.hash_tree_root()
reportDiff(stateRef, postRef) reportDiff(stateRef, postRef)

View File

@ -25,7 +25,7 @@ import
# ---------------------------------------------------------------- # ----------------------------------------------------------------
const const
SSZDir = FixturesDir/"tests-v0.11.0"/const_preset/"phase0"/"ssz_static" SSZDir = FixturesDir/"tests-v0.11.1"/const_preset/"phase0"/"ssz_static"
type type
SSZHashTreeRoot = object SSZHashTreeRoot = object
@ -106,7 +106,7 @@ proc runSSZtests() =
else: else:
raise newException(ValueError, "Unsupported test: " & sszType) raise newException(ValueError, "Unsupported test: " & sszType)
suiteReport "Official - 0.11.0 - SSZ consensus objects " & preset(): suiteReport "Official - 0.11.1 - SSZ consensus objects " & preset():
runSSZtests() runSSZtests()
summarizeLongTests("FixtureSSZConsensus") summarizeLongTests("FixtureSSZConsensus")

View File

@ -23,7 +23,7 @@ import
# ------------------------------------------------------------------------ # ------------------------------------------------------------------------
const const
SSZDir = FixturesDir/"tests-v0.11.0"/"general"/"phase0"/"ssz_generic" SSZDir = FixturesDir/"tests-v0.11.1"/"general"/"phase0"/"ssz_generic"
type type
SSZHashTreeRoot = object SSZHashTreeRoot = object

View File

@ -38,11 +38,8 @@ template runSuite(suiteDir, testName: string, transitionProc: untyped{ident}, us
let unitTestName = testDir.rsplit(DirSep, 1)[1] let unitTestName = testDir.rsplit(DirSep, 1)[1]
timedTest testName & " - " & unitTestName & preset(): timedTest testName & " - " & unitTestName & preset():
var stateRef, postRef: ref BeaconState let stateRef = parseTest(testDir/"pre.ssz", SSZ, ref BeaconState)
new stateRef let postRef = parseTest(testDir/"post.ssz", SSZ, ref BeaconState)
new postRef
stateRef[] = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState)
when useCache: when useCache:
var cache = get_empty_per_epoch_cache() var cache = get_empty_per_epoch_cache()

View File

@ -9,6 +9,13 @@ shift
# shellcheck source=/dev/null # shellcheck source=/dev/null
source "$(dirname "$0")/vars.sh" source "$(dirname "$0")/vars.sh"
if [[ ! -z "$1" ]]; then
ADDITIONAL_BEACON_NODE_ARGS=$1
shift
else
ADDITIONAL_BEACON_NODE_ARGS=""
fi
if [[ ! -z "$1" ]]; then if [[ ! -z "$1" ]]; then
BOOTSTRAP_NODE_ID=$1 BOOTSTRAP_NODE_ID=$1
BOOTSTRAP_ADDRESS_FILE="${SIMULATION_DIR}/node-${BOOTSTRAP_NODE_ID}/beacon_node.address" BOOTSTRAP_ADDRESS_FILE="${SIMULATION_DIR}/node-${BOOTSTRAP_NODE_ID}/beacon_node.address"
@ -47,13 +54,8 @@ fi
rm -rf "$DATA_DIR/dump" rm -rf "$DATA_DIR/dump"
mkdir -p "$DATA_DIR/dump" mkdir -p "$DATA_DIR/dump"
NODE_BIN=$BEACON_NODE_BIN
if [[ $NODE_ID == $MASTER_NODE ]]; then
NODE_BIN=$BOOTSTRAP_NODE_BIN
fi
# if you want tracing messages, add "--log-level=TRACE" below # if you want tracing messages, add "--log-level=TRACE" below
cd "$DATA_DIR" && $NODE_BIN \ cd "$DATA_DIR" && $BEACON_NODE_BIN \
--log-level=${LOG_LEVEL:-DEBUG} \ --log-level=${LOG_LEVEL:-DEBUG} \
--bootstrap-file=$BOOTSTRAP_ADDRESS_FILE \ --bootstrap-file=$BOOTSTRAP_ADDRESS_FILE \
--data-dir=$DATA_DIR \ --data-dir=$DATA_DIR \
@ -64,12 +66,11 @@ cd "$DATA_DIR" && $NODE_BIN \
--state-snapshot=$SNAPSHOT_FILE \ --state-snapshot=$SNAPSHOT_FILE \
$DEPOSIT_WEB3_URL_ARG \ $DEPOSIT_WEB3_URL_ARG \
--deposit-contract=$DEPOSIT_CONTRACT_ADDRESS \ --deposit-contract=$DEPOSIT_CONTRACT_ADDRESS \
--verify-finalization \
--rpc \ --rpc \
--rpc-address="127.0.0.1" \ --rpc-address="127.0.0.1" \
--rpc-port="$(( $BASE_RPC_PORT + $NODE_ID ))" \ --rpc-port="$(( $BASE_RPC_PORT + $NODE_ID ))" \
--metrics \ --metrics \
--metrics-address="127.0.0.1" \ --metrics-address="127.0.0.1" \
--metrics-port="$(( $BASE_METRICS_PORT + $NODE_ID ))" \ --metrics-port="$(( $BASE_METRICS_PORT + $NODE_ID ))" \
${ADDITIONAL_BEACON_NODE_ARGS} \
"$@" "$@"

View File

@ -39,18 +39,10 @@ build_beacon_node () {
$MAKE NIMFLAGS="-o:$OUTPUT_BIN $PARAMS" LOG_LEVEL="${LOG_LEVEL:-DEBUG}" beacon_node $MAKE NIMFLAGS="-o:$OUTPUT_BIN $PARAMS" LOG_LEVEL="${LOG_LEVEL:-DEBUG}" beacon_node
} }
build_beacon_node $BEACON_NODE_BIN -d:"NETWORK_TYPE=$NETWORK_TYPE" build_beacon_node $BEACON_NODE_BIN
if [[ "$BOOTSTRAP_NODE_NETWORK_TYPE" != "$NETWORK_TYPE" ]]; then
build_beacon_node $BOOTSTRAP_NODE_BIN \
--nimcache:nimcache/bootstrap_node \
-d:"NETWORK_TYPE=$BOOTSTRAP_NODE_NETWORK_TYPE"
else
cp $BEACON_NODE_BIN $BOOTSTRAP_NODE_BIN
fi
if [ ! -f "${LAST_VALIDATOR}" ]; then if [ ! -f "${LAST_VALIDATOR}" ]; then
echo Building $DEPLOY_DEPOSIT_CONTRACT_BIN echo Building "${DEPLOY_DEPOSIT_CONTRACT_BIN}"
$MAKE NIMFLAGS="-o:\"$DEPLOY_DEPOSIT_CONTRACT_BIN\" $CUSTOM_NIMFLAGS $DEFS" deposit_contract $MAKE NIMFLAGS="-o:\"$DEPLOY_DEPOSIT_CONTRACT_BIN\" $CUSTOM_NIMFLAGS $DEFS" deposit_contract
if [ "$DEPOSIT_WEB3_URL_ARG" != "" ]; then if [ "$DEPOSIT_WEB3_URL_ARG" != "" ]; then
@ -92,10 +84,10 @@ TMUX_SESSION_NAME="${TMUX_SESSION_NAME:-nbc-network-sim}"
# Using tmux or multitail is an opt-in # Using tmux or multitail is an opt-in
USE_MULTITAIL="${USE_MULTITAIL:-no}" USE_MULTITAIL="${USE_MULTITAIL:-no}"
type "$MULTITAIL" &>/dev/null || { echo $MULTITAIL is missing; USE_MULTITAIL="no"; } type "$MULTITAIL" &>/dev/null || { echo "${MULTITAIL}" is missing; USE_MULTITAIL="no"; }
USE_TMUX="${USE_TMUX:-no}" USE_TMUX="${USE_TMUX:-no}"
type "$TMUX" &>/dev/null || { echo $TMUX is missing; USE_TMUX="no"; } type "$TMUX" &>/dev/null || { echo "${TMUX}" is missing; USE_TMUX="no"; }
# Prometheus config (continued inside the loop) # Prometheus config (continued inside the loop)
mkdir -p "${METRICS_DIR}" mkdir -p "${METRICS_DIR}"
@ -125,18 +117,18 @@ fi
# Trap and ignore SIGTERM, so we don't kill this process along with its children. # Trap and ignore SIGTERM, so we don't kill this process along with its children.
if [ "$USE_MULTITAIL" = "no" ]; then if [ "$USE_MULTITAIL" = "no" ]; then
trap '' SIGTERM trap '' SIGTERM
trap 'kill -- -$$' SIGINT EXIT trap 'pkill -P $$ beacon_node' SIGINT EXIT
fi fi
COMMANDS=() COMMANDS=()
if [[ "$USE_TMUX" != "no" ]]; then if [[ "$USE_TMUX" != "no" ]]; then
$TMUX new-session -s $TMUX_SESSION_NAME -d $TMUX new-session -s "${TMUX_SESSION_NAME}" -d
# maybe these should be moved to a user config file # maybe these should be moved to a user config file
$TMUX set-option -t $TMUX_SESSION_NAME history-limit 999999 $TMUX set-option -t "${TMUX_SESSION_NAME}" history-limit 999999
$TMUX set-option -t $TMUX_SESSION_NAME remain-on-exit on $TMUX set-option -t "${TMUX_SESSION_NAME}" remain-on-exit on
$TMUX set -t $TMUX_SESSION_NAME mouse on $TMUX set -t "${TMUX_SESSION_NAME}" mouse on
fi fi
for i in $(seq $MASTER_NODE -1 $TOTAL_USER_NODES); do for i in $(seq $MASTER_NODE -1 $TOTAL_USER_NODES); do
@ -147,11 +139,11 @@ for i in $(seq $MASTER_NODE -1 $TOTAL_USER_NODES); do
done done
fi fi
CMD="${SIM_ROOT}/run_node.sh $i" CMD="${SIM_ROOT}/run_node.sh ${i} --verify-finalization"
if [[ "$USE_TMUX" != "no" ]]; then if [[ "$USE_TMUX" != "no" ]]; then
$TMUX split-window -t $TMUX_SESSION_NAME "$CMD" $TMUX split-window -t "${TMUX_SESSION_NAME}" "$CMD"
$TMUX select-layout -t $TMUX_SESSION_NAME tiled $TMUX select-layout -t "${TMUX_SESSION_NAME}" tiled
elif [[ "$USE_MULTITAIL" != "no" ]]; then elif [[ "$USE_MULTITAIL" != "no" ]]; then
if [[ "$i" == "$MASTER_NODE" ]]; then if [[ "$i" == "$MASTER_NODE" ]]; then
SLEEP="0" SLEEP="0"
@ -166,7 +158,7 @@ for i in $(seq $MASTER_NODE -1 $TOTAL_USER_NODES); do
# Prometheus config # Prometheus config
cat >> "${METRICS_DIR}/prometheus.yml" <<EOF cat >> "${METRICS_DIR}/prometheus.yml" <<EOF
- targets: ['127.0.0.1:$(( $BASE_METRICS_PORT + $i ))'] - targets: ['127.0.0.1:$(( BASE_METRICS_PORT + i ))']
labels: labels:
node: '$i' node: '$i'
EOF EOF
@ -174,8 +166,8 @@ done
if [[ "$USE_TMUX" != "no" ]]; then if [[ "$USE_TMUX" != "no" ]]; then
$TMUX kill-pane -t $TMUX_SESSION_NAME:0.0 $TMUX kill-pane -t $TMUX_SESSION_NAME:0.0
$TMUX select-layout -t $TMUX_SESSION_NAME tiled $TMUX select-layout -t "${TMUX_SESSION_NAME}" tiled
$TMUX attach-session -t $TMUX_SESSION_NAME -d $TMUX attach-session -t "${TMUX_SESSION_NAME}" -d
elif [[ "$USE_MULTITAIL" != "no" ]]; then elif [[ "$USE_MULTITAIL" != "no" ]]; then
eval $MULTITAIL -s 3 -M 0 -x \"Nimbus beacon chain\" "${COMMANDS[@]}" eval $MULTITAIL -s 3 -M 0 -x \"Nimbus beacon chain\" "${COMMANDS[@]}"
else else

View File

@ -1,21 +0,0 @@
#!/bin/bash
# Read in variables
set -a
# shellcheck source=/dev/null
source "$(dirname "$0")/vars.sh"
cd $(dirname "$0")
rm -rf data
tmux new-session -s 'beacon_node' -d
# maybe these should be moved to a user config file
tmux set-option -g history-limit 999999
tmux set -g mouse on
tmux send-keys -t 0 './start.sh' Enter
tmux new-window -n "demo_node" "./wait_master_node.sh && ./run_node.sh 0"
tmux attach-session -d

View File

@ -25,18 +25,12 @@ TOTAL_USER_NODES=${USER_NODES:-0}
TOTAL_SYSTEM_NODES=$(( TOTAL_NODES - TOTAL_USER_NODES )) TOTAL_SYSTEM_NODES=$(( TOTAL_NODES - TOTAL_USER_NODES ))
MASTER_NODE=$(( TOTAL_NODES - 1 )) MASTER_NODE=$(( TOTAL_NODES - 1 ))
# You can run a mixed simulation of daemon and native libp2p nodes
# by changing the variables below:
NETWORK_TYPE=${NETWORK_TYPE:-"libp2p"}
BOOTSTRAP_NODE_NETWORK_TYPE=${BOOTSTRAP_NODE_NETWORK_TYPE:-"libp2p"}
SIMULATION_DIR="${SIM_ROOT}/data" SIMULATION_DIR="${SIM_ROOT}/data"
METRICS_DIR="${SIM_ROOT}/prometheus" METRICS_DIR="${SIM_ROOT}/prometheus"
VALIDATORS_DIR="${SIM_ROOT}/validators" VALIDATORS_DIR="${SIM_ROOT}/validators"
SNAPSHOT_FILE="${SIMULATION_DIR}/state_snapshot.ssz" SNAPSHOT_FILE="${SIMULATION_DIR}/state_snapshot.ssz"
NETWORK_BOOTSTRAP_FILE="${SIMULATION_DIR}/bootstrap_nodes.txt" NETWORK_BOOTSTRAP_FILE="${SIMULATION_DIR}/bootstrap_nodes.txt"
BEACON_NODE_BIN="${SIMULATION_DIR}/beacon_node" BEACON_NODE_BIN="${SIMULATION_DIR}/beacon_node"
BOOTSTRAP_NODE_BIN="${SIMULATION_DIR}/bootstrap_node"
DEPLOY_DEPOSIT_CONTRACT_BIN="${SIMULATION_DIR}/deploy_deposit_contract" DEPLOY_DEPOSIT_CONTRACT_BIN="${SIMULATION_DIR}/deploy_deposit_contract"
MASTER_NODE_ADDRESS_FILE="${SIMULATION_DIR}/node-${MASTER_NODE}/beacon_node.address" MASTER_NODE_ADDRESS_FILE="${SIMULATION_DIR}/node-${MASTER_NODE}/beacon_node.address"

View File

@ -1,9 +0,0 @@
#!/bin/bash
if [ ! -f "${MASTER_NODE_ADDRESS_FILE}" ]; then
echo Waiting for master node...
while [ ! -f "${MASTER_NODE_ADDRESS_FILE}" ]; do
sleep 0.1
done
fi

View File

@ -3,11 +3,7 @@
import import
unittest, stint, blscurve, ./testutil, stew/byteutils, unittest, stint, blscurve, ./testutil, stew/byteutils,
../beacon_chain/[extras, interop, ssz], ../beacon_chain/[extras, interop, ssz],
../beacon_chain/spec/[beaconstate, crypto, helpers, datatypes] ../beacon_chain/spec/[beaconstate, crypto, datatypes]
# TODO: BLS changes in v0.10.1 will generate different interop signatures
# Requires an update of the interop mocked start
# or of ZRNT / ZCLI to v0.10.1
# Interop test yaml, found here: # Interop test yaml, found here:
# https://github.com/ethereum/eth2.0-pm/blob/a0b9d22fad424574b1307828f867b30237758468/interop/mocked_start/keygen_10_validators.yaml # https://github.com/ethereum/eth2.0-pm/blob/a0b9d22fad424574b1307828f867b30237758468/interop/mocked_start/keygen_10_validators.yaml
@ -35,87 +31,89 @@ type DepositConfig = object
# - https://github.com/status-im/eth2.0-specs/blob/c58096754b62389b0ea75dbdd717d362691b7c34/test_libs/pyspec/mockup_genesis.py # - https://github.com/status-im/eth2.0-specs/blob/c58096754b62389b0ea75dbdd717d362691b7c34/test_libs/pyspec/mockup_genesis.py
# - "zcli genesis mock" https://github.com/protolambda/zcli # - "zcli genesis mock" https://github.com/protolambda/zcli
func fromHex(T: type[ValidatorSig], hex: string): T = result.fromhex(hex)
let depositsConfig = [ let depositsConfig = [
DepositConfig( DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866"), privkey: ValidatorPrivKey.init("0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866"),
signing_root: hexToByteArray[32]("139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6"), signing_root: hexToByteArray[32]("139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"8684b7f46d25cdd6f937acdaa54bdd2fb34c78d687dca93884ba79e60ebb0df964faa4c49f3469fb882a50c7726985ff0b20c9584cc1ded7c90467422674a05177b2019661f78a5c5c56f67d586f04fd37f555b4876a910bedff830c2bece0aa" sig: ValidatorSig.fromHex"b796b670fa7eb04b4422bb0872b016895a6adffb1ebd1023db41452701ad65d6fa53d84f3b62e8753bf55230364c6aa318620b574528506ad78517f70c688b82d1c9ad0b12633e0fa5792cf58c21cee9ad25f74156eebd0b6dcd548b91db860f"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x51d0b65185db6989ab0b560d6deed19c7ead0e24b9b6372cbecb1f26bdfad000"), privkey: ValidatorPrivKey.init("0x51d0b65185db6989ab0b560d6deed19c7ead0e24b9b6372cbecb1f26bdfad000"),
signing_root: hexToByteArray[32]("bb4b6184b25873cdf430df3838c8d3e3d16cf3dc3b214e2f3ab7df9e6d5a9b52"), signing_root: hexToByteArray[32]("bb4b6184b25873cdf430df3838c8d3e3d16cf3dc3b214e2f3ab7df9e6d5a9b52"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"a2c86c4f654a2a229a287aabc8c63f224d9fb8e1d77d4a13276a87a80c8b75aa7c55826febe4bae6c826aeeccaa82f370517db4f0d5eed5fbc06a3846088871696b3c32ff3fdebdb52355d1eede85bcd71aaa2c00d6cf088a647332edc21e4f3" sig: ValidatorSig.fromHex"98c4c6a7e12a2b4aeaa23a7d6ae4d2acabc8193d1c1cb53fabcb107ebcbd9c04189c4278995c62883507926712133d941677bd15407eefa49ea6c1cb97f4f7ee4efc3fe0bfa80e3efc3c6b48646b06e6bb845c4e0e7f21df58ef67147f0da7ea"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x315ed405fafe339603932eebe8dbfd650ce5dafa561f6928664c75db85f97857"), privkey: ValidatorPrivKey.init("0x315ed405fafe339603932eebe8dbfd650ce5dafa561f6928664c75db85f97857"),
signing_root: hexToByteArray[32]("c6ddd74b1b45db17a864c87dd941cb6c6e16540c534cdbe1cc0d43e9a5d87f7c"), signing_root: hexToByteArray[32]("c6ddd74b1b45db17a864c87dd941cb6c6e16540c534cdbe1cc0d43e9a5d87f7c"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"a5a463d036e9ccb19757b2ddb1e6564a00463aed1ef51bf69264a14b6bfcff93eb6f63664e0df0b5c9e6760c560cb58d135265cecbf360a23641af627bcb17cf6c0541768d3f3b61e27f7c44f21b02cd09b52443405b12fb541f5762cd615d6e" sig: ValidatorSig.fromHex"8e6163059668ff2db1c8d430a1b0f9aeb330e8eaf680ed9709aaff5d437a54fb0144f2703cbb1e2a4a67c505b534718d0450d99203cccaf18e442bddd27e93ebfa289e6ce30a92e7befb656f12a01cb0204ffd14eed39ae457b7fad22faf8eab"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x25b1166a43c109cb330af8945d364722757c65ed2bfed5444b5a2f057f82d391"), privkey: ValidatorPrivKey.init("0x25b1166a43c109cb330af8945d364722757c65ed2bfed5444b5a2f057f82d391"),
signing_root: hexToByteArray[32]("9397cd33d4e8883dbdc1a1d7df410aa2b627740d11c5574697a2d483a50ab7bb"), signing_root: hexToByteArray[32]("9397cd33d4e8883dbdc1a1d7df410aa2b627740d11c5574697a2d483a50ab7bb"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"8731c258353c8aa46a8e38509eecfdc32018429239d9acad9b634a4d010ca51395828c0c056808c6e6df373fef7e9a570b3d648ec455d90f497e12fc3011148eded7265b0f995de72e5982db1dbb6eca8275fc99cdd10704b8cf19ec0bb9c350" sig: ValidatorSig.fromHex"b389e7b4db5caccad6b0b32394b1e77a814e519f4d0789a1e4bb20e2f7f68d7787fe5f065181eeab72d31d847ae96abc0512466689eafbee0439ab7229fb14272654815f535759467e012d9ab7db6e3b3e86d9f73742c46993c755d1f2893684"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x3f5615898238c4c4f906b507ee917e9ea1bb69b93f1dbd11a34d229c3b06784b"), privkey: ValidatorPrivKey.init("0x3f5615898238c4c4f906b507ee917e9ea1bb69b93f1dbd11a34d229c3b06784b"),
signing_root: hexToByteArray[32]("27340cc0f3b76bcc89c78e67166c13a58c97c232889391d1387fc404c4f5255e"), signing_root: hexToByteArray[32]("27340cc0f3b76bcc89c78e67166c13a58c97c232889391d1387fc404c4f5255e"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"90b20f054f6a2823d66e159050915335e7a4f64bf7ac449ef83bb1d1ba9a6b2385da977b5ba295ea2d019ee3a8140607079d671352ab233b3bf6be45c61dce5b443f23716d64382e34d7676ae64eedd01babeeb8bfd26386371f6bc01f1d4539" sig: ValidatorSig.fromHex"aeb410612b19c3176fa087fab3e56e278a01cf5ba5379aa7f4e7344dbfa9e3b3f91b6f39af463ce2e448787b0a77ee1a05f22c0d9afd2f0f6137232c432f83c26389c07a8348364ab8a745eda59ecf2aa65fa8eb3f18eacd10e5a8a2e71b1e06"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x055794614bc85ed5436c1f5cab586aab6ca84835788621091f4f3b813761e7a8"), privkey: ValidatorPrivKey.init("0x055794614bc85ed5436c1f5cab586aab6ca84835788621091f4f3b813761e7a8"),
signing_root: hexToByteArray[32]("b8cf48542d8531ae59b56e175228e7fcb82415649b5e992e132d3234b31dda2f"), signing_root: hexToByteArray[32]("b8cf48542d8531ae59b56e175228e7fcb82415649b5e992e132d3234b31dda2f"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"99df72b850141c67fc956a5ba91abb5a091538d963aa6c082e1ea30b7f7e5a54ec0ff79c749342d4635e4901e8dfc9b90604d5466ff2a7b028c53d4dac01ffb3ac0555abd3f52d35aa1ece7e8e9cce273416b3cf582a5f2190e87a3b15641f0c" sig: ValidatorSig.fromHex"b501a41ca61665dddbe248d2fa15e5498cb2b38dcf2093acd5768efeda1b0ac963e600d8e38c2c91964d8bf72fd197c71824c1d493272caf6140828f7f6b266281f044b4811bbd7ef0f57953b15399b4ef17af5b9c80df5c142600cf17bfee64"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x1023c68852075965e0f7352dee3f76a84a83e7582c181c10179936c6d6348893"), privkey: ValidatorPrivKey.init("0x1023c68852075965e0f7352dee3f76a84a83e7582c181c10179936c6d6348893"),
signing_root: hexToByteArray[32]("5f919d91faecece67422edf573a507fc5f9720f4e37063cceb40aa3b371f1aa9"), signing_root: hexToByteArray[32]("5f919d91faecece67422edf573a507fc5f9720f4e37063cceb40aa3b371f1aa9"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"a4023f36f4f354f69b615b3651596d4b479f005b04f80ef878aaeb342e94ad6f9acddf237309a79247d560b05f4f7139048b5eee0f08da3a11f3ee148ca76e3e1351a733250515a61e12027468cff2de193ab8ee5cd90bdd1c50e529edda512b" sig: ValidatorSig.fromHex"8f2e2de3c0504cc4d424de1593d508d7488bfc54f61882922b754e97e4faeebe4f24f19184f0630dc51327bc9ab26dd2073d55687f7284ab3395b770d7c4d35bb6e719e6881739e2f4f61e29e11c3b9e61529c202e30f5f5957544eeb0a9626e"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x3a941600dc41e5d20e818473b817a28507c23cdfdb4b659c15461ee5c71e41f5"), privkey: ValidatorPrivKey.init("0x3a941600dc41e5d20e818473b817a28507c23cdfdb4b659c15461ee5c71e41f5"),
signing_root: hexToByteArray[32]("d2ff8bfda7e7bcc64c636a4855d2a1eccb7f47379f526a753fd934ae37ba9ec7"), signing_root: hexToByteArray[32]("d2ff8bfda7e7bcc64c636a4855d2a1eccb7f47379f526a753fd934ae37ba9ec7"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"81c52ada6d975a5b968509ab16fa58d617dd36a6c333e6ed86a7977030e4c5d37a488596c6776c2cdf4831ea7337ad7902020092f60e547714449253a947277681ff80b7bf641ca782214fc9ec9b58c66ab43c0a554c133073c96ad35edff101" sig: ValidatorSig.fromHex"90a83842b6d215f1da3ebf3eeea6c4bff0682ee3f7aa9d06bb818c716cfdb5cd577f997ddd606c908f7a68157f36ff660a0e73265f17cccbd23be5ed053b3812672ba52bce6ec034fadea3b78f46a9c6da88db6327a18a9bb3a7f2747185fc6f"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x066e3bdc0415530e5c7fed6382d5c822c192b620203cf669903e1810a8c67d06"), privkey: ValidatorPrivKey.init("0x066e3bdc0415530e5c7fed6382d5c822c192b620203cf669903e1810a8c67d06"),
signing_root: hexToByteArray[32]("1e19687d32785632ddc9b6b319690ea45c0ea20d7bc8aacbd33f6ebbe30816e1"), signing_root: hexToByteArray[32]("1e19687d32785632ddc9b6b319690ea45c0ea20d7bc8aacbd33f6ebbe30816e1"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"b4aab8f6624f61f4f5eb6d75839919a3ef6b4e1b19cae6ef063d6281b60ff1d5efe02bcbfc4b9eb1038c42e0a3325d8a0fcf7b64ff3cd9df5c629b864dfdc5b763283254ccd6cfa28cff53e477fb1743440a18d76a776ec4d66c5f50d695ca85" sig: ValidatorSig.fromHex"a232a8bb03ecd356cf0e18644077880afe7ecfc565c8627841797deb4dfce8366cc0d0f6e151b51c0acc05a66f1363d204e8133e772dfb4878c11f7bf14b8293ce734c37adca9c32cc2987f0bc34242cc30f139d86c44f8d4383af743be3d1ae"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x2b3b88a041168a1c4cd04bdd8de7964fd35238f95442dc678514f9dadb81ec34"), privkey: ValidatorPrivKey.init("0x2b3b88a041168a1c4cd04bdd8de7964fd35238f95442dc678514f9dadb81ec34"),
signing_root: hexToByteArray[32]("64a910a0a3e7da9a7a29ee2c92859314a160040ffb2042641fc56cba75b78012"), signing_root: hexToByteArray[32]("64a910a0a3e7da9a7a29ee2c92859314a160040ffb2042641fc56cba75b78012"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"9603f7dcab6822edb92eb588f1e15fcc685ceb8bcc7257adb0e4a5995820b8ef77215650792120aff871f30a52475ea31212aa741a3f0e6b2dbcb3a63181571306a411c772a7fd08826ddeab98d1c47b5ead82f8e063b9d7f1f217808ee4fb50" sig: ValidatorSig.fromHex"8e0ccf7dd9dd00820a695161ea865220489ca48504012b7c36c85b3effb896a02ee9714a5e383f7105357a24f791562c1353e331d2cfa048cb94fd4fe42a008b18c5bdec6fcf7c8b75c5f5e582cd9571b308e8b1757d672fbb9092725985a716"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x2e62dbea7fe3127c3b236a92795dd633be51ee7cdfe5424882a2f355df497117"), privkey: ValidatorPrivKey.init("0x2e62dbea7fe3127c3b236a92795dd633be51ee7cdfe5424882a2f355df497117"),
signing_root: hexToByteArray[32]("5bf0c7a39df536b3c8a5dc550f0163af0b33a56b9454b5240cea9ad8356c4117"), signing_root: hexToByteArray[32]("5bf0c7a39df536b3c8a5dc550f0163af0b33a56b9454b5240cea9ad8356c4117"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"92b04a4128e84b827b46fd91611acc46f97826d13fbdcbf000b6b3585edd8629e38d4c13f7f3fde5a1170f4f3f55bef21883498602396c875275cb2c795d4488383b1e931fefe813296beea823c228af9e0d97e65742d380a0bbd6f370a89b23" sig: ValidatorSig.fromHex"a07adeeb639a974fe3ae78a0a28785b195bffeaa2ec558c6baa63458daaf5b7a245940a2d9b91a993515295075eba4e115c6777eda1e7933cb53f64ab36619e49faadf289a8cc1521ca3ae5f9a3f2b88e355ef0b75dd8a9949c9d2a43c5589e0"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x2042dc809c130e91906c9cb0be2fec0d6afaa8f22635efc7a3c2dbf833c1851a"), privkey: ValidatorPrivKey.init("0x2042dc809c130e91906c9cb0be2fec0d6afaa8f22635efc7a3c2dbf833c1851a"),
signing_root: hexToByteArray[32]("e8a45fa71addd854d8d78e0b2cdc8f9100c8a5e03d894c1c382068e8aa4b71e2"), signing_root: hexToByteArray[32]("e8a45fa71addd854d8d78e0b2cdc8f9100c8a5e03d894c1c382068e8aa4b71e2"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"89ac6297195e768b5e88cbbb047d8b81c77550c9462df5750f4b899fc0de985fa9e16fccc6c6bd71124eb7806064b7110d534fb8f6ccaf118074cd4f4fac8a22442e8facc2cd380ddc4ebf6b9c2f7e956f418279dc04a6737ede6d7763396ed9" sig: ValidatorSig.fromHex"95719c0c4dae737aac602aeadf9faeb9ad3492450af249c43a1147a6e471ddb3f2b5979b6587e843d20c9caa8ecd83e8001b57a4f7c302927725966acc959eb6668357831b7a0692f2396a18939d9fa974e611beed4a7a59ffe892e77d2680bd"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x15283c540041cd85c4533ee47517c8bb101c6207e9acbba2935287405a78502c"), privkey: ValidatorPrivKey.init("0x15283c540041cd85c4533ee47517c8bb101c6207e9acbba2935287405a78502c"),
signing_root: hexToByteArray[32]("3dfab0daa3be9c72c5dd3b383e756d6048bb76cd3d09abb4dc991211ae8a547b"), signing_root: hexToByteArray[32]("3dfab0daa3be9c72c5dd3b383e756d6048bb76cd3d09abb4dc991211ae8a547b"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"8adee09a19ca26d5753b9aa447b0af188a769f061d11bf40b32937ad3fa142ca9bc164323631a4bb78f0a5d4fd1262010134adc723ab377a2e6e362d3e2130a46b0a2088517aee519a424147f043cc5007a13f2d2d5311c18ee2f694ca3f19fc" sig: ValidatorSig.fromHex"b8221ad674d7c23378b488555eb6e06ce56a342dad84ba6e3a57e108c1c426161b568a9366d82fd0059a23621922a1fc0e59d8eaa66dbb4611a173be167731367edf8daad3b07b64207faf3ea457a335228def3ca61571c4edc15dc392bf4e56"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x03c85e538e1bb30235a87a3758c5571753ca1308b7dee321b74c19f78423999b"), privkey: ValidatorPrivKey.init("0x03c85e538e1bb30235a87a3758c5571753ca1308b7dee321b74c19f78423999b"),
signing_root: hexToByteArray[32]("8905ae60c419e38f263eb818a5536e4144df3c0a800132e07594d457c62b5825"), signing_root: hexToByteArray[32]("8905ae60c419e38f263eb818a5536e4144df3c0a800132e07594d457c62b5825"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"90dc90a295644da5c6d441cd0b33e34b8f1f77230755fd78b9ecbd86fd6e845e554c0579ab88c76ca14b56d9f0749f310cd884c193ec69623ccd724469268574c985ee614e80f00331c24f78a3638576d304c67c2aa6ce8949652257581c18a5" sig: ValidatorSig.fromHex"a5e61349958745c80862af84e06924748832cae379b02a50909468fef9f07f21d35a98e1287b6219528a1ad566567d0619e049efa9fa6e81410bb3a247cf53b0f6787f747f8229fb9f851290b140f14f14a2adcb23b7cafaf90b301d14169324"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x45a577d5cab31ac5cfff381500e09655f0799f29b130e6ad61c1eec4b15bf8dd"), privkey: ValidatorPrivKey.init("0x45a577d5cab31ac5cfff381500e09655f0799f29b130e6ad61c1eec4b15bf8dd"),
signing_root: hexToByteArray[32]("702d1bd9c27c999923149f6c6578c835943b58b90845086bbf5be3b94aa4663d"), signing_root: hexToByteArray[32]("702d1bd9c27c999923149f6c6578c835943b58b90845086bbf5be3b94aa4663d"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"9338c8b0050cdb464efae738d6d89ac48d5839ce750e3f1f20acd52a0b61e5c033fa186d3ed0ddf5856af6c4815971b00a68002b1eba45f5af27f91cad04831e32157fecf5fb091a8087829e2d3dd3438e0b86ff8d036be4a3876fa0dfa60e6c" sig: ValidatorSig.fromHex"893d8e70f2cdb6f7acc3d9828e72d7b20e512956588d8c068b3ef4aa649db369cf962506b7c9107246246d9b20361cd80250109da513809415314af3ef1f220c171dbc2d9c2b62056739703ae4eb1be13fa289ea8472920b2393041f69198dc5"
), DepositConfig( ), DepositConfig(
privkey: ValidatorPrivKey.init(hexToSeqByte"0x03cffafa1cbaa7e585eaee07a9d35ae57f6dfe19a9ea53af9c37e9f3dfac617c"), privkey: ValidatorPrivKey.init("0x03cffafa1cbaa7e585eaee07a9d35ae57f6dfe19a9ea53af9c37e9f3dfac617c"),
signing_root: hexToByteArray[32]("77f3da02c410e9ccba39d89983c52e6e77ca5dec3ae423311a578ee28b2ec0cd"), signing_root: hexToByteArray[32]("77f3da02c410e9ccba39d89983c52e6e77ca5dec3ae423311a578ee28b2ec0cd"),
domain: DOMAIN_DEPOSIT, domain: DOMAIN_DEPOSIT,
sig: ValidatorSig.fromHex"8819f719f7af378f27fe65c699b5206f1f7bbfd62200cab09e7ffe3d8fce0346eaa84b274d66d700cd1a0c0c7b46f62100afb2601270292ddf6a2bddff0248bb8ed6085d10c8c9e691a24b15d74bc7a9fcf931d953300d133f8c0e772704b9ba" sig: ValidatorSig.fromHex"87ae1567999d3ceefce04c1a48aa189c3d368efbeda53c01962783941c03d3a26e08e5e9d287a927decf4e77755b97e80856e339c3af41dc5ffd373c6e4768de62718ce76cfd8c2062e7673c9eedd2fec235467967f932e59e0b3a32040c0038"
) )
] ]
@ -128,14 +126,13 @@ suiteReport "Interop":
check: check:
# getBytes is bigendian and returns full 48 bytes of key.. # getBytes is bigendian and returns full 48 bytes of key..
Uint256.fromBytesBE(key.getBytes()[48-32..<48]) == v Uint256.fromBytesBE(key.exportRaw()[48-32..<48]) == v
timedTest "Interop signatures": timedTest "Interop signatures":
for dep in depositsConfig: for dep in depositsConfig:
let computed_sig = bls_sign( let computed_sig = bls_sign(
key = dep.privkey, privkey = dep.privkey,
msg = dep.signing_root, message = dep.signing_root
domain = compute_domain(dep.domain)
) )
check: check:
@ -152,20 +149,21 @@ suiteReport "Interop":
privKey = makeInteropPrivKey(i) privKey = makeInteropPrivKey(i)
deposits.add(makeDeposit(privKey.pubKey(), privKey)) deposits.add(makeDeposit(privKey.pubKey(), privKey))
const genesis_time = 1570500000
var var
# TODO this currently requires skipMerkleValidation to pass the test # TODO this currently requires skipMerkleValidation to pass the test
# makeDeposit doesn't appear to produce a proof? # makeDeposit doesn't appear to produce a proof?
initialState = initialize_beacon_state_from_eth1( initialState = initialize_beacon_state_from_eth1(
eth1BlockHash, 1570500000, deposits, {skipMerkleValidation}) eth1BlockHash, genesis_time, deposits, {skipMerkleValidation})
# https://github.com/ethereum/eth2.0-pm/tree/6e41fcf383ebeb5125938850d8e9b4e9888389b4/interop/mocked_start#create-genesis-state # https://github.com/ethereum/eth2.0-pm/tree/6e41fcf383ebeb5125938850d8e9b4e9888389b4/interop/mocked_start#create-genesis-state
initialState.genesis_time = 1570500000 initialState.genesis_time = genesis_time
let expected = let expected =
when const_preset == "minimal": when const_preset == "minimal":
"5a3bbcae4ab2b4eafded947689fd7bd8214a616ffffd2521befdfe2a3b2f74c0" "410c8758710155b49208d52c9e4bd2f11aa16a7c7521e560a2d05dcd69a023b3"
elif const_preset == "mainnet": elif const_preset == "mainnet":
"db0a887acd5e201ac579d6cdc0c4932f2a0adf342d84dc5cd11ce959fbce3760" "95a0b1e7b0b77d0cbe2bcd12c90469e68edb141424b1a6126f1d55498afe3ae6"
else: else:
"unimplemented" "unimplemented"
check: check:

16
tests/test_mocking.nim Normal file
View File

@ -0,0 +1,16 @@
# beacon_chain
# Copyright (c) 2020 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}
import
unittest, ./testutil, ./mocking/merkle_minimal
suiteReport "Mocking utilities":
timedTest "merkle_minimal":
check:
testMerkleMinimal()

View File

@ -35,5 +35,5 @@ asyncTest "connect two nodes":
c2.nat = "none" c2.nat = "none"
var n2 = await createEth2Node(c2) var n2 = await createEth2Node(c2)
await n2.connectToNetwork(bootstrapNodes = @[n1PersistentAddress]) await n2.connectToNetwork(@[n1PersistentAddress])

View File

@ -193,14 +193,14 @@ suiteReport "PeerPool testing suite":
itemFut23.finished == false itemFut23.finished == false
itemFut24.finished == false itemFut24.finished == false
timedTest "Acquire/Sorting and consistency test": timedTest "Acquire/Sorting and consistency test": closureScope:
const const
TestsCount = 1000 TestsCount = 1000
MaxNumber = 1_000_000 MaxNumber = 1_000_000
var pool = newPeerPool[PeerTest, PeerTestID]() var pool = newPeerPool[PeerTest, PeerTestID]()
proc testAcquireRelease(): Future[int] {.async.} = proc testAcquireRelease(): Future[int] {.async, gcsafe.} =
var weight: int var weight: int
var incoming, outgoing, total: seq[PeerTest] var incoming, outgoing, total: seq[PeerTest]
var incWeight1, outWeight1, totWeight1: int var incWeight1, outWeight1, totWeight1: int
@ -362,7 +362,7 @@ suiteReport "PeerPool testing suite":
check waitFor(testPeerLifetime()) == true check waitFor(testPeerLifetime()) == true
timedTest "Safe/Clear test": timedTest "Safe/Clear test": closureScope:
var pool = newPeerPool[PeerTest, PeerTestID]() var pool = newPeerPool[PeerTest, PeerTestID]()
var peer1 = PeerTest.init("peer1", 10) var peer1 = PeerTest.init("peer1", 10)
var peer2 = PeerTest.init("peer2", 9) var peer2 = PeerTest.init("peer2", 9)
@ -409,7 +409,7 @@ suiteReport "PeerPool testing suite":
asyncCheck testConsumer() asyncCheck testConsumer()
check waitFor(testClose()) == true check waitFor(testClose()) == true
timedTest "Access peers by key test": timedTest "Access peers by key test": closureScope:
var pool = newPeerPool[PeerTest, PeerTestID]() var pool = newPeerPool[PeerTest, PeerTestID]()
var peer1 = PeerTest.init("peer1", 10) var peer1 = PeerTest.init("peer1", 10)
var peer2 = PeerTest.init("peer2", 9) var peer2 = PeerTest.init("peer2", 9)

View File

@ -603,7 +603,7 @@ proc checkRequest(peer: SimplePeer, index: int, slot, count, step: int,
data: varargs[int]): bool {.inline.} = data: varargs[int]): bool {.inline.} =
result = checkRequest(peer.requests[index], slot, count, step, data) result = checkRequest(peer.requests[index], slot, count, step, data)
proc syncManagerOnePeerTest(): Future[bool] {.async.} = proc syncManagerOnePeerTest(): Future[bool] {.async, gcsafe.} =
# Syncing with one peer only. # Syncing with one peer only.
var pool = newPeerPool[SimplePeer, SimplePeerKey]() var pool = newPeerPool[SimplePeer, SimplePeerKey]()
var peer = SimplePeer.init("id1") var peer = SimplePeer.init("id1")

View File

@ -43,7 +43,7 @@ func makeDeposit(i: int, flags: UpdateFlags): Deposit =
privkey = makeFakeValidatorPrivKey(i) privkey = makeFakeValidatorPrivKey(i)
pubkey = privkey.pubKey() pubkey = privkey.pubKey()
withdrawal_credentials = makeFakeHash(i) withdrawal_credentials = makeFakeHash(i)
domain = compute_domain(DOMAIN_DEPOSIT) domain = compute_domain(DOMAIN_DEPOSIT, GENESIS_FORK_VERSION)
result = Deposit( result = Deposit(
data: DepositData( data: DepositData(
@ -84,7 +84,8 @@ proc addTestBlock*(
privKey = hackPrivKey(proposer) privKey = hackPrivKey(proposer)
randao_reveal = randao_reveal =
if skipBlsValidation notin flags: if skipBlsValidation notin flags:
privKey.genRandaoReveal(state.fork, state.slot) privKey.genRandaoReveal(
state.fork, state.genesis_validators_root, state.slot)
else: else:
ValidatorSig() ValidatorSig()
@ -149,7 +150,8 @@ proc makeAttestation*(
let let
sig = sig =
if skipBLSValidation notin flags: if skipBLSValidation notin flags:
get_attestation_signature(state.fork, data, hackPrivKey(validator)) get_attestation_signature(state.fork, state.genesis_validators_root,
data, hackPrivKey(validator))
else: else:
ValidatorSig() ValidatorSig()
@ -203,7 +205,7 @@ proc makeFullAttestations*(
aggregation_bits: CommitteeValidatorsBits.init(committee.len), aggregation_bits: CommitteeValidatorsBits.init(committee.len),
data: data, data: data,
signature: get_attestation_signature( signature: get_attestation_signature(
state.fork, data, state.fork, state.genesis_validators_root, data,
hackPrivKey(state.validators[committee[0]])) hackPrivKey(state.validators[committee[0]]))
) )
# Aggregate the remainder # Aggregate the remainder
@ -212,7 +214,7 @@ proc makeFullAttestations*(
attestation.aggregation_bits.setBit j attestation.aggregation_bits.setBit j
if skipBLSValidation notin flags: if skipBLSValidation notin flags:
attestation.signature.aggregate(get_attestation_signature( attestation.signature.aggregate(get_attestation_signature(
state.fork, data, state.fork, state.genesis_validators_root, data,
hackPrivKey(state.validators[committee[j]]) hackPrivKey(state.validators[committee[j]])
)) ))

2
vendor/nim-bearssl vendored

@ -1 +1 @@
Subproject commit 924fb6cad1c849eec29d2c96c9803e4f43d6a8f0 Subproject commit 68c6d27304245c948526487b37e10951acf7dbc8

@ -1 +1 @@
Subproject commit 8da0e30c526ab1c6c825e16546fc5db972c5408d Subproject commit fb8af46311965fd076412e6e071dda571d282024

2
vendor/nim-chronos vendored

@ -1 +1 @@
Subproject commit 7ed9f1431a0a8262f988553e9927676cad54e470 Subproject commit cbd8e03823c00dd230e48a4613c0f594b77616eb

@ -1 +1 @@
Subproject commit 24c73359b06340fb3b767c420e0e33e66bd05b86 Subproject commit 6e5d570490989c753d4645ba9173ef9358d302bb

2
vendor/nim-eth vendored

@ -1 +1 @@
Subproject commit 9c442bf65b52a4c857cc6e51efe901352e8b6ebf Subproject commit ec1492a65a1d82e83181c7d216dd97fb3268d5f0

@ -1 +1 @@
Subproject commit b06d78d1d8c306a3cce80c391856f44bf7db6119 Subproject commit 5326d824b1d91ea273095172512eb309f32e0c82

@ -1 +1 @@
Subproject commit 5fb40e4ffd2c5a7eca88203d99150e2d99732e41 Subproject commit 8a3cf6778d483a9d701534dfc2f14f3a4dfc4ab8

2
vendor/nim-json-rpc vendored

@ -1 +1 @@
Subproject commit 6fbaeb61cab889f74870372bc00cc99371e16794 Subproject commit 5c0d0961114bcaaf3da52d5918bf0b85ef0e4ce9

@ -1 +1 @@
Subproject commit 6350b72b5eda69f7ccfa57a94fd420509dbf6f49 Subproject commit c108ba90e6b304515f08fdcff62f428f3f8fbe53

@ -1 +1 @@
Subproject commit 3b29eed05a204e4efe5b54a50dc4cbe2dfd38c1b Subproject commit da216986c635599dccffa2e71eabad03653e5aef

2
vendor/nim-libp2p vendored

@ -1 +1 @@
Subproject commit 0a3e4a764b718d13fc330f228fce60ed265cfde2 Subproject commit f4740c8b8e1d55b45ed578cb42e1cd084f9b9644

2
vendor/nim-metrics vendored

@ -1 +1 @@
Subproject commit ab1d8891ef11e4c310c071213bd67aa5ac4b421d Subproject commit 5db86514a1185620a003d1e5ea1da4c0373c3b6e

@ -1 +1 @@
Subproject commit ae60eef4e8413e49fb0dbcae9a343fb479509fa0 Subproject commit 0eab8cfeee55cfa3bb893ec31137d3c25b83a1ae

2
vendor/nim-stew vendored

@ -1 +1 @@
Subproject commit 76beeb769e30adc912d648c014fd95bf748fef24 Subproject commit b06a5b6e32aa4d5abf9c1019ab6728fa8f360cc5

2
vendor/nim-web3 vendored

@ -1 +1 @@
Subproject commit 89d7a0c8fd1eb0f749432bd7136d8f385351c48e Subproject commit 969adf2f1ef42753ba26d5ab7eca01617c846792

@ -1 +1 @@
Subproject commit 088d3b7f6843fd61c829a5a0c0c29912945963ae Subproject commit 0cce46e1260b053349d0d6f337f5d67a7bc14462

2
vendor/nimcrypto vendored

@ -1 +1 @@
Subproject commit 04f933314ca1d7d79fc6e4f19a0bd7566afbf462 Subproject commit cd58cf69a0b883a4672cd3f79ee38ec0cf2c8c56

View File

@ -19,7 +19,7 @@ rm -rf ncli/nimcache
../env.sh nim c \ ../env.sh nim c \
--cpu:i386 --os:linux --gc:none --threads:off \ --cpu:i386 --os:linux --gc:none --threads:off \
-d:release -d:clang -d:emscripten -d:noSignalHandler -d:usemalloc \ -d:release -d:clang -d:emscripten -d:noSignalHandler -d:usemalloc \
--nimcache:ncli/nimcache -d:"network_type=none" \ --nimcache:ncli/nimcache \
-u:metrics \ -u:metrics \
-c ncli -c ncli

View File

@ -1,2 +1 @@
-d:"network_type=none"
-u:metrics -u:metrics