Merge pull request #593 from status-im/devel
Testnet0 release 2019-11-25
This commit is contained in:
commit
752369b6bb
|
@ -2,10 +2,6 @@ version: '{build}'
|
||||||
|
|
||||||
image: Visual Studio 2015
|
image: Visual Studio 2015
|
||||||
|
|
||||||
environment:
|
|
||||||
# disable LFS file downloading during regular cloning
|
|
||||||
GIT_LFS_SKIP_SMUDGE: 1
|
|
||||||
|
|
||||||
init: # Scripts called at the very beginning
|
init: # Scripts called at the very beginning
|
||||||
# Enable paths > 260 characters
|
# Enable paths > 260 characters
|
||||||
- ps: Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1
|
- ps: Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1
|
||||||
|
@ -30,7 +26,7 @@ install:
|
||||||
- IF "%PLATFORM%" == "x86" SET PATH=C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin;%PATH%
|
- IF "%PLATFORM%" == "x86" SET PATH=C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin;%PATH%
|
||||||
- IF "%PLATFORM%" == "x64" SET PATH=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%PATH%
|
- IF "%PLATFORM%" == "x64" SET PATH=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%PATH%
|
||||||
|
|
||||||
# LFS test fixtures
|
# official test fixtures
|
||||||
- bash scripts\setup_official_tests.sh jsonTestsCache
|
- bash scripts\setup_official_tests.sh jsonTestsCache
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
|
@ -41,6 +37,6 @@ 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
|
- mingw32-make -j2 ARCH_OVERRIDE=%PLATFORM% DISABLE_GO_CHECKS=1 P2PD_CACHE=p2pdCache
|
||||||
- mingw32-make -j2 ARCH_OVERRIDE=%PLATFORM% DISABLE_LFS_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
|
||||||
|
|
|
@ -13,8 +13,6 @@ cache:
|
||||||
git:
|
git:
|
||||||
# when multiple CI builds are queued, the tested commit needs to be in the last X commits cloned with "--depth X"
|
# when multiple CI builds are queued, the tested commit needs to be in the last X commits cloned with "--depth X"
|
||||||
depth: 10
|
depth: 10
|
||||||
# disable LFS file downloading during regular cloning
|
|
||||||
lfs_skip_smudge: true
|
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- "1.12.x"
|
- "1.12.x"
|
||||||
|
@ -39,7 +37,7 @@ matrix:
|
||||||
before_install:
|
before_install:
|
||||||
- export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
|
- export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
|
||||||
- sudo apt-get -q update
|
- sudo apt-get -q update
|
||||||
- sudo apt-get install -y libpcre3-dev git-lfs librocksdb-dev
|
- sudo apt-get install -y libpcre3-dev librocksdb-dev
|
||||||
- os: osx
|
- os: osx
|
||||||
env:
|
env:
|
||||||
- NPROC=2
|
- NPROC=2
|
||||||
|
@ -50,11 +48,12 @@ matrix:
|
||||||
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
# LFS test fixtures
|
# official test fixtures
|
||||||
- scripts/setup_official_tests.sh jsonTestsCache
|
- scripts/setup_official_tests.sh jsonTestsCache
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- set -e # fail fast
|
- set -e # fail fast
|
||||||
- make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC}" update # to allow a newer Nim version to be detected
|
- make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC}" update # to allow a newer Nim version to be detected
|
||||||
- make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC}"
|
- make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC}"
|
||||||
- make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC}" DISABLE_LFS_SCRIPT=1 test
|
- make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC}" DISABLE_TEST_FIXTURES_SCRIPT=1 test
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
{
|
{
|
||||||
"label": "nim-beacon-chain build",
|
"label": "nim-beacon-chain build",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "nimble build",
|
"command": "make",
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": true
|
"isDefault": true
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
{
|
{
|
||||||
"label": "nim-beacon-chain test",
|
"label": "nim-beacon-chain test",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "nimble test",
|
"command": "make test",
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": true
|
"isDefault": true
|
||||||
|
@ -28,4 +28,4 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
node('linux') {
|
node('linux') {
|
||||||
stage('Clone') {
|
stage('Clone') {
|
||||||
env.GIT_LFS_SKIP_SMUDGE = 1
|
|
||||||
checkout scm
|
checkout scm
|
||||||
}
|
}
|
||||||
stage('Build') {
|
stage('Build') {
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -24,7 +24,7 @@ all: | build-system-checks $(TOOLS)
|
||||||
# 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
|
||||||
|
|
||||||
GIT_SUBMODULE_UPDATE := export GIT_LFS_SKIP_SMUDGE=1; git submodule update --init --recursive
|
GIT_SUBMODULE_UPDATE := git submodule update --init --recursive
|
||||||
build-system-checks:
|
build-system-checks:
|
||||||
@[[ -e "$(BUILD_SYSTEM_DIR)/makefiles" ]] || { \
|
@[[ -e "$(BUILD_SYSTEM_DIR)/makefiles" ]] || { \
|
||||||
echo -e "'$(BUILD_SYSTEM_DIR)/makefiles' not found. Running '$(GIT_SUBMODULE_UPDATE)'.\n"; \
|
echo -e "'$(BUILD_SYSTEM_DIR)/makefiles' not found. Running '$(GIT_SUBMODULE_UPDATE)'.\n"; \
|
||||||
|
@ -52,9 +52,9 @@ p2pd: | go-checks
|
||||||
|
|
||||||
# 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.
|
||||||
DISABLE_LFS_SCRIPT := 0
|
DISABLE_TEST_FIXTURES_SCRIPT := 0
|
||||||
test: | build deps
|
test: | build deps
|
||||||
ifeq ($(DISABLE_LFS_SCRIPT), 0)
|
ifeq ($(DISABLE_TEST_FIXTURES_SCRIPT), 0)
|
||||||
V=$(V) scripts/setup_official_tests.sh
|
V=$(V) scripts/setup_official_tests.sh
|
||||||
endif
|
endif
|
||||||
$(ENV_SCRIPT) nim test $(NIM_PARAMS) beacon_chain.nims && rm -f 0000-*.json
|
$(ENV_SCRIPT) nim test $(NIM_PARAMS) beacon_chain.nims && rm -f 0000-*.json
|
||||||
|
|
|
@ -19,13 +19,10 @@ Nimbus is currently going through interoperability testing with several other be
|
||||||
* [multinet](https://github.com/status-im/nim-beacon-chain/tree/master/multinet) - a set of scripts to build and run several Eth2 clients locally
|
* [multinet](https://github.com/status-im/nim-beacon-chain/tree/master/multinet) - a set of scripts to build and run several Eth2 clients locally
|
||||||
* [ncli](https://github.com/status-im/nim-beacon-chain/tree/master/multinet) - command line tools for working with SSZ files and state transitions
|
* [ncli](https://github.com/status-im/nim-beacon-chain/tree/master/multinet) - command line tools for working with SSZ files and state transitions
|
||||||
|
|
||||||
⚠️ Important: To save bandwith `export GIT_LFS_SKIP_SMUDGE=1` before cloning the repo.
|
|
||||||
This prevents LFS during unusual clones (i.e. when you add `--recurse-submodules` without being instructed to do so).
|
|
||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|
||||||
* [status-im/nimbus](https://github.com/status-im/nimbus/): main Nimbus repository - start here to learn more about the Nimbus eco-system
|
* [status-im/nimbus](https://github.com/status-im/nimbus/): main Nimbus repository - start here to learn more about the Nimbus eco-system
|
||||||
* [ethereum/eth2.0-specs](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md): Serenity specification that this project implements
|
* [ethereum/eth2.0-specs](https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md): Serenity specification that this project implements
|
||||||
* [ethereum/beacon\_chain](https://github.com/ethereum/beacon_chain): reference implementation from the Ethereum foundation
|
* [ethereum/beacon\_chain](https://github.com/ethereum/beacon_chain): reference implementation from the Ethereum foundation
|
||||||
|
|
||||||
You can check where the beacon chain fits in the Ethereum research ecosystem in the [Status Athenaeum](https://github.com/status-im/athenaeum/blob/b465626cc551e361492e56d32517b2cdadd7493f/ethereum_research_records.json#L38).
|
You can check where the beacon chain fits in the Ethereum research ecosystem in the [Status Athenaeum](https://github.com/status-im/athenaeum/blob/b465626cc551e361492e56d32517b2cdadd7493f/ethereum_research_records.json#L38).
|
||||||
|
|
|
@ -24,7 +24,7 @@ jobs:
|
||||||
path: p2pdCache
|
path: p2pdCache
|
||||||
|
|
||||||
- task: CacheBeta@1
|
- task: CacheBeta@1
|
||||||
displayName: 'cache LFS JSON fixtures'
|
displayName: 'cache official test fixtures'
|
||||||
inputs:
|
inputs:
|
||||||
key: jsonTestsCache
|
key: jsonTestsCache
|
||||||
path: jsonTestsCache
|
path: jsonTestsCache
|
||||||
|
@ -64,12 +64,11 @@ jobs:
|
||||||
export PATH="/c/custom/${MINGW_DIR}/bin:$PATH"
|
export PATH="/c/custom/${MINGW_DIR}/bin:$PATH"
|
||||||
echo "Fetching submodules"
|
echo "Fetching submodules"
|
||||||
git config --global core.longpaths true
|
git config --global core.longpaths true
|
||||||
export GIT_LFS_SKIP_SMUDGE=1
|
|
||||||
git submodule --quiet update --init --recursive
|
git submodule --quiet update --init --recursive
|
||||||
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
|
mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} P2PD_CACHE=p2pdCache
|
||||||
file build/beacon_node
|
file build/beacon_node
|
||||||
mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} DISABLE_LFS_SCRIPT=1 test
|
mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} DISABLE_TEST_FIXTURES_SCRIPT=1 test
|
||||||
displayName: 'build and test'
|
displayName: 'build and test'
|
||||||
|
|
|
@ -46,7 +46,7 @@ proc buildBinary(name: string, srcDir = "./", params = "", cmdParams = "", lang
|
||||||
### tasks
|
### tasks
|
||||||
task test, "Run all tests":
|
task test, "Run all tests":
|
||||||
# Mainnet config
|
# Mainnet config
|
||||||
buildBinary "all_tests", "tests/", "-r -d:release -d:chronicles_log_level=ERROR"
|
buildBinary "all_tests", "tests/", "-r -d:release -d:chronicles_log_level=ERROR -d:const_preset=mainnet"
|
||||||
# Minimal config
|
# Minimal config
|
||||||
buildBinary "all_tests", "tests/", "-r -d:release -d:chronicles_log_level=ERROR -d:const_preset=minimal"
|
buildBinary "all_tests", "tests/", "-r -d:release -d:chronicles_log_level=ERROR -d:const_preset=minimal"
|
||||||
|
|
||||||
|
@ -63,6 +63,3 @@ task test, "Run all tests":
|
||||||
# State sim; getting into 4th epoch useful to trigger consensus checks
|
# State sim; getting into 4th epoch useful to trigger consensus checks
|
||||||
buildBinary "state_sim", "research/", "-r -d:release", "--validators=128 --slots=40"
|
buildBinary "state_sim", "research/", "-r -d:release", "--validators=128 --slots=40"
|
||||||
|
|
||||||
task sync_lfs_tests, "Sync LFS json tests":
|
|
||||||
# Syncs the json test files (but not the EF yaml tests)
|
|
||||||
exec "scripts/setup_official_tests.sh"
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import
|
import
|
||||||
deques, options, sequtils, tables,
|
deques, sequtils, tables,
|
||||||
chronicles, stew/bitseqs, json_serialization/std/sets,
|
chronicles, stew/bitseqs, json_serialization/std/sets,
|
||||||
./spec/[beaconstate, datatypes, crypto, digest, helpers, validator],
|
./spec/[beaconstate, datatypes, crypto, digest, helpers, validator],
|
||||||
./extras, ./ssz, ./block_pool,
|
./extras, ./ssz, ./block_pool,
|
||||||
|
@ -7,7 +7,7 @@ import
|
||||||
|
|
||||||
logScope: topics = "attpool"
|
logScope: topics = "attpool"
|
||||||
|
|
||||||
proc init*(T: type AttestationPool, blockPool: BlockPool): T =
|
func init*(T: type AttestationPool, blockPool: BlockPool): T =
|
||||||
# TODO blockPool is only used when resolving orphaned attestations - it should
|
# TODO blockPool is only used when resolving orphaned attestations - it should
|
||||||
# probably be removed as a dependency of AttestationPool (or some other
|
# probably be removed as a dependency of AttestationPool (or some other
|
||||||
# smart refactoring)
|
# smart refactoring)
|
||||||
|
@ -129,7 +129,7 @@ proc slotIndex(
|
||||||
|
|
||||||
int(attestationSlot - pool.startingSlot)
|
int(attestationSlot - pool.startingSlot)
|
||||||
|
|
||||||
proc updateLatestVotes(
|
func updateLatestVotes(
|
||||||
pool: var AttestationPool, state: BeaconState, attestationSlot: Slot,
|
pool: var AttestationPool, state: BeaconState, attestationSlot: Slot,
|
||||||
participants: seq[ValidatorIndex], blck: BlockRef) =
|
participants: seq[ValidatorIndex], blck: BlockRef) =
|
||||||
for validator in participants:
|
for validator in participants:
|
||||||
|
@ -245,7 +245,7 @@ proc add*(pool: var AttestationPool,
|
||||||
validations = 1,
|
validations = 1,
|
||||||
cat = "filtering"
|
cat = "filtering"
|
||||||
|
|
||||||
proc addUnresolved*(pool: var AttestationPool, attestation: Attestation) =
|
func addUnresolved*(pool: var AttestationPool, attestation: Attestation) =
|
||||||
pool.unresolved[attestation.data.beacon_block_root] =
|
pool.unresolved[attestation.data.beacon_block_root] =
|
||||||
UnresolvedAttestation(
|
UnresolvedAttestation(
|
||||||
attestation: attestation,
|
attestation: attestation,
|
||||||
|
@ -333,15 +333,6 @@ proc getAttestationsForBlock*(
|
||||||
if result.len >= MAX_ATTESTATIONS:
|
if result.len >= MAX_ATTESTATIONS:
|
||||||
return
|
return
|
||||||
|
|
||||||
proc getAttestationsForTargetEpoch*(
|
|
||||||
pool: AttestationPool, state: var BeaconState,
|
|
||||||
epoch: Epoch): seq[Attestation] =
|
|
||||||
# TODO quick testing kludge
|
|
||||||
let begin_slot = compute_start_slot_at_epoch(epoch).uint64
|
|
||||||
let end_slot_minus1 = (compute_start_slot_at_epoch(epoch+1) - 1).uint64
|
|
||||||
for s in begin_slot .. end_slot_minus1:
|
|
||||||
result.add getAttestationsForBlock(pool, state, s.Slot)
|
|
||||||
|
|
||||||
proc resolve*(pool: var AttestationPool, cache: var StateData) =
|
proc resolve*(pool: var AttestationPool, cache: var StateData) =
|
||||||
var
|
var
|
||||||
done: seq[Eth2Digest]
|
done: seq[Eth2Digest]
|
||||||
|
@ -365,6 +356,6 @@ proc resolve*(pool: var AttestationPool, cache: var StateData) =
|
||||||
|
|
||||||
pool.add(cache.data.data, a.blck, a.attestation)
|
pool.add(cache.data.data, a.blck, a.attestation)
|
||||||
|
|
||||||
proc latestAttestation*(
|
func latestAttestation*(
|
||||||
pool: AttestationPool, pubKey: ValidatorPubKey): BlockRef =
|
pool: AttestationPool, pubKey: ValidatorPubKey): BlockRef =
|
||||||
pool.latestAttestations.getOrDefault(pubKey)
|
pool.latestAttestations.getOrDefault(pubKey)
|
||||||
|
|
|
@ -86,6 +86,12 @@ proc putStateRoot*(db: BeaconChainDB, root: Eth2Digest, slot: Slot,
|
||||||
proc putBlock*(db: BeaconChainDB, value: BeaconBlock) =
|
proc putBlock*(db: BeaconChainDB, value: BeaconBlock) =
|
||||||
db.putBlock(signing_root(value), value)
|
db.putBlock(signing_root(value), value)
|
||||||
|
|
||||||
|
proc delBlock*(db: BeaconChainDB, key: Eth2Digest) =
|
||||||
|
db.backend.del(subkey(BeaconBlock, key))
|
||||||
|
|
||||||
|
proc delState*(db: BeaconChainDB, key: Eth2Digest) =
|
||||||
|
db.backend.del(subkey(BeaconState, key))
|
||||||
|
|
||||||
proc putHeadBlock*(db: BeaconChainDB, key: Eth2Digest) =
|
proc putHeadBlock*(db: BeaconChainDB, key: Eth2Digest) =
|
||||||
db.backend.put(subkey(kHeadBlock), key.data) # TODO head block?
|
db.backend.put(subkey(kHeadBlock), key.data) # TODO head block?
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,34 @@ declareCounter beacon_blocks_received,
|
||||||
|
|
||||||
logScope: topics = "beacnde"
|
logScope: topics = "beacnde"
|
||||||
|
|
||||||
|
type
|
||||||
|
BeaconNode = ref object
|
||||||
|
nickname: string
|
||||||
|
network: Eth2Node
|
||||||
|
forkVersion: array[4, byte]
|
||||||
|
networkIdentity: Eth2NodeIdentity
|
||||||
|
requestManager: RequestManager
|
||||||
|
isBootstrapNode: bool
|
||||||
|
bootstrapNodes: seq[BootstrapAddr]
|
||||||
|
db: BeaconChainDB
|
||||||
|
config: BeaconNodeConf
|
||||||
|
attachedValidators: ValidatorPool
|
||||||
|
blockPool: BlockPool
|
||||||
|
attestationPool: AttestationPool
|
||||||
|
mainchainMonitor: MainchainMonitor
|
||||||
|
beaconClock: BeaconClock
|
||||||
|
|
||||||
|
stateCache: StateData ##\
|
||||||
|
## State cache object that's used as a scratch pad
|
||||||
|
## TODO this is pretty dangerous - for example if someone sets it
|
||||||
|
## to a particular state then does `await`, it might change - prone to
|
||||||
|
## async races
|
||||||
|
|
||||||
|
justifiedStateCache: StateData ##\
|
||||||
|
## A second state cache that's used during head selection, to avoid
|
||||||
|
## state replaying.
|
||||||
|
# TODO Something smarter, so we don't need to keep two full copies, wasteful
|
||||||
|
|
||||||
proc onBeaconBlock*(node: BeaconNode, blck: BeaconBlock) {.gcsafe.}
|
proc onBeaconBlock*(node: BeaconNode, blck: BeaconBlock) {.gcsafe.}
|
||||||
|
|
||||||
func localValidatorsDir(conf: BeaconNodeConf): string =
|
func localValidatorsDir(conf: BeaconNodeConf): string =
|
||||||
|
@ -81,7 +109,7 @@ proc getStateFromSnapshot(node: BeaconNode, state: var BeaconState): bool =
|
||||||
dataDir = conf.dataDir.string, snapshot = snapshotPath
|
dataDir = conf.dataDir.string, snapshot = snapshotPath
|
||||||
quit 1
|
quit 1
|
||||||
else:
|
else:
|
||||||
error "missing genesis file"
|
debug "No genesis file in data directory", genesisPath
|
||||||
writeGenesisFile = true
|
writeGenesisFile = true
|
||||||
genesisPath = snapshotPath
|
genesisPath = snapshotPath
|
||||||
else:
|
else:
|
||||||
|
@ -93,16 +121,19 @@ proc getStateFromSnapshot(node: BeaconNode, state: var BeaconState): bool =
|
||||||
|
|
||||||
try:
|
try:
|
||||||
state = SSZ.decode(snapshotContents, BeaconState)
|
state = SSZ.decode(snapshotContents, BeaconState)
|
||||||
except SerializationError as err:
|
except SerializationError:
|
||||||
error "Failed to import genesis file", path = genesisPath
|
error "Failed to import genesis file", path = genesisPath
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
|
info "Loaded genesis state", path = genesisPath
|
||||||
|
|
||||||
if writeGenesisFile:
|
if writeGenesisFile:
|
||||||
try:
|
try:
|
||||||
error "writing genesis file", path = conf.dataDir/genesisFile
|
notice "Writing genesis to data directory", path = conf.dataDir/genesisFile
|
||||||
writeFile(conf.dataDir/genesisFile, snapshotContents.string)
|
writeFile(conf.dataDir/genesisFile, snapshotContents.string)
|
||||||
except CatchableError as err:
|
except CatchableError as err:
|
||||||
error "Failed to persist genesis file to data dir", err = err.msg
|
error "Failed to persist genesis file to data dir",
|
||||||
|
err = err.msg, genesisFile = conf.dataDir/genesisFile
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
result = true
|
result = true
|
||||||
|
@ -131,16 +162,11 @@ proc useBootstrapFile(node: BeaconNode, bootstrapFile: string) =
|
||||||
|
|
||||||
proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async.} =
|
proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async.} =
|
||||||
new result
|
new result
|
||||||
result.onBeaconBlock = onBeaconBlock
|
|
||||||
result.config = conf
|
result.config = conf
|
||||||
result.networkIdentity = getPersistentNetIdentity(conf)
|
result.networkIdentity = getPersistentNetIdentity(conf)
|
||||||
result.nickname = if conf.nodeName == "auto": shortForm(result.networkIdentity)
|
result.nickname = if conf.nodeName == "auto": shortForm(result.networkIdentity)
|
||||||
else: conf.nodeName
|
else: conf.nodeName
|
||||||
|
|
||||||
template fail(args: varargs[untyped]) =
|
|
||||||
stderr.write args, "\n"
|
|
||||||
quit 1
|
|
||||||
|
|
||||||
for bootNode in conf.bootstrapNodes:
|
for bootNode in conf.bootstrapNodes:
|
||||||
result.addBootstrapNode BootstrapAddr.init(bootNode)
|
result.addBootstrapNode BootstrapAddr.init(bootNode)
|
||||||
|
|
||||||
|
@ -164,22 +190,25 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async
|
||||||
|
|
||||||
var eth1MonitorStartBlock: Eth2Digest
|
var eth1MonitorStartBlock: Eth2Digest
|
||||||
if result.db.getHeadBlock().isNone():
|
if result.db.getHeadBlock().isNone():
|
||||||
var state: BeaconState
|
var state = new BeaconState
|
||||||
if not result.getStateFromSnapshot(state):
|
# TODO getStateFromSnapshot never returns false - it quits..
|
||||||
|
if not result.getStateFromSnapshot(state[]):
|
||||||
if conf.depositWeb3Url.len != 0:
|
if conf.depositWeb3Url.len != 0:
|
||||||
result.mainchainMonitor = MainchainMonitor.init(conf.depositWeb3Url, conf.depositContractAddress, eth1MonitorStartBlock)
|
result.mainchainMonitor = MainchainMonitor.init(
|
||||||
|
conf.depositWeb3Url, conf.depositContractAddress, eth1MonitorStartBlock)
|
||||||
result.mainchainMonitor.start()
|
result.mainchainMonitor.start()
|
||||||
else:
|
else:
|
||||||
stderr.write "No state snapshot (or web3 URL) provided\n"
|
stderr.write "No state snapshot (or web3 URL) provided\n"
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
state = await result.mainchainMonitor.getGenesis()
|
state[] = await result.mainchainMonitor.getGenesis()
|
||||||
else:
|
else:
|
||||||
eth1MonitorStartBlock = state.eth1Data.block_hash
|
eth1MonitorStartBlock = state.eth1Data.block_hash
|
||||||
result.commitGenesisState(state)
|
result.commitGenesisState(state[])
|
||||||
|
|
||||||
if result.mainchainMonitor.isNil and conf.depositWeb3Url.len != 0:
|
if result.mainchainMonitor.isNil and conf.depositWeb3Url.len != 0:
|
||||||
result.mainchainMonitor = MainchainMonitor.init(conf.depositWeb3Url, conf.depositContractAddress, eth1MonitorStartBlock)
|
result.mainchainMonitor = MainchainMonitor.init(
|
||||||
|
conf.depositWeb3Url, conf.depositContractAddress, eth1MonitorStartBlock)
|
||||||
result.mainchainMonitor.start()
|
result.mainchainMonitor.start()
|
||||||
|
|
||||||
result.blockPool = BlockPool.init(result.db)
|
result.blockPool = BlockPool.init(result.db)
|
||||||
|
@ -191,8 +220,9 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async
|
||||||
# TODO sync is called when a remote peer is connected - is that the right
|
# TODO sync is called when a remote peer is connected - is that the right
|
||||||
# time to do so?
|
# time to do so?
|
||||||
let sync = result.network.protocolState(BeaconSync)
|
let sync = result.network.protocolState(BeaconSync)
|
||||||
sync.node = result
|
sync.init(
|
||||||
sync.db = result.db
|
result.blockPool, result.forkVersion,
|
||||||
|
proc(blck: BeaconBlock) = onBeaconBlock(result, blck))
|
||||||
|
|
||||||
result.stateCache = result.blockPool.loadTailState()
|
result.stateCache = result.blockPool.loadTailState()
|
||||||
result.justifiedStateCache = result.stateCache
|
result.justifiedStateCache = result.stateCache
|
||||||
|
@ -245,9 +275,11 @@ proc addLocalValidator(
|
||||||
|
|
||||||
let idx = state.validators.findIt(it.pubKey == pubKey)
|
let idx = state.validators.findIt(it.pubKey == pubKey)
|
||||||
if idx == -1:
|
if idx == -1:
|
||||||
warn "Validator not in registry", pubKey
|
# We allow adding a validator even if its key is not in the state registry:
|
||||||
else:
|
# it might be that the deposit for this validator has not yet been processed
|
||||||
node.attachedValidators.addLocalValidator(ValidatorIndex(idx), pubKey, privKey)
|
warn "Validator not in registry (yet?)", pubKey
|
||||||
|
|
||||||
|
node.attachedValidators.addLocalValidator(pubKey, privKey)
|
||||||
|
|
||||||
proc addLocalValidators(node: BeaconNode, state: BeaconState) =
|
proc addLocalValidators(node: BeaconNode, state: BeaconState) =
|
||||||
for validatorKeyFile in node.config.validators:
|
for validatorKeyFile in node.config.validators:
|
||||||
|
@ -259,7 +291,7 @@ proc addLocalValidators(node: BeaconNode, state: BeaconState) =
|
||||||
|
|
||||||
info "Local validators attached ", count = node.attachedValidators.count
|
info "Local validators attached ", count = node.attachedValidators.count
|
||||||
|
|
||||||
proc getAttachedValidator(node: BeaconNode,
|
func getAttachedValidator(node: BeaconNode,
|
||||||
state: BeaconState,
|
state: BeaconState,
|
||||||
idx: ValidatorIndex): AttachedValidator =
|
idx: ValidatorIndex): AttachedValidator =
|
||||||
let validatorKey = state.validators[idx].pubkey
|
let validatorKey = state.validators[idx].pubkey
|
||||||
|
@ -287,7 +319,7 @@ proc updateHead(node: BeaconNode, slot: Slot): BlockRef =
|
||||||
newHead
|
newHead
|
||||||
|
|
||||||
proc sendAttestation(node: BeaconNode,
|
proc sendAttestation(node: BeaconNode,
|
||||||
state: BeaconState,
|
fork: Fork,
|
||||||
validator: AttachedValidator,
|
validator: AttachedValidator,
|
||||||
attestationData: AttestationData,
|
attestationData: AttestationData,
|
||||||
committeeLen: int,
|
committeeLen: int,
|
||||||
|
@ -295,7 +327,7 @@ proc sendAttestation(node: BeaconNode,
|
||||||
logScope: pcs = "send_attestation"
|
logScope: pcs = "send_attestation"
|
||||||
|
|
||||||
let
|
let
|
||||||
validatorSignature = await validator.signAttestation(attestationData, state)
|
validatorSignature = await validator.signAttestation(attestationData, fork)
|
||||||
|
|
||||||
var aggregationBits = CommitteeValidatorsBits.init(committeeLen)
|
var aggregationBits = CommitteeValidatorsBits.init(committeeLen)
|
||||||
aggregationBits.raiseBit indexInCommittee
|
aggregationBits.raiseBit indexInCommittee
|
||||||
|
@ -353,29 +385,25 @@ proc proposeBlock(node: BeaconNode,
|
||||||
doAssert false, "head slot matches proposal slot (!)"
|
doAssert false, "head slot matches proposal slot (!)"
|
||||||
# return
|
# return
|
||||||
|
|
||||||
# Get eth1data which may be async
|
# Advance state to the slot immediately preceding the one we're creating a
|
||||||
# TODO it's a bad idea to get eth1data async because that might delay block
|
# block for - potentially we will be processing empty slots along the way.
|
||||||
# production
|
|
||||||
let (eth1data, deposits) = node.blockPool.withState(
|
|
||||||
node.stateCache, BlockSlot(blck: head, slot: slot - 1)):
|
|
||||||
if node.mainchainMonitor.isNil:
|
|
||||||
let e1d =
|
|
||||||
get_eth1data_stub(
|
|
||||||
state.eth1_deposit_index, slot.compute_epoch_at_slot())
|
|
||||||
|
|
||||||
(e1d, newSeq[Deposit]())
|
|
||||||
else:
|
|
||||||
let e1d = node.mainchainMonitor.eth1Data
|
|
||||||
|
|
||||||
(e1d, node.mainchainMonitor.getPendingDeposits())
|
|
||||||
|
|
||||||
let (nroot, nblck) = node.blockPool.withState(
|
let (nroot, nblck) = node.blockPool.withState(
|
||||||
node.stateCache, BlockSlot(blck: head, slot: slot - 1)):
|
node.stateCache, BlockSlot(blck: head, slot: slot - 1)):
|
||||||
|
let (eth1data, deposits) =
|
||||||
|
if node.mainchainMonitor.isNil:
|
||||||
|
(get_eth1data_stub(
|
||||||
|
state.eth1_deposit_index, slot.compute_epoch_at_slot()),
|
||||||
|
newSeq[Deposit]())
|
||||||
|
else:
|
||||||
|
(node.mainchainMonitor.eth1Data,
|
||||||
|
node.mainchainMonitor.getPendingDeposits())
|
||||||
|
|
||||||
# To create a block, we'll first apply a partial block to the state, skipping
|
# To create a block, we'll first apply a partial block to the state, skipping
|
||||||
# some validations.
|
# some validations.
|
||||||
let
|
let
|
||||||
|
fork = state.fork
|
||||||
blockBody = BeaconBlockBody(
|
blockBody = BeaconBlockBody(
|
||||||
randao_reveal: validator.genRandaoReveal(state, slot),
|
randao_reveal: validator.genRandaoReveal(fork, slot),
|
||||||
eth1_data: eth1data,
|
eth1_data: eth1data,
|
||||||
attestations:
|
attestations:
|
||||||
node.attestationPool.getAttestationsForBlock(state, slot),
|
node.attestationPool.getAttestationsForBlock(state, slot),
|
||||||
|
@ -388,10 +416,7 @@ proc proposeBlock(node: BeaconNode,
|
||||||
body: blockBody,
|
body: blockBody,
|
||||||
# TODO: This shouldn't be necessary if OpaqueBlob is the default
|
# TODO: This shouldn't be necessary if OpaqueBlob is the default
|
||||||
signature: ValidatorSig(kind: OpaqueBlob))
|
signature: ValidatorSig(kind: OpaqueBlob))
|
||||||
|
|
||||||
var
|
|
||||||
tmpState = hashedState
|
tmpState = hashedState
|
||||||
|
|
||||||
discard state_transition(tmpState, newBlock, {skipValidation})
|
discard state_transition(tmpState, newBlock, {skipValidation})
|
||||||
# TODO only enable in fast-fail debugging situations
|
# TODO only enable in fast-fail debugging situations
|
||||||
# otherwise, bad attestations can bring down network
|
# otherwise, bad attestations can bring down network
|
||||||
|
@ -402,8 +427,11 @@ proc proposeBlock(node: BeaconNode,
|
||||||
let blockRoot = signing_root(newBlock)
|
let blockRoot = signing_root(newBlock)
|
||||||
|
|
||||||
# Careful, state no longer valid after here..
|
# Careful, state no longer valid after here..
|
||||||
|
# We use the fork from the pre-newBlock state which should be fine because
|
||||||
|
# fork carries two epochs, so even if it's a fork block, the right thing
|
||||||
|
# will happen here
|
||||||
newBlock.signature =
|
newBlock.signature =
|
||||||
await validator.signBlockProposal(state, slot, blockRoot)
|
await validator.signBlockProposal(fork, slot, blockRoot)
|
||||||
|
|
||||||
(blockRoot, newBlock)
|
(blockRoot, newBlock)
|
||||||
|
|
||||||
|
@ -551,7 +579,7 @@ proc handleAttestations(node: BeaconNode, head: BlockRef, slot: Slot) =
|
||||||
|
|
||||||
for a in attestations:
|
for a in attestations:
|
||||||
traceAsyncErrors sendAttestation(
|
traceAsyncErrors sendAttestation(
|
||||||
node, state, a.validator, a.data, a.committeeLen, a.indexInCommittee)
|
node, state.fork, 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.} =
|
||||||
|
@ -786,19 +814,26 @@ proc createPidFile(filename: string) =
|
||||||
gPidFile = filename
|
gPidFile = filename
|
||||||
addQuitProc proc {.noconv.} = removeFile gPidFile
|
addQuitProc proc {.noconv.} = removeFile gPidFile
|
||||||
|
|
||||||
proc start(node: BeaconNode, headState: BeaconState) =
|
proc start(node: BeaconNode) =
|
||||||
# TODO: while it's nice to cheat by waiting for connections here, we
|
# TODO: while it's nice to cheat by waiting for connections here, we
|
||||||
# actually need to make this part of normal application flow -
|
# actually need to make this part of normal application flow -
|
||||||
# losing all connections might happen at any time and we should be
|
# losing all connections might happen at any time and we should be
|
||||||
# prepared to handle it.
|
# prepared to handle it.
|
||||||
waitFor node.connectToNetwork()
|
waitFor node.connectToNetwork()
|
||||||
|
|
||||||
|
let
|
||||||
|
head = node.blockPool.head
|
||||||
|
finalizedHead = node.blockPool.finalizedHead
|
||||||
|
|
||||||
info "Starting beacon node",
|
info "Starting beacon node",
|
||||||
version = fullVersionStr,
|
version = fullVersionStr,
|
||||||
timeSinceFinalization =
|
timeSinceFinalization =
|
||||||
int64(node.blockPool.finalizedHead.slot.toBeaconTime()) -
|
int64(finalizedHead.slot.toBeaconTime()) -
|
||||||
int64(node.beaconClock.now()),
|
int64(node.beaconClock.now()),
|
||||||
stateSlot = shortLog(headState.slot),
|
headSlot = shortLog(head.blck.slot),
|
||||||
|
headRoot = shortLog(head.blck.root),
|
||||||
|
finalizedSlot = shortLog(finalizedHead.blck.slot),
|
||||||
|
finalizedRoot = shortLog(finalizedHead.blck.root),
|
||||||
SLOTS_PER_EPOCH,
|
SLOTS_PER_EPOCH,
|
||||||
SECONDS_PER_SLOT,
|
SECONDS_PER_SLOT,
|
||||||
SPEC_VERSION,
|
SPEC_VERSION,
|
||||||
|
@ -806,7 +841,12 @@ proc start(node: BeaconNode, headState: BeaconState) =
|
||||||
cat = "init",
|
cat = "init",
|
||||||
pcs = "start_beacon_node"
|
pcs = "start_beacon_node"
|
||||||
|
|
||||||
node.addLocalValidators(headState)
|
let
|
||||||
|
bs = BlockSlot(blck: head.blck, slot: head.blck.slot)
|
||||||
|
|
||||||
|
node.blockPool.withState(node.stateCache, bs):
|
||||||
|
node.addLocalValidators(state)
|
||||||
|
|
||||||
node.run()
|
node.run()
|
||||||
|
|
||||||
func formatGwei(amount: uint64): string =
|
func formatGwei(amount: uint64): string =
|
||||||
|
@ -896,8 +936,11 @@ when hasPrompt:
|
||||||
|
|
||||||
of "attached_validators_balance":
|
of "attached_validators_balance":
|
||||||
var balance = uint64(0)
|
var balance = uint64(0)
|
||||||
for _, validator in node.attachedValidators.validators:
|
# TODO slow linear scan!
|
||||||
balance += node.stateCache.data.data.balances[validator.idx]
|
for idx, b in node.stateCache.data.data.balances:
|
||||||
|
if node.getAttachedValidator(
|
||||||
|
node.stateCache.data.data, ValidatorIndex(idx)) != nil:
|
||||||
|
balance += b
|
||||||
formatGwei(balance)
|
formatGwei(balance)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -923,7 +966,7 @@ when hasPrompt:
|
||||||
proc statusBarUpdatesPollingLoop() {.async.} =
|
proc statusBarUpdatesPollingLoop() {.async.} =
|
||||||
while true:
|
while true:
|
||||||
update statusBar
|
update statusBar
|
||||||
await sleepAsync(1000)
|
await sleepAsync(chronos.seconds(1))
|
||||||
|
|
||||||
traceAsyncErrors statusBarUpdatesPollingLoop()
|
traceAsyncErrors statusBarUpdatesPollingLoop()
|
||||||
|
|
||||||
|
@ -1027,11 +1070,10 @@ when isMainModule:
|
||||||
var node = waitFor BeaconNode.init(config)
|
var node = waitFor BeaconNode.init(config)
|
||||||
when hasPrompt: initPrompt(node)
|
when hasPrompt: initPrompt(node)
|
||||||
|
|
||||||
# TODO slightly ugly to rely on node.stateCache state here..
|
|
||||||
if node.nickname != "":
|
if node.nickname != "":
|
||||||
dynamicLogScope(node = node.nickname): node.start(node.stateCache.data.data)
|
dynamicLogScope(node = node.nickname): node.start()
|
||||||
else:
|
else:
|
||||||
node.start(node.stateCache.data.data)
|
node.start()
|
||||||
|
|
||||||
of makeDeposits:
|
of makeDeposits:
|
||||||
createDir(config.depositsDir)
|
createDir(config.depositsDir)
|
||||||
|
@ -1052,9 +1094,6 @@ when isMainModule:
|
||||||
config.depositPrivateKey)
|
config.depositPrivateKey)
|
||||||
|
|
||||||
of query:
|
of query:
|
||||||
var
|
|
||||||
trieDB = trieDB newChainDb(config.databaseDir)
|
|
||||||
|
|
||||||
case config.queryCmd
|
case config.queryCmd
|
||||||
of QueryCmd.nimQuery:
|
of QueryCmd.nimQuery:
|
||||||
# TODO: This will handle a simple subset of Nim using
|
# TODO: This will handle a simple subset of Nim using
|
||||||
|
|
|
@ -1,45 +1,10 @@
|
||||||
import
|
import
|
||||||
sets, deques, tables, options,
|
deques, tables, options,
|
||||||
stew/[endians2],
|
stew/[endians2], chronicles,
|
||||||
spec/[datatypes, crypto, digest],
|
spec/[datatypes, crypto, digest],
|
||||||
beacon_chain_db, conf, mainchain_monitor, eth2_network, time
|
beacon_chain_db
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
# #############################################
|
|
||||||
#
|
|
||||||
# Beacon Node
|
|
||||||
#
|
|
||||||
# #############################################
|
|
||||||
BeaconNode* = ref object
|
|
||||||
nickname*: string
|
|
||||||
network*: Eth2Node
|
|
||||||
forkVersion*: array[4, byte]
|
|
||||||
networkIdentity*: Eth2NodeIdentity
|
|
||||||
requestManager*: RequestManager
|
|
||||||
isBootstrapNode*: bool
|
|
||||||
bootstrapNodes*: seq[BootstrapAddr]
|
|
||||||
db*: BeaconChainDB
|
|
||||||
config*: BeaconNodeConf
|
|
||||||
attachedValidators*: ValidatorPool
|
|
||||||
blockPool*: BlockPool
|
|
||||||
attestationPool*: AttestationPool
|
|
||||||
mainchainMonitor*: MainchainMonitor
|
|
||||||
beaconClock*: BeaconClock
|
|
||||||
onBeaconBlock*: proc (node: BeaconNode, blck: BeaconBlock) {.gcsafe.}
|
|
||||||
|
|
||||||
stateCache*: StateData ##\
|
|
||||||
## State cache object that's used as a scratch pad
|
|
||||||
## TODO this is pretty dangerous - for example if someone sets it
|
|
||||||
## to a particular state then does `await`, it might change - prone to
|
|
||||||
## async races
|
|
||||||
|
|
||||||
justifiedStateCache*: StateData ##\
|
|
||||||
## A second state cache that's used during head selection, to avoid
|
|
||||||
## state replaying.
|
|
||||||
# TODO Something smarter, so we don't need to keep two full copies, wasteful
|
|
||||||
|
|
||||||
|
|
||||||
# #############################################
|
# #############################################
|
||||||
#
|
#
|
||||||
# Attestation Pool
|
# Attestation Pool
|
||||||
|
@ -153,7 +118,7 @@ type
|
||||||
## Tree of blocks pointing back to a finalized block on the chain we're
|
## Tree of blocks pointing back to a finalized block on the chain we're
|
||||||
## interested in - we call that block the tail
|
## interested in - we call that block the tail
|
||||||
|
|
||||||
blocksBySlot*: Table[uint64, seq[BlockRef]]
|
blocksBySlot*: Table[Slot, seq[BlockRef]]
|
||||||
|
|
||||||
tail*: BlockRef ##\
|
tail*: BlockRef ##\
|
||||||
## The earliest finalized block we know about
|
## The earliest finalized block we know about
|
||||||
|
@ -207,6 +172,10 @@ type
|
||||||
## Unique identifier for a particular fork in the block chain - normally,
|
## Unique identifier for a particular fork in the block chain - normally,
|
||||||
## there's a block for every slot, but in the case a block is not produced,
|
## there's a block for every slot, but in the case a block is not produced,
|
||||||
## the chain progresses anyway, producing a new state for every slot.
|
## the chain progresses anyway, producing a new state for every slot.
|
||||||
|
#
|
||||||
|
# TODO: Isn't this type unnecessary?
|
||||||
|
# The `BlockRef` stored here already includes the `slot` number as well.
|
||||||
|
# We should either remove it or write a comment clarifying why it exists.
|
||||||
blck*: BlockRef
|
blck*: BlockRef
|
||||||
slot*: Slot
|
slot*: Slot
|
||||||
|
|
||||||
|
@ -226,7 +195,6 @@ type
|
||||||
ValidatorConnection* = object
|
ValidatorConnection* = object
|
||||||
|
|
||||||
AttachedValidator* = ref object
|
AttachedValidator* = ref object
|
||||||
idx*: ValidatorIndex
|
|
||||||
pubKey*: ValidatorPubKey
|
pubKey*: ValidatorPubKey
|
||||||
|
|
||||||
case kind*: ValidatorKind
|
case kind*: ValidatorKind
|
||||||
|
@ -238,12 +206,15 @@ type
|
||||||
ValidatorPool* = object
|
ValidatorPool* = object
|
||||||
validators*: Table[ValidatorPubKey, AttachedValidator]
|
validators*: Table[ValidatorPubKey, AttachedValidator]
|
||||||
|
|
||||||
RequestManager* = object
|
|
||||||
network*: Eth2Node
|
|
||||||
|
|
||||||
FetchRecord* = object
|
FetchRecord* = object
|
||||||
root*: Eth2Digest
|
root*: Eth2Digest
|
||||||
historySlots*: uint64
|
historySlots*: uint64
|
||||||
|
|
||||||
proc shortLog*(v: AttachedValidator): string = shortLog(v.pubKey)
|
proc shortLog*(v: AttachedValidator): string = shortLog(v.pubKey)
|
||||||
|
|
||||||
|
chronicles.formatIt BlockSlot:
|
||||||
|
($it.blck.root)[0..7] & ":" & $it.slot
|
||||||
|
|
||||||
|
chronicles.formatIt BlockRef:
|
||||||
|
($it.root)[0..7] & ":" & $it.slot
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
import
|
|
||||||
spec/datatypes, beacon_node_types
|
|
||||||
|
|
||||||
proc onBeaconBlock*(node: BeaconNode, blck: BeaconBlock) {.gcsafe.}
|
|
|
@ -8,13 +8,13 @@ declareCounter beacon_reorgs_total, "Total occurrences of reorganizations of the
|
||||||
|
|
||||||
logScope: topics = "blkpool"
|
logScope: topics = "blkpool"
|
||||||
|
|
||||||
proc parent*(bs: BlockSlot): BlockSlot =
|
func parent*(bs: BlockSlot): BlockSlot =
|
||||||
BlockSlot(
|
BlockSlot(
|
||||||
blck: if bs.slot > bs.blck.slot: bs.blck else: bs.blck.parent,
|
blck: if bs.slot > bs.blck.slot: bs.blck else: bs.blck.parent,
|
||||||
slot: bs.slot - 1
|
slot: bs.slot - 1
|
||||||
)
|
)
|
||||||
|
|
||||||
proc link(parent, child: BlockRef) =
|
func link(parent, child: BlockRef) =
|
||||||
doAssert (not (parent.root == Eth2Digest() or child.root == Eth2Digest())),
|
doAssert (not (parent.root == Eth2Digest() or child.root == Eth2Digest())),
|
||||||
"blocks missing root!"
|
"blocks missing root!"
|
||||||
doAssert parent.root != child.root, "self-references not allowed"
|
doAssert parent.root != child.root, "self-references not allowed"
|
||||||
|
@ -22,18 +22,18 @@ proc link(parent, child: BlockRef) =
|
||||||
child.parent = parent
|
child.parent = parent
|
||||||
parent.children.add(child)
|
parent.children.add(child)
|
||||||
|
|
||||||
proc init*(T: type BlockRef, root: Eth2Digest, slot: Slot): BlockRef =
|
func init*(T: type BlockRef, root: Eth2Digest, slot: Slot): BlockRef =
|
||||||
BlockRef(
|
BlockRef(
|
||||||
root: root,
|
root: root,
|
||||||
slot: slot
|
slot: slot
|
||||||
)
|
)
|
||||||
|
|
||||||
proc init*(T: type BlockRef, root: Eth2Digest, blck: BeaconBlock): BlockRef =
|
func init*(T: type BlockRef, root: Eth2Digest, blck: BeaconBlock): BlockRef =
|
||||||
BlockRef.init(root, blck.slot)
|
BlockRef.init(root, blck.slot)
|
||||||
|
|
||||||
proc findAncestorBySlot*(blck: BlockRef, slot: Slot): BlockSlot =
|
func findAncestorBySlot*(blck: BlockRef, slot: Slot): BlockSlot =
|
||||||
## Find the first ancestor that has a slot number less than or equal to `slot`
|
## Find the first ancestor that has a slot number less than or equal to `slot`
|
||||||
assert(not blck.isNil)
|
doAssert(not blck.isNil)
|
||||||
var ret = blck
|
var ret = blck
|
||||||
|
|
||||||
while ret.parent != nil and ret.slot > slot:
|
while ret.parent != nil and ret.slot > slot:
|
||||||
|
@ -81,6 +81,7 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
|
||||||
link(newRef, curRef)
|
link(newRef, curRef)
|
||||||
curRef = curRef.parent
|
curRef = curRef.parent
|
||||||
blocks[curRef.root] = curRef
|
blocks[curRef.root] = curRef
|
||||||
|
trace "Populating block pool", key = curRef.root, val = curRef
|
||||||
|
|
||||||
if latestStateRoot.isNone() and db.containsState(blck.state_root):
|
if latestStateRoot.isNone() and db.containsState(blck.state_root):
|
||||||
latestStateRoot = some(blck.state_root)
|
latestStateRoot = some(blck.state_root)
|
||||||
|
@ -90,10 +91,10 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
|
||||||
else:
|
else:
|
||||||
headRef = tailRef
|
headRef = tailRef
|
||||||
|
|
||||||
var blocksBySlot = initTable[uint64, seq[BlockRef]]()
|
var blocksBySlot = initTable[Slot, seq[BlockRef]]()
|
||||||
for _, b in tables.pairs(blocks):
|
for _, b in tables.pairs(blocks):
|
||||||
let slot = db.getBlock(b.root).get().slot
|
let slot = db.getBlock(b.root).get().slot
|
||||||
blocksBySlot.mgetOrPut(slot.uint64, @[]).add(b)
|
blocksBySlot.mgetOrPut(slot, @[]).add(b)
|
||||||
|
|
||||||
let
|
let
|
||||||
# The head state is necessary to find out what we considered to be the
|
# The head state is necessary to find out what we considered to be the
|
||||||
|
@ -120,6 +121,10 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
|
||||||
doAssert justifiedHead.slot >= finalizedHead.slot,
|
doAssert justifiedHead.slot >= finalizedHead.slot,
|
||||||
"justified head comes before finalized head - database corrupt?"
|
"justified head comes before finalized head - database corrupt?"
|
||||||
|
|
||||||
|
debug "Block pool initialized",
|
||||||
|
head = head.blck, finalizedHead, tail = tailRef,
|
||||||
|
totalBlocks = blocks.len, totalKnownSlots = blocksBySlot.len
|
||||||
|
|
||||||
BlockPool(
|
BlockPool(
|
||||||
pending: initTable[Eth2Digest, BeaconBlock](),
|
pending: initTable[Eth2Digest, BeaconBlock](),
|
||||||
missing: initTable[Eth2Digest, MissingBlock](),
|
missing: initTable[Eth2Digest, MissingBlock](),
|
||||||
|
@ -132,11 +137,21 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
|
||||||
heads: @[head]
|
heads: @[head]
|
||||||
)
|
)
|
||||||
|
|
||||||
proc addSlotMapping(pool: BlockPool, slot: uint64, br: BlockRef) =
|
proc addSlotMapping(pool: BlockPool, br: BlockRef) =
|
||||||
proc addIfMissing(s: var seq[BlockRef], v: BlockRef) =
|
proc addIfMissing(s: var seq[BlockRef], v: BlockRef) =
|
||||||
if v notin s:
|
if v notin s:
|
||||||
s.add(v)
|
s.add(v)
|
||||||
pool.blocksBySlot.mgetOrPut(slot, @[]).addIfMissing(br)
|
pool.blocksBySlot.mgetOrPut(br.slot, @[]).addIfMissing(br)
|
||||||
|
|
||||||
|
proc delSlotMapping(pool: BlockPool, br: BlockRef) =
|
||||||
|
var blks = pool.blocksBySlot.getOrDefault(br.slot)
|
||||||
|
if blks.len != 0:
|
||||||
|
let i = blks.find(br)
|
||||||
|
if i >= 0: blks.del(i)
|
||||||
|
if blks.len == 0:
|
||||||
|
pool.blocksBySlot.del(br.slot)
|
||||||
|
else:
|
||||||
|
pool.blocksBySlot[br.slot] = blks
|
||||||
|
|
||||||
proc updateStateData*(
|
proc updateStateData*(
|
||||||
pool: BlockPool, state: var StateData, bs: BlockSlot) {.gcsafe.}
|
pool: BlockPool, state: var StateData, bs: BlockSlot) {.gcsafe.}
|
||||||
|
@ -154,8 +169,9 @@ proc addResolvedBlock(
|
||||||
link(parent, blockRef)
|
link(parent, blockRef)
|
||||||
|
|
||||||
pool.blocks[blockRoot] = blockRef
|
pool.blocks[blockRoot] = blockRef
|
||||||
|
trace "Populating block pool", key = blockRoot, val = blockRef
|
||||||
|
|
||||||
pool.addSlotMapping(blck.slot.uint64, blockRef)
|
pool.addSlotMapping(blockRef)
|
||||||
|
|
||||||
# Resolved blocks should be stored in database
|
# Resolved blocks should be stored in database
|
||||||
pool.db.putBlock(blockRoot, blck)
|
pool.db.putBlock(blockRoot, blck)
|
||||||
|
@ -306,9 +322,9 @@ proc add*(
|
||||||
(parentSlot.uint64 mod SLOTS_PER_EPOCH.uint64))
|
(parentSlot.uint64 mod SLOTS_PER_EPOCH.uint64))
|
||||||
)
|
)
|
||||||
|
|
||||||
proc getRef*(pool: BlockPool, root: Eth2Digest): BlockRef =
|
func getRef*(pool: BlockPool, root: Eth2Digest): BlockRef =
|
||||||
## Retrieve a resolved block reference, if available
|
## Retrieve a resolved block reference, if available
|
||||||
pool.blocks.getOrDefault(root)
|
pool.blocks.getOrDefault(root, nil)
|
||||||
|
|
||||||
proc getBlockRange*(pool: BlockPool, headBlock: Eth2Digest,
|
proc getBlockRange*(pool: BlockPool, headBlock: Eth2Digest,
|
||||||
startSlot: Slot, skipStep: Natural,
|
startSlot: Slot, skipStep: Natural,
|
||||||
|
@ -337,13 +353,20 @@ proc getBlockRange*(pool: BlockPool, headBlock: Eth2Digest,
|
||||||
result = output.len
|
result = output.len
|
||||||
|
|
||||||
var b = pool.getRef(headBlock)
|
var b = pool.getRef(headBlock)
|
||||||
if b == nil or b.slot < startSlot:
|
if b == nil:
|
||||||
|
trace "head block not found", headBlock
|
||||||
|
return
|
||||||
|
|
||||||
|
if b.slot < startSlot:
|
||||||
|
trace "head block is older than startSlot", headBlockSlot = b.slot, startSlot
|
||||||
return
|
return
|
||||||
|
|
||||||
template skip(n: int) =
|
template skip(n: int) =
|
||||||
for i in 0 ..< n:
|
for i in 0 ..< n:
|
||||||
|
if b.parent == nil:
|
||||||
|
trace "stopping at parentless block", slot = b.slot, root = b.root
|
||||||
|
return
|
||||||
b = b.parent
|
b = b.parent
|
||||||
if b == nil: return
|
|
||||||
|
|
||||||
# We must compute the last block that is eligible for inclusion
|
# We must compute the last block that is eligible for inclusion
|
||||||
# in the results. This will be a block with a slot number that's
|
# in the results. This will be a block with a slot number that's
|
||||||
|
@ -365,6 +388,7 @@ proc getBlockRange*(pool: BlockPool, headBlock: Eth2Digest,
|
||||||
while b != nil and result > 0:
|
while b != nil and result > 0:
|
||||||
dec result
|
dec result
|
||||||
output[result] = b
|
output[result] = b
|
||||||
|
trace "getBlockRange result", position = result, blockSlot = b.slot
|
||||||
skip skipStep
|
skip skipStep
|
||||||
|
|
||||||
proc get*(pool: BlockPool, blck: BlockRef): BlockData =
|
proc get*(pool: BlockPool, blck: BlockRef): BlockData =
|
||||||
|
@ -385,7 +409,7 @@ proc get*(pool: BlockPool, root: Eth2Digest): Option[BlockData] =
|
||||||
else:
|
else:
|
||||||
none(BlockData)
|
none(BlockData)
|
||||||
|
|
||||||
proc getOrResolve*(pool: var BlockPool, root: Eth2Digest): BlockRef =
|
func getOrResolve*(pool: var BlockPool, root: Eth2Digest): BlockRef =
|
||||||
## Fetch a block ref, or nil if not found (will be added to list of
|
## Fetch a block ref, or nil if not found (will be added to list of
|
||||||
## blocks-to-resolve)
|
## blocks-to-resolve)
|
||||||
result = pool.getRef(root)
|
result = pool.getRef(root)
|
||||||
|
@ -393,11 +417,11 @@ proc getOrResolve*(pool: var BlockPool, root: Eth2Digest): BlockRef =
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
pool.missing[root] = MissingBlock(slots: 1)
|
pool.missing[root] = MissingBlock(slots: 1)
|
||||||
|
|
||||||
iterator blockRootsForSlot*(pool: BlockPool, slot: uint64|Slot): Eth2Digest =
|
iterator blockRootsForSlot*(pool: BlockPool, slot: Slot): Eth2Digest =
|
||||||
for br in pool.blocksBySlot.getOrDefault(slot.uint64, @[]):
|
for br in pool.blocksBySlot.getOrDefault(slot, @[]):
|
||||||
yield br.root
|
yield br.root
|
||||||
|
|
||||||
proc checkMissing*(pool: var BlockPool): seq[FetchRecord] =
|
func checkMissing*(pool: var BlockPool): seq[FetchRecord] =
|
||||||
## Return a list of blocks that we should try to resolve from other client -
|
## Return a list of blocks that we should try to resolve from other client -
|
||||||
## to be called periodically but not too often (once per slot?)
|
## to be called periodically but not too often (once per slot?)
|
||||||
var done: seq[Eth2Digest]
|
var done: seq[Eth2Digest]
|
||||||
|
@ -580,6 +604,44 @@ func isAncestorOf*(a, b: BlockRef): bool =
|
||||||
else:
|
else:
|
||||||
a.isAncestorOf(b.parent)
|
a.isAncestorOf(b.parent)
|
||||||
|
|
||||||
|
proc delBlockAndState(pool: BlockPool, blockRoot: Eth2Digest) =
|
||||||
|
if (let blk = pool.db.getBlock(blockRoot); blk.isSome):
|
||||||
|
pool.db.delState(blk.get.stateRoot)
|
||||||
|
pool.db.delBlock(blockRoot)
|
||||||
|
|
||||||
|
proc delFinalizedStateIfNeeded(pool: BlockPool, b: BlockRef) =
|
||||||
|
# Delete finalized state for block `b` from the database, that doesn't need
|
||||||
|
# to be kept for replaying.
|
||||||
|
# TODO: Currently the protocol doesn't provide a way to request states,
|
||||||
|
# so we don't need any of the finalized states, and thus remove all of them
|
||||||
|
# (except the most recent)
|
||||||
|
if (let blk = pool.db.getBlock(b.root); blk.isSome):
|
||||||
|
pool.db.delState(blk.get.stateRoot)
|
||||||
|
|
||||||
|
proc setTailBlock(pool: BlockPool, newTail: BlockRef) =
|
||||||
|
## Advance tail block, pruning all the states and blocks with older slots
|
||||||
|
let oldTail = pool.tail
|
||||||
|
let fromSlot = oldTail.slot.uint64
|
||||||
|
let toSlot = newTail.slot.uint64 - 1
|
||||||
|
assert(toSlot > fromSlot)
|
||||||
|
for s in fromSlot .. toSlot:
|
||||||
|
for b in pool.blocksBySlot.getOrDefault(s.Slot, @[]):
|
||||||
|
pool.delBlockAndState(b.root)
|
||||||
|
b.children = @[]
|
||||||
|
b.parent = nil
|
||||||
|
pool.blocks.del(b.root)
|
||||||
|
pool.pending.del(b.root)
|
||||||
|
pool.missing.del(b.root)
|
||||||
|
|
||||||
|
pool.blocksBySlot.del(s.Slot)
|
||||||
|
|
||||||
|
pool.db.putTailBlock(newTail.root)
|
||||||
|
pool.tail = newTail
|
||||||
|
pool.addSlotMapping(newTail)
|
||||||
|
info "Tail block updated",
|
||||||
|
slot = newTail.slot,
|
||||||
|
root = shortLog(newTail.root)
|
||||||
|
|
||||||
proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
|
proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
|
||||||
## Update what we consider to be the current head, as given by the fork
|
## Update what we consider to be the current head, as given by the fork
|
||||||
## choice.
|
## choice.
|
||||||
|
@ -587,6 +649,7 @@ proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
|
||||||
## of operations naturally becomes important here - after updating the head,
|
## of operations naturally becomes important here - after updating the head,
|
||||||
## blocks that were once considered potential candidates for a tree will
|
## blocks that were once considered potential candidates for a tree will
|
||||||
## now fall from grace, or no longer be considered resolved.
|
## now fall from grace, or no longer be considered resolved.
|
||||||
|
doAssert blck.parent != nil or blck.slot == 0
|
||||||
logScope: pcs = "fork_choice"
|
logScope: pcs = "fork_choice"
|
||||||
|
|
||||||
if pool.head.blck == blck:
|
if pool.head.blck == blck:
|
||||||
|
@ -610,7 +673,7 @@ proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
|
||||||
pool.head = Head(blck: blck, justified: blck.findAncestorBySlot(justifiedSlot))
|
pool.head = Head(blck: blck, justified: blck.findAncestorBySlot(justifiedSlot))
|
||||||
|
|
||||||
if lastHead.blck != blck.parent:
|
if lastHead.blck != blck.parent:
|
||||||
info "Updated No head block (new parent)",
|
info "Updated head block (new parent)",
|
||||||
lastHeadRoot = shortLog(lastHead.blck.root),
|
lastHeadRoot = shortLog(lastHead.blck.root),
|
||||||
parentRoot = shortLog(blck.parent.root),
|
parentRoot = shortLog(blck.parent.root),
|
||||||
stateRoot = shortLog(state.data.root),
|
stateRoot = shortLog(state.data.root),
|
||||||
|
@ -625,7 +688,7 @@ proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
|
||||||
# spurious times
|
# spurious times
|
||||||
beacon_reorgs_total.inc()
|
beacon_reorgs_total.inc()
|
||||||
else:
|
else:
|
||||||
info "Updated No head block",
|
info "Updated head block",
|
||||||
stateRoot = shortLog(state.data.root),
|
stateRoot = shortLog(state.data.root),
|
||||||
headBlockRoot = shortLog(state.blck.root),
|
headBlockRoot = shortLog(state.blck.root),
|
||||||
stateSlot = shortLog(state.data.data.slot),
|
stateSlot = shortLog(state.data.data.slot),
|
||||||
|
@ -634,10 +697,9 @@ proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
|
||||||
cat = "fork_choice"
|
cat = "fork_choice"
|
||||||
|
|
||||||
let
|
let
|
||||||
|
finalizedEpochStartSlot = state.data.data.finalized_checkpoint.epoch.compute_start_slot_at_epoch()
|
||||||
# TODO there might not be a block at the epoch boundary - what then?
|
# TODO there might not be a block at the epoch boundary - what then?
|
||||||
finalizedHead =
|
finalizedHead = blck.findAncestorBySlot(finalizedEpochStartSlot)
|
||||||
blck.findAncestorBySlot(
|
|
||||||
state.data.data.finalized_checkpoint.epoch.compute_start_slot_at_epoch())
|
|
||||||
|
|
||||||
doAssert (not finalizedHead.blck.isNil),
|
doAssert (not finalizedHead.blck.isNil),
|
||||||
"Block graph should always lead to a finalized block"
|
"Block graph should always lead to a finalized block"
|
||||||
|
@ -650,6 +712,8 @@ proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
|
||||||
headBlockSlot = shortLog(blck.slot),
|
headBlockSlot = shortLog(blck.slot),
|
||||||
cat = "fork_choice"
|
cat = "fork_choice"
|
||||||
|
|
||||||
|
pool.finalizedHead = finalizedHead
|
||||||
|
|
||||||
var cur = finalizedHead.blck
|
var cur = finalizedHead.blck
|
||||||
while cur != pool.finalizedHead.blck:
|
while cur != pool.finalizedHead.blck:
|
||||||
# Finalization means that we choose a single chain as the canonical one -
|
# Finalization means that we choose a single chain as the canonical one -
|
||||||
|
@ -666,11 +730,13 @@ proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
|
||||||
for child in cur.parent.children:
|
for child in cur.parent.children:
|
||||||
if child != cur:
|
if child != cur:
|
||||||
pool.blocks.del(child.root)
|
pool.blocks.del(child.root)
|
||||||
|
pool.delBlockAndState(child.root)
|
||||||
|
pool.delSlotMapping(child)
|
||||||
|
else:
|
||||||
|
pool.delFinalizedStateIfNeeded(child)
|
||||||
cur.parent.children = @[cur]
|
cur.parent.children = @[cur]
|
||||||
cur = cur.parent
|
cur = cur.parent
|
||||||
|
|
||||||
pool.finalizedHead = finalizedHead
|
|
||||||
|
|
||||||
let hlen = pool.heads.len
|
let hlen = pool.heads.len
|
||||||
for i in 0..<hlen:
|
for i in 0..<hlen:
|
||||||
let n = hlen - i - 1
|
let n = hlen - i - 1
|
||||||
|
@ -678,7 +744,15 @@ proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
|
||||||
not pool.heads[n].blck.isAncestorOf(pool.finalizedHead.blck):
|
not pool.heads[n].blck.isAncestorOf(pool.finalizedHead.blck):
|
||||||
pool.heads.del(n)
|
pool.heads.del(n)
|
||||||
|
|
||||||
proc latestJustifiedBlock*(pool: BlockPool): BlockSlot =
|
# Calculate new tail block and set it
|
||||||
|
# New tail should be WEAK_SUBJECTIVITY_PERIOD * 2 older than finalizedHead
|
||||||
|
const tailSlotInterval = WEAK_SUBJECTVITY_PERIOD * 2
|
||||||
|
if finalizedEpochStartSlot - GENESIS_SLOT > tailSlotInterval:
|
||||||
|
let tailSlot = finalizedEpochStartSlot - tailSlotInterval
|
||||||
|
let newTail = finalizedHead.blck.findAncestorBySlot(tailSlot)
|
||||||
|
pool.setTailBlock(newTail.blck)
|
||||||
|
|
||||||
|
func latestJustifiedBlock*(pool: BlockPool): BlockSlot =
|
||||||
## Return the most recent block that is justified and at least as recent
|
## Return the most recent block that is justified and at least as recent
|
||||||
## as the latest finalized block
|
## as the latest finalized block
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ type
|
||||||
|
|
||||||
BeaconNodeConf* = object
|
BeaconNodeConf* = object
|
||||||
logLevel* {.
|
logLevel* {.
|
||||||
defaultValue: enabledLogLevel
|
defaultValue: LogLevel.DEBUG
|
||||||
desc: "Sets the log level."
|
desc: "Sets the log level."
|
||||||
name: "log-level" }: LogLevel
|
name: "log-level" }: LogLevel
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ proc main() {.async.} =
|
||||||
web3.privateKey = initPrivateKey(cfg.privateKey)
|
web3.privateKey = initPrivateKey(cfg.privateKey)
|
||||||
else:
|
else:
|
||||||
let accounts = await web3.provider.eth_accounts()
|
let accounts = await web3.provider.eth_accounts()
|
||||||
assert(accounts.len > 0)
|
doAssert(accounts.len > 0)
|
||||||
web3.defaultAccount = accounts[0]
|
web3.defaultAccount = accounts[0]
|
||||||
|
|
||||||
case cfg.cmd
|
case cfg.cmd
|
||||||
|
|
|
@ -272,7 +272,7 @@ else:
|
||||||
|
|
||||||
proc saveConnectionAddressFile*(node: Eth2Node, filename: string) =
|
proc saveConnectionAddressFile*(node: Eth2Node, filename: string) =
|
||||||
let id = waitFor node.daemon.identity()
|
let id = waitFor node.daemon.identity()
|
||||||
Json.saveFile(filename, id, pretty = false)
|
writeFile(filename, $id.addresses[0] & "/p2p/" & id.peer.pretty)
|
||||||
|
|
||||||
proc loadConnectionAddressFile*(filename: string): PeerInfo =
|
proc loadConnectionAddressFile*(filename: string): PeerInfo =
|
||||||
Json.loadFile(filename, PeerInfo)
|
Json.loadFile(filename, PeerInfo)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
# Temporary dumping ground for extra types and helpers that could make it into
|
# Temporary dumping ground for extra types and helpers that could make it into
|
||||||
|
|
|
@ -4,7 +4,7 @@ import
|
||||||
./spec/[datatypes, crypto, helpers],
|
./spec/[datatypes, crypto, helpers],
|
||||||
./attestation_pool, ./beacon_node_types, ./ssz
|
./attestation_pool, ./beacon_node_types, ./ssz
|
||||||
|
|
||||||
proc get_ancestor(blck: BlockRef, slot: Slot): BlockRef =
|
func get_ancestor(blck: BlockRef, slot: Slot): BlockRef =
|
||||||
if blck.slot == slot:
|
if blck.slot == slot:
|
||||||
blck
|
blck
|
||||||
elif blck.slot < slot:
|
elif blck.slot < slot:
|
||||||
|
@ -16,7 +16,7 @@ proc get_ancestor(blck: BlockRef, slot: Slot): BlockRef =
|
||||||
# The structure of this code differs from the spec since we use a different
|
# The structure of this code differs from the spec since we use a different
|
||||||
# strategy for storing states and justification points - it should nonetheless
|
# strategy for storing states and justification points - it should nonetheless
|
||||||
# be close in terms of functionality.
|
# be close in terms of functionality.
|
||||||
proc lmdGhost*(
|
func lmdGhost*(
|
||||||
pool: AttestationPool, start_state: BeaconState,
|
pool: AttestationPool, start_state: BeaconState,
|
||||||
start_block: BlockRef): BlockRef =
|
start_block: BlockRef): BlockRef =
|
||||||
# TODO: a Fenwick Tree datastructure to keep track of cumulated votes
|
# TODO: a Fenwick Tree datastructure to keep track of cumulated votes
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
import strutils, os, tables
|
import strutils, os, tables
|
||||||
import confutils, chronicles, chronos, libp2p/daemon/daemonapi,
|
import confutils, chronicles, chronos, libp2p/daemon/daemonapi,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import
|
import
|
||||||
ospaths,
|
|
||||||
stew/endians2, stint,
|
stew/endians2, stint,
|
||||||
./extras, ./ssz,
|
./extras, ./ssz,
|
||||||
spec/[crypto, datatypes, digest, helpers]
|
spec/[crypto, datatypes, digest, helpers]
|
||||||
|
@ -41,7 +40,7 @@ const eth1BlockHash* = block:
|
||||||
x
|
x
|
||||||
|
|
||||||
func makeWithdrawalCredentials*(k: ValidatorPubKey): Eth2Digest =
|
func makeWithdrawalCredentials*(k: ValidatorPubKey): Eth2Digest =
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_deposit-contract.md#withdrawal-credentials
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_deposit-contract.md#withdrawal-credentials
|
||||||
var bytes = eth2hash(k.getBytes())
|
var bytes = eth2hash(k.getBytes())
|
||||||
bytes.data[0] = BLS_WITHDRAWAL_PREFIX.uint8
|
bytes.data[0] = BLS_WITHDRAWAL_PREFIX.uint8
|
||||||
bytes
|
bytes
|
||||||
|
|
|
@ -85,8 +85,6 @@ type
|
||||||
|
|
||||||
TransmissionError* = object of CatchableError
|
TransmissionError* = object of CatchableError
|
||||||
|
|
||||||
ResponseSizeLimitReached* = object of CatchableError
|
|
||||||
|
|
||||||
const
|
const
|
||||||
defaultIncomingReqTimeout = 5000
|
defaultIncomingReqTimeout = 5000
|
||||||
HandshakeTimeout = FaultOrError
|
HandshakeTimeout = FaultOrError
|
||||||
|
@ -337,9 +335,6 @@ proc sendNotificationMsg(peer: Peer, protocolId: string, requestBytes: Bytes) {.
|
||||||
if sent != bytes.len:
|
if sent != bytes.len:
|
||||||
raise newException(TransmissionError, "Failed to deliver msg bytes")
|
raise newException(TransmissionError, "Failed to deliver msg bytes")
|
||||||
|
|
||||||
template raiseMaxRespSizeError =
|
|
||||||
raise newException(ResponseSizeLimitReached, "Response size limit reached")
|
|
||||||
|
|
||||||
# TODO There is too much duplication in the responder functions, but
|
# TODO There is too much duplication in the responder functions, but
|
||||||
# I hope to reduce this when I increse the reliance on output streams.
|
# I hope to reduce this when I increse the reliance on output streams.
|
||||||
proc sendResponseChunkBytes(responder: UntypedResponder, payload: Bytes) {.async.} =
|
proc sendResponseChunkBytes(responder: UntypedResponder, payload: Bytes) {.async.} =
|
||||||
|
@ -604,12 +599,6 @@ proc p2pProtocolBackendImpl*(p: P2PProtocol): Backend =
|
||||||
try:
|
try:
|
||||||
`tracing`
|
`tracing`
|
||||||
`awaitUserHandler`
|
`awaitUserHandler`
|
||||||
except ResponseSizeLimitReached:
|
|
||||||
# The response size limit is currently handled with an exception in
|
|
||||||
# order to make it easier to switch to an alternative policy when it
|
|
||||||
# will be signalled with an error response code (and to avoid making
|
|
||||||
# the `response` API in the high-level protocols more complicated for now).
|
|
||||||
chronicles.debug "response size limit reached", peer, reqName = `msgNameLit`
|
|
||||||
except CatchableError as `errVar`:
|
except CatchableError as `errVar`:
|
||||||
`await` sendErrorResponse(`peerVar`, `streamVar`, ServerError, `errVar`.msg)
|
`await` sendErrorResponse(`peerVar`, `streamVar`, ServerError, `errVar`.msg)
|
||||||
|
|
||||||
|
|
|
@ -85,8 +85,6 @@ type
|
||||||
|
|
||||||
TransmissionError* = object of CatchableError
|
TransmissionError* = object of CatchableError
|
||||||
|
|
||||||
ResponseSizeLimitReached* = object of CatchableError
|
|
||||||
|
|
||||||
const
|
const
|
||||||
defaultIncomingReqTimeout = 5000
|
defaultIncomingReqTimeout = 5000
|
||||||
HandshakeTimeout = FaultOrError
|
HandshakeTimeout = FaultOrError
|
||||||
|
@ -187,21 +185,26 @@ proc readChunk(stream: P2PStream,
|
||||||
|
|
||||||
proc readSizePrefix(transp: StreamTransport,
|
proc readSizePrefix(transp: StreamTransport,
|
||||||
deadline: Future[void]): Future[int] {.async.} =
|
deadline: Future[void]): Future[int] {.async.} =
|
||||||
|
trace "about to read msg size prefix"
|
||||||
var parser: VarintParser[uint64, ProtoBuf]
|
var parser: VarintParser[uint64, ProtoBuf]
|
||||||
while true:
|
while true:
|
||||||
var nextByte: byte
|
var nextByte: byte
|
||||||
var readNextByte = transp.readExactly(addr nextByte, 1)
|
var readNextByte = transp.readExactly(addr nextByte, 1)
|
||||||
await readNextByte or deadline
|
await readNextByte or deadline
|
||||||
if not readNextByte.finished:
|
if not readNextByte.finished:
|
||||||
|
trace "size prefix byte not received in time"
|
||||||
return -1
|
return -1
|
||||||
case parser.feedByte(nextByte)
|
case parser.feedByte(nextByte)
|
||||||
of Done:
|
of Done:
|
||||||
let res = parser.getResult
|
let res = parser.getResult
|
||||||
if res > uint64(REQ_RESP_MAX_SIZE):
|
if res > uint64(REQ_RESP_MAX_SIZE):
|
||||||
|
trace "size prefix outside of range", res
|
||||||
return -1
|
return -1
|
||||||
else:
|
else:
|
||||||
|
trace "got size prefix", res
|
||||||
return int(res)
|
return int(res)
|
||||||
of Overflow:
|
of Overflow:
|
||||||
|
trace "size prefix overflow"
|
||||||
return -1
|
return -1
|
||||||
of Incomplete:
|
of Incomplete:
|
||||||
continue
|
continue
|
||||||
|
@ -209,26 +212,39 @@ proc readSizePrefix(transp: StreamTransport,
|
||||||
proc readMsgBytes(stream: P2PStream,
|
proc readMsgBytes(stream: P2PStream,
|
||||||
withResponseCode: bool,
|
withResponseCode: bool,
|
||||||
deadline: Future[void]): Future[Bytes] {.async.} =
|
deadline: Future[void]): Future[Bytes] {.async.} =
|
||||||
|
trace "about to read message bytes", withResponseCode
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if withResponseCode:
|
if withResponseCode:
|
||||||
var responseCode: byte
|
var responseCode: byte
|
||||||
|
trace "about to read response code"
|
||||||
var readResponseCode = stream.transp.readExactly(addr responseCode, 1)
|
var readResponseCode = stream.transp.readExactly(addr responseCode, 1)
|
||||||
await readResponseCode or deadline
|
await readResponseCode or deadline
|
||||||
|
|
||||||
if not readResponseCode.finished:
|
if not readResponseCode.finished:
|
||||||
|
trace "response code not received in time"
|
||||||
|
return
|
||||||
|
|
||||||
|
if responseCode > ResponseCode.high.byte:
|
||||||
|
trace "invalid response code", responseCode
|
||||||
return
|
return
|
||||||
if responseCode > ResponseCode.high.byte: return
|
|
||||||
|
|
||||||
logScope: responseCode = ResponseCode(responseCode)
|
logScope: responseCode = ResponseCode(responseCode)
|
||||||
|
trace "got response code"
|
||||||
|
|
||||||
case ResponseCode(responseCode)
|
case ResponseCode(responseCode)
|
||||||
of InvalidRequest, ServerError:
|
of InvalidRequest, ServerError:
|
||||||
let responseErrMsg = await readChunk(stream, string, false, deadline)
|
let responseErrMsg = await readChunk(stream, string, false, deadline)
|
||||||
debug "P2P request resulted in error", responseErrMsg
|
debug "P2P request resulted in error", responseErrMsg
|
||||||
return
|
return
|
||||||
|
|
||||||
of Success:
|
of Success:
|
||||||
# The response is OK, the execution continues below
|
# The response is OK, the execution continues below
|
||||||
discard
|
discard
|
||||||
|
|
||||||
var sizePrefix = await readSizePrefix(stream.transp, deadline)
|
var sizePrefix = await readSizePrefix(stream.transp, deadline)
|
||||||
|
trace "got msg size prefix", sizePrefix
|
||||||
|
|
||||||
if sizePrefix == -1:
|
if sizePrefix == -1:
|
||||||
debug "Failed to read an incoming message size prefix", peer = stream.peer
|
debug "Failed to read an incoming message size prefix", peer = stream.peer
|
||||||
return
|
return
|
||||||
|
@ -237,12 +253,17 @@ proc readMsgBytes(stream: P2PStream,
|
||||||
debug "Received SSZ with zero size", peer = stream.peer
|
debug "Received SSZ with zero size", peer = stream.peer
|
||||||
return
|
return
|
||||||
|
|
||||||
|
trace "about to read msg bytes"
|
||||||
var msgBytes = newSeq[byte](sizePrefix)
|
var msgBytes = newSeq[byte](sizePrefix)
|
||||||
var readBody = stream.transp.readExactly(addr msgBytes[0], sizePrefix)
|
var readBody = stream.transp.readExactly(addr msgBytes[0], sizePrefix)
|
||||||
await readBody or deadline
|
await readBody or deadline
|
||||||
if not readBody.finished: return
|
if not readBody.finished:
|
||||||
|
trace "msg bytes not received in time"
|
||||||
|
return
|
||||||
|
|
||||||
|
trace "got message bytes", msgBytes
|
||||||
return msgBytes
|
return msgBytes
|
||||||
|
|
||||||
except TransportIncompleteError:
|
except TransportIncompleteError:
|
||||||
return @[]
|
return @[]
|
||||||
|
|
||||||
|
@ -337,9 +358,6 @@ proc sendNotificationMsg(peer: Peer, protocolId: string, requestBytes: Bytes) {.
|
||||||
if sent != bytes.len:
|
if sent != bytes.len:
|
||||||
raise newException(TransmissionError, "Failed to deliver msg bytes")
|
raise newException(TransmissionError, "Failed to deliver msg bytes")
|
||||||
|
|
||||||
template raiseMaxRespSizeError =
|
|
||||||
raise newException(ResponseSizeLimitReached, "Response size limit reached")
|
|
||||||
|
|
||||||
# TODO There is too much duplication in the responder functions, but
|
# TODO There is too much duplication in the responder functions, but
|
||||||
# I hope to reduce this when I increse the reliance on output streams.
|
# I hope to reduce this when I increse the reliance on output streams.
|
||||||
proc sendResponseChunkBytes(responder: UntypedResponder, payload: Bytes) {.async.} =
|
proc sendResponseChunkBytes(responder: UntypedResponder, payload: Bytes) {.async.} =
|
||||||
|
@ -572,6 +590,11 @@ proc p2pProtocolBackendImpl*(p: P2PProtocol): Backend =
|
||||||
msg.defineThunk quote do:
|
msg.defineThunk quote do:
|
||||||
proc `thunkName`(`daemonVar`: `DaemonAPI`,
|
proc `thunkName`(`daemonVar`: `DaemonAPI`,
|
||||||
`streamVar`: `P2PStream`) {.async, gcsafe.} =
|
`streamVar`: `P2PStream`) {.async, gcsafe.} =
|
||||||
|
when chronicles.runtimeFilteringEnabled:
|
||||||
|
setLogLevel(LogLevel.TRACE)
|
||||||
|
defer: setLogLevel(LogLevel.DEBUG)
|
||||||
|
trace "incoming " & `msgNameLit` & " stream"
|
||||||
|
|
||||||
defer:
|
defer:
|
||||||
`await` safeClose(`streamVar`)
|
`await` safeClose(`streamVar`)
|
||||||
|
|
||||||
|
@ -587,6 +610,7 @@ proc p2pProtocolBackendImpl*(p: P2PProtocol): Backend =
|
||||||
|
|
||||||
var `msgVar`: `msgRecName`
|
var `msgVar`: `msgRecName`
|
||||||
try:
|
try:
|
||||||
|
trace "about to decode incoming msg"
|
||||||
`msgVar` = decode(`Format`, `msgBytesVar`, `msgRecName`)
|
`msgVar` = decode(`Format`, `msgBytesVar`, `msgRecName`)
|
||||||
except SerializationError as `errVar`:
|
except SerializationError as `errVar`:
|
||||||
`await` sendErrorResponse(`peerVar`, `streamVar`, `errVar`,
|
`await` sendErrorResponse(`peerVar`, `streamVar`, `errVar`,
|
||||||
|
@ -603,13 +627,8 @@ proc p2pProtocolBackendImpl*(p: P2PProtocol): Backend =
|
||||||
|
|
||||||
try:
|
try:
|
||||||
`tracing`
|
`tracing`
|
||||||
|
trace "about to execute user handler"
|
||||||
`awaitUserHandler`
|
`awaitUserHandler`
|
||||||
except ResponseSizeLimitReached:
|
|
||||||
# The response size limit is currently handled with an exception in
|
|
||||||
# order to make it easier to switch to an alternative policy when it
|
|
||||||
# will be signalled with an error response code (and to avoid making
|
|
||||||
# the `response` API in the high-level protocols more complicated for now).
|
|
||||||
chronicles.debug "response size limit reached", peer, reqName = `msgNameLit`
|
|
||||||
except CatchableError as `errVar`:
|
except CatchableError as `errVar`:
|
||||||
try:
|
try:
|
||||||
`await` sendErrorResponse(`peerVar`, `streamVar`, ServerError, `errVar`.msg)
|
`await` sendErrorResponse(`peerVar`, `streamVar`, ServerError, `errVar`.msg)
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import
|
import
|
||||||
chronos, web3, json,
|
chronos, web3, json, chronicles,
|
||||||
spec/[datatypes, digest, crypto, beaconstate, helpers],
|
spec/[datatypes, digest, crypto, beaconstate, helpers],
|
||||||
./extras
|
./extras
|
||||||
|
|
||||||
type
|
type
|
||||||
MainchainMonitor* = ref object
|
MainchainMonitor* = ref object
|
||||||
web3Url: string
|
web3Url: string
|
||||||
web3: Web3
|
|
||||||
depositContractAddress: Address
|
depositContractAddress: Address
|
||||||
|
|
||||||
genesisState: ref BeaconState
|
genesisState: ref BeaconState
|
||||||
|
@ -21,6 +20,8 @@ type
|
||||||
eth1Block: BlockHash
|
eth1Block: BlockHash
|
||||||
eth1Data*: Eth1Data
|
eth1Data*: Eth1Data
|
||||||
|
|
||||||
|
runFut: Future[void]
|
||||||
|
|
||||||
QueueElement = (BlockHash, DepositData)
|
QueueElement = (BlockHash, DepositData)
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,32 +40,48 @@ contract(DepositContract):
|
||||||
|
|
||||||
const MIN_GENESIS_TIME = 0
|
const MIN_GENESIS_TIME = 0
|
||||||
|
|
||||||
proc updateEth1Data*(m: MainchainMonitor) {.async.} =
|
proc updateEth1Data(m: MainchainMonitor, count: uint64, root: FixedBytes[32]) =
|
||||||
let ns = m.web3.contractSender(DepositContract, m.depositContractAddress)
|
m.eth1Data.deposit_count = count
|
||||||
|
m.eth1Data.deposit_root.data = array[32, byte](root)
|
||||||
# TODO: use m.eth1Block for web3 calls
|
|
||||||
let cnt = await ns.get_deposit_count().call()
|
|
||||||
let htr = await ns.get_deposit_root().call()
|
|
||||||
m.eth1Data.deposit_count = bytes_to_int(array[8, byte](cnt))
|
|
||||||
m.eth1Data.deposit_root.data = array[32, byte](htr)
|
|
||||||
m.eth1Data.block_hash.data = array[32, byte](m.eth1Block)
|
m.eth1Data.block_hash.data = array[32, byte](m.eth1Block)
|
||||||
|
|
||||||
proc processDeposits(m: MainchainMonitor) {.async.} =
|
proc processDeposits(m: MainchainMonitor, web3: Web3) {.async.} =
|
||||||
while true:
|
while true:
|
||||||
let (blkHash, data) = await m.depositQueue.popFirst()
|
let (blkHash, data) = await m.depositQueue.popFirst()
|
||||||
|
var blk: BlockObject
|
||||||
|
var depositCount: uint64
|
||||||
|
var depositRoot: FixedBytes[32]
|
||||||
|
try:
|
||||||
|
blk = await web3.provider.eth_getBlockByHash(blkHash, false)
|
||||||
|
|
||||||
|
let ns = web3.contractSender(DepositContract, m.depositContractAddress)
|
||||||
|
|
||||||
|
# TODO: use m.eth1Block for web3 calls
|
||||||
|
let cnt = await ns.get_deposit_count().call()
|
||||||
|
depositRoot = await ns.get_deposit_root().call()
|
||||||
|
depositCount = bytes_to_int(array[8, byte](cnt))
|
||||||
|
|
||||||
|
except:
|
||||||
|
# Connection problem? Put the unprocessed deposit back to queue
|
||||||
|
m.depositQueue.addFirstNoWait((blkHash, data))
|
||||||
|
raise
|
||||||
|
|
||||||
|
debug "Got deposit from eth1", pubKey = data.pubKey
|
||||||
|
|
||||||
let blk = await m.web3.provider.eth_getBlockByHash(blkHash, false)
|
|
||||||
let dep = datatypes.Deposit(data: data)
|
let dep = datatypes.Deposit(data: data)
|
||||||
m.pendingDeposits.add(dep)
|
m.pendingDeposits.add(dep)
|
||||||
inc m.depositCount
|
inc m.depositCount
|
||||||
m.eth1Block = blkHash
|
m.eth1Block = blkHash
|
||||||
|
|
||||||
if m.pendingDeposits.len >= SLOTS_PER_EPOCH and m.pendingDeposits.len >= MIN_GENESIS_ACTIVE_VALIDATOR_COUNT and blk.timestamp.uint64 >= MIN_GENESIS_TIME.uint64:
|
if m.pendingDeposits.len >= SLOTS_PER_EPOCH and
|
||||||
|
m.pendingDeposits.len >= MIN_GENESIS_ACTIVE_VALIDATOR_COUNT and
|
||||||
|
blk.timestamp.uint64 >= MIN_GENESIS_TIME.uint64:
|
||||||
# This block is a genesis candidate
|
# This block is a genesis candidate
|
||||||
var h: Eth2Digest
|
var h: Eth2Digest
|
||||||
h.data = array[32, byte](blkHash)
|
h.data = array[32, byte](blkHash)
|
||||||
let startTime = blk.timestamp.uint64
|
let startTime = blk.timestamp.uint64
|
||||||
var s = initialize_beacon_state_from_eth1(h, startTime, m.pendingDeposits, {skipValidation})
|
var s = initialize_beacon_state_from_eth1(
|
||||||
|
h, startTime, m.pendingDeposits, {skipValidation})
|
||||||
|
|
||||||
if is_valid_genesis_state(s):
|
if is_valid_genesis_state(s):
|
||||||
# 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
|
||||||
|
@ -77,13 +94,13 @@ proc processDeposits(m: MainchainMonitor) {.async.} =
|
||||||
m.genesisStateFut.complete()
|
m.genesisStateFut.complete()
|
||||||
m.genesisStateFut = nil
|
m.genesisStateFut = nil
|
||||||
# TODO: Set curBlock to blk number
|
# TODO: Set curBlock to blk number
|
||||||
|
|
||||||
# TODO: This should be progressing in more independent way.
|
# TODO: This should be progressing in more independent way.
|
||||||
# The Eth1 cross-link can advance even when there are no new deposits.
|
# The Eth1 cross-link can advance even when there are no new deposits.
|
||||||
await m.updateEth1Data
|
m.updateEth1Data(depositCount, depositRoot)
|
||||||
|
|
||||||
proc isRunning*(m: MainchainMonitor): bool =
|
proc isRunning*(m: MainchainMonitor): bool =
|
||||||
not m.web3.isNil
|
not m.runFut.isNil
|
||||||
|
|
||||||
proc getGenesis*(m: MainchainMonitor): Future[BeaconState] {.async.} =
|
proc getGenesis*(m: MainchainMonitor): Future[BeaconState] {.async.} =
|
||||||
if m.genesisState.isNil:
|
if m.genesisState.isNil:
|
||||||
|
@ -95,11 +112,33 @@ proc getGenesis*(m: MainchainMonitor): Future[BeaconState] {.async.} =
|
||||||
doAssert(not m.genesisState.isNil)
|
doAssert(not m.genesisState.isNil)
|
||||||
return m.genesisState[]
|
return m.genesisState[]
|
||||||
|
|
||||||
proc run(m: MainchainMonitor) {.async.} =
|
proc getBlockNumber(web3: Web3, hash: BlockHash): Future[Quantity] {.async.} =
|
||||||
m.web3 = await newWeb3(m.web3Url)
|
let blk = await web3.provider.eth_getBlockByHash(hash, false)
|
||||||
let ns = m.web3.contractSender(DepositContract, m.depositContractAddress)
|
return blk.number
|
||||||
|
|
||||||
let s = await ns.subscribe(DepositEvent, %*{"fromBlock": m.eth1Block}) do(pubkey: Bytes48, withdrawalCredentials: Bytes32, amount: Bytes8, signature: Bytes96, merkleTreeIndex: Bytes8, j: JsonNode):
|
proc run(m: MainchainMonitor, delayBeforeStart: Duration) {.async.} =
|
||||||
|
if delayBeforeStart != ZeroDuration:
|
||||||
|
await sleepAsync(delayBeforeStart)
|
||||||
|
|
||||||
|
let web3 = await newWeb3(m.web3Url)
|
||||||
|
defer: await web3.close()
|
||||||
|
|
||||||
|
let processFut = m.processDeposits(web3)
|
||||||
|
|
||||||
|
web3.onDisconnect = proc() =
|
||||||
|
error "Web3 server disconnected", ulr = m.web3Url
|
||||||
|
processFut.cancel()
|
||||||
|
|
||||||
|
let startBlkNum = await web3.getBlockNumber(m.eth1Block)
|
||||||
|
debug "Starting eth1 monitor", fromBlock = startBlkNum.uint64
|
||||||
|
|
||||||
|
let ns = web3.contractSender(DepositContract, m.depositContractAddress)
|
||||||
|
|
||||||
|
let s = await ns.subscribe(DepositEvent, %*{"fromBlock": startBlkNum}) do(
|
||||||
|
pubkey: Bytes48,
|
||||||
|
withdrawalCredentials: Bytes32,
|
||||||
|
amount: Bytes8,
|
||||||
|
signature: Bytes96, merkleTreeIndex: Bytes8, j: JsonNode):
|
||||||
|
|
||||||
let blkHash = BlockHash.fromHex(j["blockHash"].getStr())
|
let blkHash = BlockHash.fromHex(j["blockHash"].getStr())
|
||||||
let amount = bytes_to_int(array[8, byte](amount))
|
let amount = bytes_to_int(array[8, byte](amount))
|
||||||
|
@ -111,14 +150,27 @@ proc run(m: MainchainMonitor) {.async.} =
|
||||||
signature: ValidatorSig.init(array[96, byte](signature)))))
|
signature: ValidatorSig.init(array[96, byte](signature)))))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await m.processDeposits()
|
await processFut
|
||||||
finally:
|
finally:
|
||||||
await s.unsubscribe()
|
await s.unsubscribe()
|
||||||
# await m.web3.close()
|
|
||||||
m.web3 = nil
|
|
||||||
|
|
||||||
proc start*(m: MainchainMonitor) =
|
proc start(m: MainchainMonitor, delayBeforeStart: Duration) =
|
||||||
asyncCheck m.run()
|
if m.runFut.isNil:
|
||||||
|
let runFut = m.run(delayBeforeStart)
|
||||||
|
m.runFut = runFut
|
||||||
|
runFut.addCallback() do(p: pointer):
|
||||||
|
if runFut.failed and runFut == m.runFut:
|
||||||
|
error "Mainchain monitor failure, restarting", err = runFut.error.msg
|
||||||
|
m.runFut = nil
|
||||||
|
m.start(5.seconds)
|
||||||
|
|
||||||
|
proc start*(m: MainchainMonitor) {.inline.} =
|
||||||
|
m.start(0.seconds)
|
||||||
|
|
||||||
|
proc stop*(m: MainchainMonitor) =
|
||||||
|
if not m.runFut.isNil:
|
||||||
|
m.runFut.cancel()
|
||||||
|
m.runFut = nil
|
||||||
|
|
||||||
proc getPendingDeposits*(m: MainchainMonitor): seq[Deposit] =
|
proc getPendingDeposits*(m: MainchainMonitor): seq[Deposit] =
|
||||||
# This should be a simple accessor for the reference kept above
|
# This should be a simple accessor for the reference kept above
|
||||||
|
|
|
@ -5,6 +5,10 @@ import
|
||||||
eth2_network, beacon_node_types, sync_protocol,
|
eth2_network, beacon_node_types, sync_protocol,
|
||||||
eth/async_utils
|
eth/async_utils
|
||||||
|
|
||||||
|
type
|
||||||
|
RequestManager* = object
|
||||||
|
network*: Eth2Node
|
||||||
|
|
||||||
proc init*(T: type RequestManager, network: Eth2Node): T =
|
proc init*(T: type RequestManager, network: Eth2Node): T =
|
||||||
T(network: network)
|
T(network: network)
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
@ -11,7 +11,7 @@ import
|
||||||
../extras, ../ssz,
|
../extras, ../ssz,
|
||||||
./crypto, ./datatypes, ./digest, ./helpers, ./validator
|
./crypto, ./datatypes, ./digest, ./helpers, ./validator
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#is_valid_merkle_branch
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#is_valid_merkle_branch
|
||||||
func is_valid_merkle_branch*(leaf: Eth2Digest, branch: openarray[Eth2Digest], depth: uint64, index: uint64, root: Eth2Digest): bool =
|
func is_valid_merkle_branch*(leaf: Eth2Digest, branch: openarray[Eth2Digest], depth: uint64, index: uint64, root: Eth2Digest): bool =
|
||||||
## Check if ``leaf`` at ``index`` verifies against the Merkle ``root`` and
|
## Check if ``leaf`` at ``index`` verifies against the Merkle ``root`` and
|
||||||
## ``branch``.
|
## ``branch``.
|
||||||
|
@ -29,13 +29,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.9.1/specs/core/0_beacon-chain.md#increase_balance
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#decrease_balance
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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
|
||||||
|
@ -46,7 +46,7 @@ func decrease_balance*(
|
||||||
else:
|
else:
|
||||||
state.balances[index] - delta
|
state.balances[index] - delta
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#deposits
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.8.4/specs/core/0_beacon-chain.md#deposits
|
||||||
func process_deposit*(
|
func process_deposit*(
|
||||||
state: var BeaconState, deposit: Deposit, flags: UpdateFlags = {}): bool =
|
state: var BeaconState, deposit: Deposit, flags: UpdateFlags = {}): bool =
|
||||||
# Process an Eth1 deposit, registering a validator or increasing its balance.
|
# Process an Eth1 deposit, registering a validator or increasing its balance.
|
||||||
|
@ -102,13 +102,13 @@ func process_deposit*(
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#compute_activation_exit_epoch
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#get_validator_churn_limit
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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 =
|
||||||
|
@ -116,7 +116,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.9.1/specs/core/0_beacon-chain.md#initiate_validator_exit
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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``.
|
||||||
|
@ -146,13 +146,23 @@ func initiate_validator_exit*(state: var BeaconState,
|
||||||
validator.withdrawable_epoch =
|
validator.withdrawable_epoch =
|
||||||
validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#slash_validator
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#slash_validator
|
||||||
func slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex,
|
proc slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex,
|
||||||
stateCache: var StateCache) =
|
stateCache: var StateCache) =
|
||||||
# Slash the validator with index ``index``.
|
# Slash the validator with index ``index``.
|
||||||
let epoch = get_current_epoch(state)
|
let epoch = get_current_epoch(state)
|
||||||
initiate_validator_exit(state, slashed_index)
|
initiate_validator_exit(state, slashed_index)
|
||||||
let validator = addr state.validators[slashed_index]
|
let validator = addr state.validators[slashed_index]
|
||||||
|
|
||||||
|
debug "slash_validator: ejecting validator via slashing (validator_leaving)",
|
||||||
|
index = slashed_index,
|
||||||
|
num_validators = state.validators.len,
|
||||||
|
current_epoch = get_current_epoch(state),
|
||||||
|
validator_slashed = validator.slashed,
|
||||||
|
validator_withdrawable_epoch = validator.withdrawable_epoch,
|
||||||
|
validator_exit_epoch = validator.exit_epoch,
|
||||||
|
validator_effective_balance = validator.effective_balance
|
||||||
|
|
||||||
validator.slashed = true
|
validator.slashed = true
|
||||||
validator.withdrawable_epoch =
|
validator.withdrawable_epoch =
|
||||||
max(validator.withdrawable_epoch, epoch + EPOCHS_PER_SLASHINGS_VECTOR)
|
max(validator.withdrawable_epoch, epoch + EPOCHS_PER_SLASHINGS_VECTOR)
|
||||||
|
@ -174,7 +184,7 @@ func 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.8.4/specs/core/0_beacon-chain.md#genesis
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#genesis
|
||||||
func initialize_beacon_state_from_eth1*(
|
func initialize_beacon_state_from_eth1*(
|
||||||
eth1_block_hash: Eth2Digest,
|
eth1_block_hash: Eth2Digest,
|
||||||
eth1_timestamp: uint64,
|
eth1_timestamp: uint64,
|
||||||
|
@ -213,14 +223,18 @@ func initialize_beacon_state_from_eth1*(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Process deposits
|
# Seed RANDAO with Eth1 entropy
|
||||||
let leaves = deposits.mapIt(it.data)
|
state.randao_mixes.fill(eth1_block_hash)
|
||||||
for i, deposit in deposits:
|
|
||||||
let deposit_data_list = leaves[0..i]
|
|
||||||
state.eth1_data.deposit_root = hash_tree_root(
|
|
||||||
sszList(deposit_data_list, 2'i64^DEPOSIT_CONTRACT_TREE_DEPTH))
|
|
||||||
|
|
||||||
discard process_deposit(state, deposit, flags)
|
# Process deposits
|
||||||
|
let
|
||||||
|
leaves = deposits.mapIt(it.data)
|
||||||
|
var i = 0
|
||||||
|
for prefix_root in hash_tree_roots_prefix(
|
||||||
|
leaves, 2'i64^DEPOSIT_CONTRACT_TREE_DEPTH):
|
||||||
|
state.eth1_data.deposit_root = prefix_root
|
||||||
|
discard process_deposit(state, deposits[i], flags)
|
||||||
|
i += 1
|
||||||
|
|
||||||
# Process activations
|
# Process activations
|
||||||
for validator_index in 0 ..< state.validators.len:
|
for validator_index in 0 ..< state.validators.len:
|
||||||
|
@ -237,7 +251,7 @@ func initialize_beacon_state_from_eth1*(
|
||||||
|
|
||||||
state
|
state
|
||||||
|
|
||||||
proc is_valid_genesis_state*(state: BeaconState): bool =
|
func is_valid_genesis_state*(state: BeaconState): bool =
|
||||||
if state.genesis_time < MIN_GENESIS_TIME:
|
if state.genesis_time < MIN_GENESIS_TIME:
|
||||||
return false
|
return false
|
||||||
if len(get_active_validator_indices(state, GENESIS_EPOCH)) < MIN_GENESIS_ACTIVE_VALIDATOR_COUNT:
|
if len(get_active_validator_indices(state, GENESIS_EPOCH)) < MIN_GENESIS_ACTIVE_VALIDATOR_COUNT:
|
||||||
|
@ -258,7 +272,7 @@ func get_initial_beacon_block*(state: BeaconState): BeaconBlock =
|
||||||
# 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.9.1/specs/core/0_beacon-chain.md#get_block_root_at_slot
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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``.
|
||||||
|
@ -267,12 +281,12 @@ 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.9.1/specs/core/0_beacon-chain.md#get_block_root
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#get_total_balance
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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``. (1 Gwei minimum
|
||||||
## to avoid divisions by zero.)
|
## to avoid divisions by zero.)
|
||||||
|
@ -281,8 +295,8 @@ func get_total_balance*(state: BeaconState, validators: auto): Gwei =
|
||||||
)
|
)
|
||||||
|
|
||||||
# XXX: Move to state_transition_epoch.nim?
|
# XXX: Move to state_transition_epoch.nim?
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#registry-updates
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#registry-updates
|
||||||
func process_registry_updates*(state: var BeaconState) =
|
proc process_registry_updates*(state: var BeaconState) =
|
||||||
## Process activation eligibility and ejections
|
## Process activation eligibility and ejections
|
||||||
## Try to avoid caching here, since this could easily become undefined
|
## Try to avoid caching here, since this could easily become undefined
|
||||||
|
|
||||||
|
@ -294,6 +308,14 @@ func process_registry_updates*(state: var BeaconState) =
|
||||||
|
|
||||||
if is_active_validator(validator, get_current_epoch(state)) and
|
if is_active_validator(validator, get_current_epoch(state)) and
|
||||||
validator.effective_balance <= EJECTION_BALANCE:
|
validator.effective_balance <= EJECTION_BALANCE:
|
||||||
|
debug "Registry updating: ejecting validator due to low balance (validator_leaving)",
|
||||||
|
index = index,
|
||||||
|
num_validators = state.validators.len,
|
||||||
|
current_epoch = get_current_epoch(state),
|
||||||
|
validator_slashed = validator.slashed,
|
||||||
|
validator_withdrawable_epoch = validator.withdrawable_epoch,
|
||||||
|
validator_exit_epoch = validator.exit_epoch,
|
||||||
|
validator_effective_balance = validator.effective_balance
|
||||||
initiate_validator_exit(state, index.ValidatorIndex)
|
initiate_validator_exit(state, index.ValidatorIndex)
|
||||||
|
|
||||||
## Queue validators eligible for activation and not dequeued for activation
|
## Queue validators eligible for activation and not dequeued for activation
|
||||||
|
@ -321,7 +343,7 @@ func process_registry_updates*(state: var BeaconState) =
|
||||||
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.1/specs/core/0_beacon-chain.md#is_valid_indexed_attestation
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#is_valid_indexed_attestation
|
||||||
proc is_valid_indexed_attestation*(
|
proc is_valid_indexed_attestation*(
|
||||||
state: BeaconState, indexed_attestation: IndexedAttestation): bool =
|
state: BeaconState, indexed_attestation: IndexedAttestation): bool =
|
||||||
## Check if ``indexed_attestation`` has valid indices and signature.
|
## Check if ``indexed_attestation`` has valid indices and signature.
|
||||||
|
@ -342,17 +364,19 @@ proc is_valid_indexed_attestation*(
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Verify aggregate signature
|
# Verify aggregate signature
|
||||||
result = bls_verify(
|
if not bls_verify(
|
||||||
bls_aggregate_pubkeys(mapIt(indices, state.validators[it.int].pubkey)),
|
bls_aggregate_pubkeys(mapIt(indices, state.validators[it.int].pubkey)),
|
||||||
hash_tree_root(indexed_attestation.data).data,
|
hash_tree_root(indexed_attestation.data).data,
|
||||||
indexed_attestation.signature,
|
indexed_attestation.signature,
|
||||||
get_domain(
|
get_domain(
|
||||||
state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch)
|
state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch)
|
||||||
)
|
):
|
||||||
if not result:
|
|
||||||
notice "indexed attestation: signature verification failure"
|
notice "indexed attestation: signature verification failure"
|
||||||
|
return false
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#get_attesting_indices
|
true
|
||||||
|
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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,
|
||||||
|
@ -365,8 +389,8 @@ func get_attesting_indices*(state: BeaconState,
|
||||||
if bits[i]:
|
if bits[i]:
|
||||||
result.incl index
|
result.incl index
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#get_indexed_attestation
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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
|
||||||
|
@ -389,7 +413,7 @@ func get_indexed_attestation*(state: BeaconState, attestation: Attestation,
|
||||||
signature: attestation.signature
|
signature: attestation.signature
|
||||||
)
|
)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#attestations
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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 =
|
||||||
|
@ -486,7 +510,7 @@ proc process_attestation*(
|
||||||
else:
|
else:
|
||||||
false
|
false
|
||||||
|
|
||||||
proc makeAttestationData*(
|
func makeAttestationData*(
|
||||||
state: BeaconState, slot: Slot, committee_index: uint64,
|
state: BeaconState, slot: Slot, committee_index: uint64,
|
||||||
beacon_block_root: Eth2Digest): AttestationData =
|
beacon_block_root: Eth2Digest): AttestationData =
|
||||||
## Create an attestation / vote for the block `beacon_block_root` using the
|
## Create an attestation / vote for the block `beacon_block_root` using the
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# At the time of writing, the exact definitions of what should be used for
|
# At the time of writing, the exact definitions of what should be used for
|
||||||
|
@ -122,7 +122,7 @@ func shortLog*(x: BlsValue): string =
|
||||||
func shortLog*(x: BlsCurveType): string =
|
func shortLog*(x: BlsCurveType): string =
|
||||||
($x)[0..7]
|
($x)[0..7]
|
||||||
|
|
||||||
proc hash*(x: BlsValue): Hash {.inline.} =
|
func hash*(x: BlsValue): Hash {.inline.} =
|
||||||
if x.kind == Real:
|
if x.kind == Real:
|
||||||
hash x.blsValue.getBytes()
|
hash x.blsValue.getBytes()
|
||||||
else:
|
else:
|
||||||
|
@ -145,27 +145,27 @@ func pubKey*(pk: ValidatorPrivKey): ValidatorPubKey =
|
||||||
else:
|
else:
|
||||||
pk.getKey
|
pk.getKey
|
||||||
|
|
||||||
proc init(T: type VerKey): VerKey =
|
func init(T: type VerKey): VerKey =
|
||||||
result.point.inf()
|
result.point.inf()
|
||||||
|
|
||||||
proc init(T: type SigKey): SigKey =
|
func init(T: type SigKey): SigKey =
|
||||||
result.point.inf()
|
result.point.inf()
|
||||||
|
|
||||||
proc combine*[T](values: openarray[BlsValue[T]]): BlsValue[T] =
|
func combine*[T](values: openarray[BlsValue[T]]): BlsValue[T] =
|
||||||
result = BlsValue[T](kind: Real, blsValue: T.init())
|
result = BlsValue[T](kind: Real, blsValue: T.init())
|
||||||
|
|
||||||
for value in values:
|
for value in values:
|
||||||
result.blsValue.combine(value.blsValue)
|
result.blsValue.combine(value.blsValue)
|
||||||
|
|
||||||
proc combine*[T](x: var BlsValue[T], other: BlsValue[T]) =
|
func combine*[T](x: var BlsValue[T], other: BlsValue[T]) =
|
||||||
doAssert x.kind == Real and other.kind == Real
|
doAssert x.kind == Real and other.kind == Real
|
||||||
x.blsValue.combine(other.blsValue)
|
x.blsValue.combine(other.blsValue)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/bls_signature.md#bls_aggregate_pubkeys
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/bls_signature.md#bls_aggregate_pubkeys
|
||||||
func bls_aggregate_pubkeys*(keys: openArray[ValidatorPubKey]): ValidatorPubKey =
|
func bls_aggregate_pubkeys*(keys: openArray[ValidatorPubKey]): ValidatorPubKey =
|
||||||
keys.combine()
|
keys.combine()
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/bls_signature.md#bls_verify
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/bls_signature.md#bls_verify
|
||||||
func bls_verify*(
|
func bls_verify*(
|
||||||
pubkey: ValidatorPubKey, msg: openArray[byte], sig: ValidatorSig,
|
pubkey: ValidatorPubKey, msg: openArray[byte], sig: ValidatorSig,
|
||||||
domain: Domain): bool =
|
domain: Domain): bool =
|
||||||
|
@ -215,7 +215,7 @@ func fromBytes*[T](R: type BlsValue[T], bytes: openarray[byte]): R =
|
||||||
if not success:
|
if not success:
|
||||||
# TODO: chronicles trace
|
# TODO: chronicles trace
|
||||||
result = R(kind: OpaqueBlob)
|
result = R(kind: OpaqueBlob)
|
||||||
assert result.blob.len == bytes.len
|
doAssert result.blob.len == bytes.len
|
||||||
result.blob[result.blob.low .. result.blob.high] = bytes
|
result.blob[result.blob.low .. result.blob.high] = bytes
|
||||||
|
|
||||||
func fromHex*[T](R: type BlsValue[T], hexStr: string): R =
|
func fromHex*[T](R: type BlsValue[T], hexStr: string): R =
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# This file contains data types that are part of the spec and thus subject to
|
# This file contains data types that are part of the spec and thus subject to
|
||||||
|
@ -52,13 +52,13 @@ else:
|
||||||
{.fatal: "Preset \"" & const_preset ".nim\" is not supported.".}
|
{.fatal: "Preset \"" & const_preset ".nim\" is not supported.".}
|
||||||
|
|
||||||
const
|
const
|
||||||
SPEC_VERSION* = "0.9.1" ## \
|
SPEC_VERSION* = "0.9.2" ## \
|
||||||
## Spec version we're aiming to be compatible with, right now
|
## Spec version we're aiming to be compatible with, right now
|
||||||
## TODO: improve this scheme once we can negotiate versions in protocol
|
## TODO: improve this scheme once we can negotiate versions in protocol
|
||||||
|
|
||||||
# Initial values
|
# Initial values
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#initial-values
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#initial-values
|
||||||
GENESIS_EPOCH* = (GENESIS_SLOT.uint64 div SLOTS_PER_EPOCH).Epoch ##\
|
GENESIS_EPOCH* = (GENESIS_SLOT.uint64 div SLOTS_PER_EPOCH).Epoch ##\
|
||||||
## compute_epoch_at_slot(GENESIS_SLOT)
|
## compute_epoch_at_slot(GENESIS_SLOT)
|
||||||
|
|
||||||
|
@ -67,11 +67,34 @@ const
|
||||||
# Not part of spec. Still useful, pending removing usage if appropriate.
|
# Not part of spec. Still useful, pending removing usage if appropriate.
|
||||||
ZERO_HASH* = Eth2Digest()
|
ZERO_HASH* = Eth2Digest()
|
||||||
|
|
||||||
|
# Not part of spec
|
||||||
|
WEAK_SUBJECTVITY_PERIOD* =
|
||||||
|
Slot(uint64(4 * 30 * 24 * 60 * 60) div SECONDS_PER_SLOT)
|
||||||
|
# TODO: This needs revisiting.
|
||||||
|
# Why was the validator WITHDRAWAL_PERIOD altered in the spec?
|
||||||
|
|
||||||
template maxSize*(n: int) {.pragma.}
|
template maxSize*(n: int) {.pragma.}
|
||||||
|
|
||||||
type
|
type
|
||||||
Bytes = seq[byte]
|
Bytes = seq[byte]
|
||||||
|
|
||||||
|
# Domains
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#domain-types
|
||||||
|
DomainType* {.pure.} = enum
|
||||||
|
DOMAIN_BEACON_PROPOSER = 0
|
||||||
|
DOMAIN_BEACON_ATTESTER = 1
|
||||||
|
DOMAIN_RANDAO = 2
|
||||||
|
DOMAIN_DEPOSIT = 3
|
||||||
|
DOMAIN_VOLUNTARY_EXIT = 4
|
||||||
|
# Phase 1 - Custody game
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/1_custody-game.md#signature-domain-types
|
||||||
|
DOMAIN_CUSTODY_BIT_CHALLENGE = 6
|
||||||
|
# Phase 1 - Sharding
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/1_shard-data-chains.md#signature-domain-types
|
||||||
|
DOMAIN_SHARD_PROPOSER = 128
|
||||||
|
DOMAIN_SHARD_ATTESTER = 129
|
||||||
|
|
||||||
# https://github.com/nim-lang/Nim/issues/574 and be consistent across
|
# https://github.com/nim-lang/Nim/issues/574 and be consistent across
|
||||||
# 32-bit and 64-bit word platforms.
|
# 32-bit and 64-bit word platforms.
|
||||||
# TODO VALIDATOR_REGISTRY_LIMIT is 1 shl 40 in 0.8.3, and
|
# TODO VALIDATOR_REGISTRY_LIMIT is 1 shl 40 in 0.8.3, and
|
||||||
|
@ -84,18 +107,18 @@ type
|
||||||
|
|
||||||
BitList*[maxLen: static int] = distinct BitSeq
|
BitList*[maxLen: static int] = distinct BitSeq
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#proposerslashing
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#proposerslashing
|
||||||
ProposerSlashing* = object
|
ProposerSlashing* = object
|
||||||
proposer_index*: uint64
|
proposer_index*: uint64
|
||||||
header_1*: BeaconBlockHeader
|
header_1*: BeaconBlockHeader
|
||||||
header_2*: BeaconBlockHeader
|
header_2*: BeaconBlockHeader
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#attesterslashing
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#indexedattestation
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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]
|
||||||
|
@ -104,18 +127,18 @@ type
|
||||||
|
|
||||||
CommitteeValidatorsBits* = BitList[MAX_VALIDATORS_PER_COMMITTEE]
|
CommitteeValidatorsBits* = BitList[MAX_VALIDATORS_PER_COMMITTEE]
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#attestation
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#checkpoint
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#AttestationData
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#AttestationData
|
||||||
AttestationData* = object
|
AttestationData* = object
|
||||||
slot*: Slot
|
slot*: Slot
|
||||||
index*: uint64
|
index*: uint64
|
||||||
|
@ -127,21 +150,21 @@ type
|
||||||
source*: Checkpoint
|
source*: Checkpoint
|
||||||
target*: Checkpoint
|
target*: Checkpoint
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#deposit
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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 data list root
|
## Merkle path to deposit data list root
|
||||||
|
|
||||||
data*: DepositData
|
data*: DepositData
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#depositdata
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#depositdata
|
||||||
DepositData* = object
|
DepositData* = object
|
||||||
pubkey*: ValidatorPubKey
|
pubkey*: ValidatorPubKey
|
||||||
withdrawal_credentials*: Eth2Digest
|
withdrawal_credentials*: Eth2Digest
|
||||||
amount*: uint64
|
amount*: uint64
|
||||||
signature*: ValidatorSig
|
signature*: ValidatorSig
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#voluntaryexit
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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
|
||||||
|
@ -149,7 +172,7 @@ type
|
||||||
validator_index*: uint64
|
validator_index*: uint64
|
||||||
signature*: ValidatorSig
|
signature*: ValidatorSig
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#beaconblock
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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
|
||||||
|
@ -170,7 +193,7 @@ type
|
||||||
signature*: ValidatorSig ##\
|
signature*: ValidatorSig ##\
|
||||||
## Proposer signature
|
## Proposer signature
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#beaconblockheader
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#beaconblockheader
|
||||||
BeaconBlockHeader* = object
|
BeaconBlockHeader* = object
|
||||||
slot*: Slot
|
slot*: Slot
|
||||||
parent_root*: Eth2Digest
|
parent_root*: Eth2Digest
|
||||||
|
@ -178,7 +201,7 @@ type
|
||||||
body_root*: Eth2Digest
|
body_root*: Eth2Digest
|
||||||
signature*: ValidatorSig
|
signature*: ValidatorSig
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#beaconblockbody
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#beaconblockbody
|
||||||
BeaconBlockBody* = object
|
BeaconBlockBody* = object
|
||||||
randao_reveal*: ValidatorSig
|
randao_reveal*: ValidatorSig
|
||||||
eth1_data*: Eth1Data
|
eth1_data*: Eth1Data
|
||||||
|
@ -191,7 +214,7 @@ type
|
||||||
deposits*: List[Deposit, MAX_DEPOSITS]
|
deposits*: List[Deposit, MAX_DEPOSITS]
|
||||||
voluntary_exits*: List[VoluntaryExit, MAX_VOLUNTARY_EXITS]
|
voluntary_exits*: List[VoluntaryExit, MAX_VOLUNTARY_EXITS]
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#beaconstate
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#beaconstate
|
||||||
BeaconState* = object
|
BeaconState* = object
|
||||||
# Versioning
|
# Versioning
|
||||||
genesis_time*: uint64
|
genesis_time*: uint64
|
||||||
|
@ -243,7 +266,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.9.1/specs/core/0_beacon-chain.md#validator
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#validator
|
||||||
Validator* = object
|
Validator* = object
|
||||||
pubkey*: ValidatorPubKey
|
pubkey*: ValidatorPubKey
|
||||||
|
|
||||||
|
@ -266,7 +289,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.9.1/specs/core/0_beacon-chain.md#pendingattestation
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#pendingattestation
|
||||||
PendingAttestation* = object
|
PendingAttestation* = object
|
||||||
aggregation_bits*: CommitteeValidatorsBits
|
aggregation_bits*: CommitteeValidatorsBits
|
||||||
data*: AttestationData
|
data*: AttestationData
|
||||||
|
@ -276,12 +299,12 @@ type
|
||||||
|
|
||||||
proposer_index*: uint64
|
proposer_index*: uint64
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#historicalbatch
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#fork
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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
|
||||||
|
@ -291,7 +314,7 @@ type
|
||||||
epoch*: Epoch ##\
|
epoch*: Epoch ##\
|
||||||
## Epoch of latest fork
|
## Epoch of latest fork
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#eth1data
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#eth1data
|
||||||
Eth1Data* = object
|
Eth1Data* = object
|
||||||
deposit_root*: Eth2Digest
|
deposit_root*: Eth2Digest
|
||||||
deposit_count*: uint64
|
deposit_count*: uint64
|
||||||
|
@ -352,15 +375,20 @@ macro fieldMaxLen*(x: typed): untyped =
|
||||||
return newLit(0)
|
return newLit(0)
|
||||||
|
|
||||||
let size = case $x[1]
|
let size = case $x[1]
|
||||||
|
# Obsolete
|
||||||
of "pubkeys",
|
of "pubkeys",
|
||||||
"compact_validators",
|
"compact_validators",
|
||||||
"aggregation_bits",
|
"aggregation_bits",
|
||||||
"custody_bits": int64(MAX_VALIDATORS_PER_COMMITTEE)
|
"custody_bits": int64(MAX_VALIDATORS_PER_COMMITTEE)
|
||||||
|
# IndexedAttestation
|
||||||
|
of "attesting_indices": MAX_VALIDATORS_PER_COMMITTEE
|
||||||
|
# BeaconBlockBody
|
||||||
of "proposer_slashings": MAX_PROPOSER_SLASHINGS
|
of "proposer_slashings": MAX_PROPOSER_SLASHINGS
|
||||||
of "attester_slashings": MAX_ATTESTER_SLASHINGS
|
of "attester_slashings": MAX_ATTESTER_SLASHINGS
|
||||||
of "attestations": MAX_ATTESTATIONS
|
of "attestations": MAX_ATTESTATIONS
|
||||||
of "deposits": MAX_DEPOSITS
|
of "deposits": MAX_DEPOSITS
|
||||||
of "voluntary_exits": MAX_VOLUNTARY_EXITS
|
of "voluntary_exits": MAX_VOLUNTARY_EXITS
|
||||||
|
# BeaconState
|
||||||
of "historical_roots": HISTORICAL_ROOTS_LIMIT
|
of "historical_roots": HISTORICAL_ROOTS_LIMIT
|
||||||
of "eth1_data_votes": SLOTS_PER_ETH1_VOTING_PERIOD
|
of "eth1_data_votes": SLOTS_PER_ETH1_VOTING_PERIOD
|
||||||
of "validators": VALIDATOR_REGISTRY_LIMIT
|
of "validators": VALIDATOR_REGISTRY_LIMIT
|
||||||
|
@ -424,6 +452,12 @@ template ethTimeUnit(typ: type) {.dirty.} =
|
||||||
proc readValue*(reader: var JsonReader, value: var typ) =
|
proc readValue*(reader: var JsonReader, value: var typ) =
|
||||||
value = typ reader.readValue(uint64)
|
value = typ reader.readValue(uint64)
|
||||||
|
|
||||||
|
proc writeValue*(writer: var JsonWriter, value: ValidatorIndex) =
|
||||||
|
writeValue(writer, uint32 value)
|
||||||
|
|
||||||
|
proc readValue*(reader: var JsonReader, value: var ValidatorIndex) =
|
||||||
|
value = ValidatorIndex reader.readValue(uint32)
|
||||||
|
|
||||||
proc `%`*(i: uint64): JsonNode =
|
proc `%`*(i: uint64): JsonNode =
|
||||||
% int(i)
|
% int(i)
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# Serenity hash function / digest
|
# Serenity hash function / digest
|
||||||
#
|
#
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#hash
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#hash
|
||||||
#
|
#
|
||||||
# In Phase 0 the beacon chain is deployed with SHA256 (SHA2-256).
|
# In Phase 0 the beacon chain is deployed with SHA256 (SHA2-256).
|
||||||
# Note that is is different from Keccak256 (often mistakenly called SHA3-256)
|
# Note that is is different from Keccak256 (often mistakenly called SHA3-256)
|
||||||
|
@ -33,7 +33,7 @@ type
|
||||||
|
|
||||||
chronicles.formatIt Eth2Digest:
|
chronicles.formatIt Eth2Digest:
|
||||||
mixin toHex
|
mixin toHex
|
||||||
it.data.toHex(true)
|
it.data.toHex(true)[0..7]
|
||||||
|
|
||||||
func shortLog*(x: Eth2Digest): string =
|
func shortLog*(x: Eth2Digest): string =
|
||||||
x.data.toHex(true)[0..7]
|
x.data.toHex(true)[0..7]
|
||||||
|
@ -50,7 +50,7 @@ func eth2hash*(v: openArray[byte]): Eth2Digest {.inline.} =
|
||||||
ctx.update(v)
|
ctx.update(v)
|
||||||
ctx.finish()
|
ctx.finish()
|
||||||
|
|
||||||
proc update*(ctx: var Sha2Context; digest: Eth2Digest) =
|
func update*(ctx: var Sha2Context; digest: Eth2Digest) =
|
||||||
ctx.update digest.data
|
ctx.update digest.data
|
||||||
|
|
||||||
template withEth2Hash*(body: untyped): Eth2Digest =
|
template withEth2Hash*(body: untyped): Eth2Digest =
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
# Uncategorized helper functions from the spec
|
# Uncategorized helper functions from the spec
|
||||||
|
@ -15,7 +15,7 @@ import
|
||||||
# Internal
|
# Internal
|
||||||
./datatypes, ./digest
|
./datatypes, ./digest
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#integer_squareroot
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#compute_epoch_at_slot
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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 of the given ``slot``.
|
# Return the epoch number of the given ``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.9.1/specs/core/0_beacon-chain.md#compute_start_slot_at_epoch
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#is_active_validator
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#get_active_validator_indices
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#get_committee_count_at_slot
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#get_current_epoch
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#get_randao_mix
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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,30 +114,37 @@ 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.9.1/specs/core/0_beacon-chain.md#compute_domain
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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]): Domain =
|
fork_version: array[4, byte] = [0'u8, 0, 0, 0]): Domain =
|
||||||
result[0..3] = int_to_bytes4(domain_type.uint64)
|
result[0..3] = int_to_bytes4(domain_type.uint64)
|
||||||
result[4..7] = fork_version
|
result[4..7] = fork_version
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#get_domain
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#get_domain
|
||||||
|
|
||||||
|
func get_domain*(
|
||||||
|
fork: Fork, domain_type: DomainType, epoch: Epoch): Domain =
|
||||||
|
## Return the signature domain (fork version concatenated with domain type)
|
||||||
|
## of a message.
|
||||||
|
let
|
||||||
|
fork_version =
|
||||||
|
if epoch < fork.epoch:
|
||||||
|
fork.previous_version
|
||||||
|
else:
|
||||||
|
fork.current_version
|
||||||
|
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, message_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.
|
||||||
let
|
get_domain(state.fork, domain_type, message_epoch)
|
||||||
epoch = message_epoch
|
|
||||||
fork_version = if epoch < state.fork.epoch:
|
|
||||||
state.fork.previous_version
|
|
||||||
else:
|
|
||||||
state.fork.current_version
|
|
||||||
compute_domain(domain_type, fork_version)
|
|
||||||
|
|
||||||
func get_domain*(state: BeaconState, domain_type: DomainType): Domain =
|
func get_domain*(state: BeaconState, domain_type: DomainType): Domain =
|
||||||
get_domain(state, domain_type, get_current_epoch(state))
|
get_domain(state, domain_type, get_current_epoch(state))
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#get_seed
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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 =
|
||||||
# Generate a seed for the given ``epoch``.
|
# Generate a seed for the given ``epoch``.
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# This file contains constants that are part of the spec and thus subject to
|
# This file contains constants that are part of the spec and thus subject to
|
||||||
|
@ -20,7 +20,7 @@ type
|
||||||
const
|
const
|
||||||
# Misc
|
# Misc
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/configs/mainnet.yaml#L6
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/mainnet.yaml#L6
|
||||||
|
|
||||||
MAX_COMMITTEES_PER_SLOT* {.intdefine.} = 64
|
MAX_COMMITTEES_PER_SLOT* {.intdefine.} = 64
|
||||||
|
|
||||||
|
@ -35,24 +35,24 @@ const
|
||||||
## with a Verifiable Delay Function (VDF) will improve committee robustness
|
## with a Verifiable Delay Function (VDF) will improve committee robustness
|
||||||
## and lower the safe minimum committee size.)
|
## and lower the safe minimum committee size.)
|
||||||
|
|
||||||
MAX_VALIDATORS_PER_COMMITTEE* = 2^12 ##\
|
MAX_VALIDATORS_PER_COMMITTEE* = 2048 ##\
|
||||||
## votes
|
## votes
|
||||||
|
|
||||||
MIN_PER_EPOCH_CHURN_LIMIT* = 4
|
MIN_PER_EPOCH_CHURN_LIMIT* = 4
|
||||||
|
|
||||||
CHURN_LIMIT_QUOTIENT* = 2^16
|
CHURN_LIMIT_QUOTIENT* = 2^16
|
||||||
|
|
||||||
SHUFFLE_ROUND_COUNT* = 90
|
SHUFFLE_ROUND_COUNT* = 90
|
||||||
|
MIN_GENESIS_TIME* {.intdefine.} = 1578009600
|
||||||
|
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT* {.intdefine.} = 16384
|
||||||
|
|
||||||
# Constants (TODO: not actually configurable)
|
# Constants (TODO: not actually configurable)
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#constants
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/configs/mainnet.yaml#L33
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/mainnet.yaml#L50
|
||||||
|
|
||||||
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
|
||||||
|
@ -69,16 +69,16 @@ const
|
||||||
|
|
||||||
# Initial values
|
# Initial values
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.8.4/configs/mainnet.yaml#L45
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/mainnet.yaml#L62
|
||||||
|
|
||||||
GENESIS_SLOT* = 0.Slot
|
GENESIS_SLOT* = 0.Slot
|
||||||
BLS_WITHDRAWAL_PREFIX* = 0'u8
|
BLS_WITHDRAWAL_PREFIX* = 0'u8
|
||||||
|
|
||||||
# Time parameters
|
# Time parameters
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.8.4/configs/mainnet.yaml#L52
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/mainnet.yaml#L69
|
||||||
|
|
||||||
SECONDS_PER_SLOT*{.intdefine.} = 12'u64 # Compile with -d:SECONDS_PER_SLOT=1 for 6x faster slots
|
SECONDS_PER_SLOT*{.intdefine.} = 12'u64 # Compile with -d:SECONDS_PER_SLOT=1 for 12x faster slots
|
||||||
## TODO consistent time unit across projects, similar to C++ chrono?
|
## TODO consistent time unit across projects, similar to C++ chrono?
|
||||||
|
|
||||||
MIN_ATTESTATION_INCLUSION_DELAY* = 1 ##\
|
MIN_ATTESTATION_INCLUSION_DELAY* = 1 ##\
|
||||||
|
@ -127,7 +127,7 @@ const
|
||||||
|
|
||||||
# State vector lengths
|
# State vector lengths
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/configs/mainnet.yaml#L81
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/mainnet.yaml#L98
|
||||||
EPOCHS_PER_HISTORICAL_VECTOR* = 65536
|
EPOCHS_PER_HISTORICAL_VECTOR* = 65536
|
||||||
EPOCHS_PER_SLASHINGS_VECTOR* = 8192
|
EPOCHS_PER_SLASHINGS_VECTOR* = 8192
|
||||||
HISTORICAL_ROOTS_LIMIT* = 16777216
|
HISTORICAL_ROOTS_LIMIT* = 16777216
|
||||||
|
@ -135,7 +135,7 @@ const
|
||||||
|
|
||||||
# Reward and penalty quotients
|
# Reward and penalty quotients
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/configs/mainnet.yaml#L93
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/mainnet.yaml#L110
|
||||||
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
|
||||||
|
@ -144,23 +144,41 @@ const
|
||||||
|
|
||||||
# Max operations per block
|
# Max operations per block
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/configs/mainnet.yaml#L107
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/mainnet.yaml#L124
|
||||||
MAX_PROPOSER_SLASHINGS* = 2^4
|
MAX_PROPOSER_SLASHINGS* = 2^4
|
||||||
MAX_ATTESTER_SLASHINGS* = 2^0
|
MAX_ATTESTER_SLASHINGS* = 2^0
|
||||||
MAX_ATTESTATIONS* = 2^7
|
MAX_ATTESTATIONS* = 2^7
|
||||||
MAX_DEPOSITS* = 2^4
|
MAX_DEPOSITS* = 2^4
|
||||||
MAX_VOLUNTARY_EXITS* = 2^4
|
MAX_VOLUNTARY_EXITS* = 2^4
|
||||||
|
|
||||||
MIN_GENESIS_TIME* {.intdefine.} = 0
|
# Fork choice
|
||||||
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT* {.intdefine.} = 99
|
|
||||||
|
|
||||||
type
|
|
||||||
# Domains
|
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#domain-types
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_fork-choice.md#configuration
|
||||||
DomainType* {.pure.} = enum
|
SAFE_SLOTS_TO_UPDATE_JUSTIFIED* = 8 # 96 seconds
|
||||||
DOMAIN_BEACON_PROPOSER = 0
|
|
||||||
DOMAIN_BEACON_ATTESTER = 1
|
# Validators
|
||||||
DOMAIN_RANDAO = 2
|
# ---------------------------------------------------------------
|
||||||
DOMAIN_DEPOSIT = 3
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/validator/0_beacon-chain-validator.md#misc
|
||||||
DOMAIN_VOLUNTARY_EXIT = 4
|
ETH1_FOLLOW_DISTANCE* = 1024 # blocks ~ 4 hours
|
||||||
|
TARGET_AGGREGATORS_PER_COMMITTEE* = 16 # validators
|
||||||
|
RANDOM_SUBNETS_PER_VALIDATOR* = 1 # subnet
|
||||||
|
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION* = 256 # epochs ~ 27 hours
|
||||||
|
|
||||||
|
# Phase 1 - Sharding
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/1_shard-data-chains.md#time-parameters
|
||||||
|
# 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
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/1_custody-game.md#constants
|
||||||
|
# TODO those are included in minimal.yaml but not mainnet.yaml
|
||||||
|
# Why?
|
||||||
|
# EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS* = 4096 # epochs
|
||||||
|
# EPOCHS_PER_CUSTODY_PERIOD* = 4
|
||||||
|
# CUSTODY_PERIOD_TO_RANDAO_PADDING* = 4
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# This file contains constants that are part of the spec and thus subject to
|
# This file contains constants that are part of the spec and thus subject to
|
||||||
|
@ -20,7 +20,7 @@ type
|
||||||
const
|
const
|
||||||
# Misc
|
# Misc
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/configs/minimal.yaml#L4
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/minimal.yaml#L4
|
||||||
|
|
||||||
# Changed
|
# Changed
|
||||||
MAX_COMMITTEES_PER_SLOT* = 4
|
MAX_COMMITTEES_PER_SLOT* = 4
|
||||||
|
@ -34,11 +34,11 @@ const
|
||||||
# Changed
|
# Changed
|
||||||
SHUFFLE_ROUND_COUNT* = 10
|
SHUFFLE_ROUND_COUNT* = 10
|
||||||
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT* {.intdefine.} = 64
|
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT* {.intdefine.} = 64
|
||||||
MIN_GENESIS_TIME* {.intdefine.} = 0
|
MIN_GENESIS_TIME* {.intdefine.} = 1578009600 # 3 Jan, 2020
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#constants
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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
|
||||||
|
@ -47,7 +47,7 @@ const
|
||||||
|
|
||||||
# Gwei values
|
# Gwei values
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/configs/minimal.yaml#L32
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/minimal.yaml#L50
|
||||||
|
|
||||||
# Unchanged
|
# Unchanged
|
||||||
MIN_DEPOSIT_AMOUNT* = 2'u64^0 * 10'u64^9
|
MIN_DEPOSIT_AMOUNT* = 2'u64^0 * 10'u64^9
|
||||||
|
@ -57,7 +57,7 @@ const
|
||||||
|
|
||||||
# Initial values
|
# Initial values
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/configs/minimal.yaml#L44
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/minimal.yaml#L62
|
||||||
|
|
||||||
# Unchanged
|
# Unchanged
|
||||||
GENESIS_SLOT* = 0.Slot
|
GENESIS_SLOT* = 0.Slot
|
||||||
|
@ -65,7 +65,7 @@ const
|
||||||
|
|
||||||
# Time parameters
|
# Time parameters
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.0/configs/minimal.yaml#L51
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/minimal.yaml#L69
|
||||||
# Unchanged
|
# Unchanged
|
||||||
SECONDS_PER_SLOT*{.intdefine.} = 6'u64
|
SECONDS_PER_SLOT*{.intdefine.} = 6'u64
|
||||||
|
|
||||||
|
@ -87,11 +87,13 @@ const
|
||||||
MIN_VALIDATOR_WITHDRAWABILITY_DELAY* = 2'u64^8
|
MIN_VALIDATOR_WITHDRAWABILITY_DELAY* = 2'u64^8
|
||||||
PERSISTENT_COMMITTEE_PERIOD* = 2'u64^11
|
PERSISTENT_COMMITTEE_PERIOD* = 2'u64^11
|
||||||
MAX_EPOCHS_PER_CROSSLINK* = 4
|
MAX_EPOCHS_PER_CROSSLINK* = 4
|
||||||
|
|
||||||
|
# Changed
|
||||||
MIN_EPOCHS_TO_INACTIVITY_PENALTY* = 2'u64^2
|
MIN_EPOCHS_TO_INACTIVITY_PENALTY* = 2'u64^2
|
||||||
|
|
||||||
# State vector lengths
|
# State vector lengths
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/configs/minimal.yaml#L83
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/minimal.yaml#L101
|
||||||
|
|
||||||
# Changed
|
# Changed
|
||||||
EPOCHS_PER_HISTORICAL_VECTOR* = 64
|
EPOCHS_PER_HISTORICAL_VECTOR* = 64
|
||||||
|
@ -101,7 +103,7 @@ const
|
||||||
|
|
||||||
# Reward and penalty quotients
|
# Reward and penalty quotients
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/configs/minimal.yaml#L95
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/minimal.yaml#L113
|
||||||
|
|
||||||
BASE_REWARD_FACTOR* = 2'u64^6
|
BASE_REWARD_FACTOR* = 2'u64^6
|
||||||
WHISTLEBLOWER_REWARD_QUOTIENT* = 2'u64^9
|
WHISTLEBLOWER_REWARD_QUOTIENT* = 2'u64^9
|
||||||
|
@ -111,7 +113,7 @@ const
|
||||||
|
|
||||||
# Max operations per block
|
# Max operations per block
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/configs/minimal.yaml#L109
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/configs/minimal.yaml#L127
|
||||||
|
|
||||||
MAX_PROPOSER_SLASHINGS* = 2^4
|
MAX_PROPOSER_SLASHINGS* = 2^4
|
||||||
MAX_ATTESTER_SLASHINGS* = 2^0
|
MAX_ATTESTER_SLASHINGS* = 2^0
|
||||||
|
@ -119,14 +121,40 @@ const
|
||||||
MAX_DEPOSITS* = 2^4
|
MAX_DEPOSITS* = 2^4
|
||||||
MAX_VOLUNTARY_EXITS* = 2^4
|
MAX_VOLUNTARY_EXITS* = 2^4
|
||||||
|
|
||||||
|
# Fork choice
|
||||||
type
|
|
||||||
# Domains
|
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#domain-types
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_fork-choice.md#configuration
|
||||||
DomainType* {.pure.} = enum
|
|
||||||
DOMAIN_BEACON_PROPOSER = 0
|
# Changed
|
||||||
DOMAIN_BEACON_ATTESTER = 1
|
SAFE_SLOTS_TO_UPDATE_JUSTIFIED* = 2
|
||||||
DOMAIN_RANDAO = 2
|
|
||||||
DOMAIN_DEPOSIT = 3
|
# Validators
|
||||||
DOMAIN_VOLUNTARY_EXIT = 4
|
# ---------------------------------------------------------------
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/validator/0_beacon-chain-validator.md#misc
|
||||||
|
|
||||||
|
# Changed
|
||||||
|
ETH1_FOLLOW_DISTANCE* = 16 # blocks
|
||||||
|
|
||||||
|
# Unchanged
|
||||||
|
TARGET_AGGREGATORS_PER_COMMITTEE* = 16 # validators
|
||||||
|
RANDOM_SUBNETS_PER_VALIDATOR* = 1 # subnet
|
||||||
|
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION* = 256 # epochs ~ 27 hours
|
||||||
|
|
||||||
|
# Phase 1 - Sharding
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/1_shard-data-chains.md#time-parameters
|
||||||
|
# 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
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/1_custody-game.md#constants
|
||||||
|
# TODO those are included in minimal.yaml but not mainnet.yaml
|
||||||
|
# Why?
|
||||||
|
EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS* = 4096 # epochs
|
||||||
|
EPOCHS_PER_CUSTODY_PERIOD* = 4
|
||||||
|
CUSTODY_PERIOD_TO_RANDAO_PADDING* = 4
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# State transition - block processing, as described in
|
# State transition - block processing, as described in
|
||||||
|
@ -43,7 +43,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.9.1/specs/core/0_beacon-chain.md#block-header
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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 =
|
stateCache: var StateCache): bool =
|
||||||
|
@ -98,7 +98,7 @@ proc process_block_header*(
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#randao
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#randao
|
||||||
proc process_randao(
|
proc process_randao(
|
||||||
state: var BeaconState, body: BeaconBlockBody, flags: UpdateFlags,
|
state: var BeaconState, body: BeaconBlockBody, flags: UpdateFlags,
|
||||||
stateCache: var StateCache): bool =
|
stateCache: var StateCache): bool =
|
||||||
|
@ -131,21 +131,21 @@ proc process_randao(
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#eth1-data
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#eth1-data
|
||||||
func process_eth1_data(state: var BeaconState, body: BeaconBlockBody) =
|
func process_eth1_data(state: var BeaconState, body: BeaconBlockBody) =
|
||||||
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 >
|
||||||
SLOTS_PER_ETH1_VOTING_PERIOD:
|
SLOTS_PER_ETH1_VOTING_PERIOD:
|
||||||
state.eth1_data = body.eth1_data
|
state.eth1_data = body.eth1_data
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#is_slashable_validator
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#proposer-slashings
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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 =
|
flags: UpdateFlags, stateCache: var StateCache): bool =
|
||||||
|
@ -204,7 +204,7 @@ proc processProposerSlashings(
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#is_slashable_attestation_data
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#is_slashable_attestation_data
|
||||||
func is_slashable_attestation_data(
|
func is_slashable_attestation_data(
|
||||||
data_1: AttestationData, data_2: AttestationData): bool =
|
data_1: AttestationData, data_2: AttestationData): bool =
|
||||||
## Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG
|
## Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG
|
||||||
|
@ -216,7 +216,7 @@ func is_slashable_attestation_data(
|
||||||
(data_1.source.epoch < data_2.source.epoch and
|
(data_1.source.epoch < data_2.source.epoch and
|
||||||
data_2.target.epoch < data_1.target.epoch)
|
data_2.target.epoch < data_1.target.epoch)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#attester-slashings
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#attester-slashings
|
||||||
proc process_attester_slashing*(
|
proc process_attester_slashing*(
|
||||||
state: var BeaconState,
|
state: var BeaconState,
|
||||||
attester_slashing: AttesterSlashing,
|
attester_slashing: AttesterSlashing,
|
||||||
|
@ -256,7 +256,7 @@ proc process_attester_slashing*(
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#attester-slashings
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#attester-slashings
|
||||||
proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock,
|
proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock,
|
||||||
stateCache: var StateCache): bool =
|
stateCache: var StateCache): bool =
|
||||||
# Process ``AttesterSlashing`` operation.
|
# Process ``AttesterSlashing`` operation.
|
||||||
|
@ -269,8 +269,8 @@ proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock,
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.3/specs/core/0_beacon-chain.md#attestations
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.8.4/specs/core/0_beacon-chain.md#attestations
|
||||||
proc processAttestations*(
|
proc processAttestations(
|
||||||
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
|
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
|
||||||
stateCache: var StateCache): bool =
|
stateCache: var StateCache): bool =
|
||||||
## Each block includes a number of attestations that the proposer chose. Each
|
## Each block includes a number of attestations that the proposer chose. Each
|
||||||
|
@ -291,7 +291,7 @@ proc processAttestations*(
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#deposits
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.8.4/specs/core/0_beacon-chain.md#deposits
|
||||||
proc processDeposits(state: var BeaconState, blck: BeaconBlock): bool =
|
proc processDeposits(state: var BeaconState, blck: BeaconBlock): bool =
|
||||||
if not (len(blck.body.deposits) <= MAX_DEPOSITS):
|
if not (len(blck.body.deposits) <= MAX_DEPOSITS):
|
||||||
notice "processDeposits: too many deposits"
|
notice "processDeposits: too many deposits"
|
||||||
|
@ -304,7 +304,7 @@ proc processDeposits(state: var BeaconState, blck: BeaconBlock): bool =
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#voluntary-exits
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#voluntary-exits
|
||||||
proc process_voluntary_exit*(
|
proc process_voluntary_exit*(
|
||||||
state: var BeaconState,
|
state: var BeaconState,
|
||||||
exit: VoluntaryExit,
|
exit: VoluntaryExit,
|
||||||
|
@ -353,6 +353,15 @@ proc process_voluntary_exit*(
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Initiate exit
|
# Initiate exit
|
||||||
|
debug "Exit: processing voluntary exit (validator_leaving)",
|
||||||
|
index = exit.validator_index,
|
||||||
|
num_validators = state.validators.len,
|
||||||
|
epoch = exit.epoch,
|
||||||
|
current_epoch = get_current_epoch(state),
|
||||||
|
validator_slashed = validator.slashed,
|
||||||
|
validator_withdrawable_epoch = validator.withdrawable_epoch,
|
||||||
|
validator_exit_epoch = validator.exit_epoch,
|
||||||
|
validator_effective_balance = validator.effective_balance
|
||||||
initiate_validator_exit(state, exit.validator_index.ValidatorIndex)
|
initiate_validator_exit(state, exit.validator_index.ValidatorIndex)
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# State transition - epoch processing, as described in
|
# State transition - epoch processing, as described in
|
||||||
|
@ -62,14 +62,14 @@ declareGauge epoch_transition_final_updates, "Epoch transition final updates tim
|
||||||
# Spec
|
# Spec
|
||||||
# --------------------------------------------------------
|
# --------------------------------------------------------
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#get_total_active_balance
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.
|
||||||
return get_total_balance(
|
return 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.9.1/specs/core/0_beacon-chain.md#helper-functions-1
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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)]
|
||||||
|
@ -99,7 +99,7 @@ func get_attesting_balance(
|
||||||
get_total_balance(state, get_unslashed_attesting_indices(
|
get_total_balance(state, get_unslashed_attesting_indices(
|
||||||
state, attestations, stateCache))
|
state, attestations, stateCache))
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#justification-and-finalization
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#justification-and-finalization
|
||||||
proc process_justification_and_finalization*(
|
proc process_justification_and_finalization*(
|
||||||
state: var BeaconState, stateCache: var StateCache) =
|
state: var BeaconState, stateCache: var StateCache) =
|
||||||
|
|
||||||
|
@ -138,11 +138,11 @@ proc process_justification_and_finalization*(
|
||||||
## matter -- in the next epoch, they'll be 2 epochs old, when BeaconState
|
## matter -- in the next epoch, they'll be 2 epochs old, when BeaconState
|
||||||
## tracks current_epoch_attestations and previous_epoch_attestations only
|
## tracks current_epoch_attestations and previous_epoch_attestations only
|
||||||
## per
|
## per
|
||||||
## https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#attestations
|
## https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#attestations
|
||||||
## and `get_matching_source_attestations(...)` via
|
## and `get_matching_source_attestations(...)` via
|
||||||
## https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#helper-functions-1
|
## https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#helper-functions-1
|
||||||
## and
|
## and
|
||||||
## https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#final-updates
|
## https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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=
|
||||||
|
@ -231,7 +231,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.9.1/specs/core/0_beacon-chain.md#rewards-and-penalties-1
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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
|
||||||
|
@ -240,7 +240,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.9.1/specs/core/0_beacon-chain.md#rewards-and-penalties-1
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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]] =
|
tuple[a: seq[Gwei], b: seq[Gwei]] =
|
||||||
let
|
let
|
||||||
|
@ -336,7 +336,7 @@ func get_attestation_deltas(state: BeaconState, stateCache: var StateCache):
|
||||||
|
|
||||||
(rewards, penalties)
|
(rewards, penalties)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#rewards-and-penalties-1
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#rewards-and-penalties-1
|
||||||
func process_rewards_and_penalties(
|
func process_rewards_and_penalties(
|
||||||
state: var BeaconState, cache: var StateCache) =
|
state: var BeaconState, cache: var StateCache) =
|
||||||
if get_current_epoch(state) == GENESIS_EPOCH:
|
if get_current_epoch(state) == GENESIS_EPOCH:
|
||||||
|
@ -348,7 +348,7 @@ func process_rewards_and_penalties(
|
||||||
increase_balance(state, i.ValidatorIndex, rewards[i])
|
increase_balance(state, i.ValidatorIndex, rewards[i])
|
||||||
decrease_balance(state, i.ValidatorIndex, penalties[i])
|
decrease_balance(state, i.ValidatorIndex, penalties[i])
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#slashings
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#slashings
|
||||||
func process_slashings*(state: var BeaconState) =
|
func process_slashings*(state: var BeaconState) =
|
||||||
let
|
let
|
||||||
epoch = get_current_epoch(state)
|
epoch = get_current_epoch(state)
|
||||||
|
@ -365,8 +365,8 @@ func process_slashings*(state: var BeaconState) =
|
||||||
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.9.1/specs/core/0_beacon-chain.md#final-updates
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#final-updates
|
||||||
proc process_final_updates*(state: var BeaconState) =
|
func process_final_updates*(state: var BeaconState) =
|
||||||
let
|
let
|
||||||
current_epoch = get_current_epoch(state)
|
current_epoch = get_current_epoch(state)
|
||||||
next_epoch = current_epoch + 1
|
next_epoch = current_epoch + 1
|
||||||
|
@ -405,7 +405,7 @@ proc process_final_updates*(state: var BeaconState) =
|
||||||
state.previous_epoch_attestations = state.current_epoch_attestations
|
state.previous_epoch_attestations = state.current_epoch_attestations
|
||||||
state.current_epoch_attestations = @[]
|
state.current_epoch_attestations = @[]
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#epoch-processing
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#epoch-processing
|
||||||
proc process_epoch*(state: var BeaconState) =
|
proc process_epoch*(state: var BeaconState) =
|
||||||
# @proc are placeholders
|
# @proc are placeholders
|
||||||
|
|
||||||
|
@ -414,16 +414,16 @@ proc process_epoch*(state: var BeaconState) =
|
||||||
|
|
||||||
var per_epoch_cache = get_empty_per_epoch_cache()
|
var per_epoch_cache = get_empty_per_epoch_cache()
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#justification-and-finalization
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#justification-and-finalization
|
||||||
process_justification_and_finalization(state, per_epoch_cache)
|
process_justification_and_finalization(state, per_epoch_cache)
|
||||||
|
|
||||||
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.9.1/specs/core/0_beacon-chain.md#rewards-and-penalties-1
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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.9.1/specs/core/0_beacon-chain.md#registry-updates
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#registry-updates
|
||||||
# Don't rely on caching here.
|
# Don't rely on caching here.
|
||||||
process_registry_updates(state)
|
process_registry_updates(state)
|
||||||
|
|
||||||
|
@ -434,12 +434,12 @@ proc process_epoch*(state: var BeaconState) =
|
||||||
# @process_reveal_deadlines
|
# @process_reveal_deadlines
|
||||||
# @process_challenge_deadlines
|
# @process_challenge_deadlines
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#slashings
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#slashings
|
||||||
process_slashings(state)
|
process_slashings(state)
|
||||||
|
|
||||||
# @update_period_committee
|
# @update_period_committee
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#final-updates
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#final-updates
|
||||||
process_final_updates(state)
|
process_final_updates(state)
|
||||||
|
|
||||||
# @after_process_final_updates
|
# @after_process_final_updates
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
@ -22,17 +22,17 @@ func shortLog*(x: Checkpoint): string =
|
||||||
# Helpers used in epoch transition and trace-level block transition
|
# Helpers used in epoch transition and trace-level block transition
|
||||||
# --------------------------------------------------------
|
# --------------------------------------------------------
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.8.4/specs/core/0_beacon-chain.md#get_attesting_indices
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#helper-functions-1
|
||||||
# TODO there's another one of these, check for redundancy
|
|
||||||
func get_attesting_indices*(
|
func get_attesting_indices*(
|
||||||
state: BeaconState, attestations: openarray[PendingAttestation],
|
state: BeaconState, attestations: openarray[PendingAttestation],
|
||||||
stateCache: var StateCache): HashSet[ValidatorIndex] =
|
stateCache: var StateCache): HashSet[ValidatorIndex] =
|
||||||
|
# This is part of get_unslashed_attesting_indices(...) in spec.
|
||||||
result = initHashSet[ValidatorIndex]()
|
result = initHashSet[ValidatorIndex]()
|
||||||
for a in attestations:
|
for a in attestations:
|
||||||
result = result.union(get_attesting_indices(
|
result = result.union(get_attesting_indices(
|
||||||
state, a.data, a.aggregation_bits, stateCache))
|
state, a.data, a.aggregation_bits, stateCache))
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.8.4/specs/core/0_beacon-chain.md#helper-functions-1
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#helper-functions-1
|
||||||
func get_unslashed_attesting_indices*(
|
func get_unslashed_attesting_indices*(
|
||||||
state: BeaconState, attestations: openarray[PendingAttestation],
|
state: BeaconState, attestations: openarray[PendingAttestation],
|
||||||
stateCache: var StateCache): HashSet[ValidatorIndex] =
|
stateCache: var StateCache): HashSet[ValidatorIndex] =
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# Helpers and functions pertaining to managing the validator set
|
# Helpers and functions pertaining to managing the validator set
|
||||||
|
@ -11,13 +11,13 @@ import
|
||||||
./datatypes, ./digest, ./helpers
|
./datatypes, ./digest, ./helpers
|
||||||
|
|
||||||
# TODO: Proceed to renaming and signature changes
|
# TODO: Proceed to renaming and signature changes
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#compute_shuffled_index
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#compute_shuffled_index
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#compute_committee
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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] =
|
||||||
## Via https://github.com/protolambda/eth2-shuffle/blob/master/shuffle.go
|
## Via https://github.com/protolambda/eth2-shuffle/blob/master/shuffle.go
|
||||||
## Shuffles ``validators`` into crosslink committees seeded by ``seed`` and
|
## Shuffles ``validators`` into beacon committees, seeded by ``seed`` and
|
||||||
## ``slot``.
|
## ``slot``.
|
||||||
## Returns a list of ``SLOTS_PER_EPOCH * committees_per_slot`` committees
|
## Returns a list of ``SLOTS_PER_EPOCH * committees_per_slot`` committees
|
||||||
## where each committee is itself a list of validator indices.
|
## where each committee is itself a list of validator indices.
|
||||||
|
@ -78,7 +78,7 @@ func get_shuffled_seq*(seed: Eth2Digest,
|
||||||
|
|
||||||
result = shuffled_active_validator_indices
|
result = shuffled_active_validator_indices
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#get_previous_epoch
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#get_previous_epoch
|
||||||
func get_previous_epoch*(state: BeaconState): Epoch =
|
func get_previous_epoch*(state: BeaconState): Epoch =
|
||||||
# Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
|
# Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
|
||||||
let current_epoch = get_current_epoch(state)
|
let current_epoch = get_current_epoch(state)
|
||||||
|
@ -87,7 +87,7 @@ func get_previous_epoch*(state: BeaconState): Epoch =
|
||||||
else:
|
else:
|
||||||
current_epoch - 1
|
current_epoch - 1
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#compute_committee
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#compute_committee
|
||||||
func compute_committee(indices: seq[ValidatorIndex], seed: Eth2Digest,
|
func compute_committee(indices: seq[ValidatorIndex], seed: Eth2Digest,
|
||||||
index: uint64, count: uint64, stateCache: var StateCache): seq[ValidatorIndex] =
|
index: uint64, count: uint64, stateCache: var StateCache): seq[ValidatorIndex] =
|
||||||
## Return the committee corresponding to ``indices``, ``seed``, ``index``,
|
## Return the committee corresponding to ``indices``, ``seed``, ``index``,
|
||||||
|
@ -112,7 +112,7 @@ func compute_committee(indices: seq[ValidatorIndex], seed: Eth2Digest,
|
||||||
start.int .. (endIdx.int-1),
|
start.int .. (endIdx.int-1),
|
||||||
indices[stateCache.beacon_committee_cache[key][it]])
|
indices[stateCache.beacon_committee_cache[key][it]])
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#get_beacon_committee
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#get_beacon_committee
|
||||||
func get_beacon_committee*(state: BeaconState, slot: Slot, index: uint64, cache: var StateCache): seq[ValidatorIndex] =
|
func get_beacon_committee*(state: BeaconState, slot: Slot, index: uint64, cache: var StateCache): seq[ValidatorIndex] =
|
||||||
# Return the beacon committee at ``slot`` for ``index``.
|
# Return the beacon committee at ``slot`` for ``index``.
|
||||||
let
|
let
|
||||||
|
@ -146,8 +146,8 @@ 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.9.1/specs/core/0_beacon-chain.md#compute_proposer_index
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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): ValidatorIndex =
|
seed: Eth2Digest, stateCache: var StateCache): ValidatorIndex =
|
||||||
# Return from ``indices`` a random index sampled by effective balance.
|
# Return from ``indices`` a random index sampled by effective balance.
|
||||||
const MAX_RANDOM_BYTE = 255
|
const MAX_RANDOM_BYTE = 255
|
||||||
|
@ -178,7 +178,7 @@ func compute_proposer_index*(state: BeaconState, indices: seq[ValidatorIndex],
|
||||||
return candidate_index
|
return candidate_index
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#get_beacon_proposer_index
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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):
|
||||||
ValidatorIndex =
|
ValidatorIndex =
|
||||||
# Return the beacon proposer index at the current slot.
|
# Return the beacon proposer index at the current slot.
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
# SSZ Serialization (simple serialize)
|
# SSZ Serialization (simple serialize)
|
||||||
|
@ -269,7 +269,7 @@ template fromSszBytes*[T; N](_: type TypeWithMaxLen[T, N],
|
||||||
mixin fromSszBytes
|
mixin fromSszBytes
|
||||||
fromSszBytes(T, bytes)
|
fromSszBytes(T, bytes)
|
||||||
|
|
||||||
func fromSszBytes*(T: type BlsCurveType, bytes: openarray[byte]): auto =
|
func fromSszBytes(T: type BlsCurveType, bytes: openarray[byte]): auto =
|
||||||
init(T, bytes)
|
init(T, bytes)
|
||||||
|
|
||||||
proc readValue*(r: var SszReader, val: var auto) =
|
proc readValue*(r: var SszReader, val: var auto) =
|
||||||
|
@ -327,7 +327,7 @@ func getZeroHashWithoutSideEffect(idx: int): Eth2Digest =
|
||||||
{.noSideEffect.}:
|
{.noSideEffect.}:
|
||||||
zeroHashes[idx]
|
zeroHashes[idx]
|
||||||
|
|
||||||
func addChunk*(merkelizer: SszChunksMerkelizer, data: openarray[byte]) =
|
func addChunk(merkelizer: SszChunksMerkelizer, data: openarray[byte]) =
|
||||||
doAssert data.len > 0 and data.len <= bytesPerChunk
|
doAssert data.len > 0 and data.len <= bytesPerChunk
|
||||||
|
|
||||||
if not getBitLE(merkelizer.totalChunks, 0):
|
if not getBitLE(merkelizer.totalChunks, 0):
|
||||||
|
@ -350,7 +350,7 @@ func addChunk*(merkelizer: SszChunksMerkelizer, data: openarray[byte]) =
|
||||||
|
|
||||||
inc merkelizer.totalChunks
|
inc merkelizer.totalChunks
|
||||||
|
|
||||||
func getFinalHash*(merkelizer: SszChunksMerkelizer): Eth2Digest =
|
func getFinalHash(merkelizer: SszChunksMerkelizer): Eth2Digest =
|
||||||
let limit = merkelizer.limit
|
let limit = merkelizer.limit
|
||||||
|
|
||||||
if merkelizer.totalChunks == 0:
|
if merkelizer.totalChunks == 0:
|
||||||
|
@ -395,7 +395,7 @@ func getFinalHash*(merkelizer: SszChunksMerkelizer): Eth2Digest =
|
||||||
|
|
||||||
let HashingStreamVTable = OutputStreamVTable(
|
let HashingStreamVTable = OutputStreamVTable(
|
||||||
writePage: proc (s: OutputStreamVar, data: openarray[byte])
|
writePage: proc (s: OutputStreamVar, data: openarray[byte])
|
||||||
{.nimcall, gcsafe, raises: [IOError, Defect].} =
|
{.nimcall, gcsafe, raises: [IOError].} =
|
||||||
trs "ADDING STREAM CHUNK ", data
|
trs "ADDING STREAM CHUNK ", data
|
||||||
SszChunksMerkelizer(s.outputDevice).addChunk(data)
|
SszChunksMerkelizer(s.outputDevice).addChunk(data)
|
||||||
,
|
,
|
||||||
|
@ -407,9 +407,8 @@ func getVtableAddresWithoutSideEffect: ptr OutputStreamVTable =
|
||||||
# TODO this is a work-around for the somewhat broken side
|
# TODO this is a work-around for the somewhat broken side
|
||||||
# effects analysis of Nim - reading from global let variables
|
# effects analysis of Nim - reading from global let variables
|
||||||
# is considered a side-effect.
|
# is considered a side-effect.
|
||||||
# Nim 0.19 doesnt have the `{.noSideEffect.}:` override, so
|
{.noSideEffect.}:
|
||||||
# we should revisit this in Nim 0.20.2.
|
unsafeAddr HashingStreamVTable
|
||||||
{.emit: "`result` = &`HashingStreamVTable`;".}
|
|
||||||
|
|
||||||
func newSszHashingStream(merkelizer: SszChunksMerkelizer): ref OutputStream =
|
func newSszHashingStream(merkelizer: SszChunksMerkelizer): ref OutputStream =
|
||||||
new result
|
new result
|
||||||
|
@ -574,11 +573,23 @@ func hash_tree_root*(x: auto): Eth2Digest =
|
||||||
|
|
||||||
trs "HASH TREE ROOT FOR ", name(type x), " = ", "0x", $result
|
trs "HASH TREE ROOT FOR ", name(type x), " = ", "0x", $result
|
||||||
|
|
||||||
|
iterator hash_tree_roots_prefix*[T](lst: openarray[T], limit: auto):
|
||||||
|
Eth2Digest =
|
||||||
|
# This is a particular type's instantiation of a general fold, reduce,
|
||||||
|
# accumulation, prefix sums, etc family of operations. As long as that
|
||||||
|
# Eth1 deposit case is the only notable example -- the usual uses of a
|
||||||
|
# list involve, at some point, tree-hashing it -- finalized hashes are
|
||||||
|
# the only abstraction that escapes from this module this way.
|
||||||
|
var merkelizer = SszChunksMerkelizer(limit: uint64(limit))
|
||||||
|
for i, elem in lst:
|
||||||
|
merkelizer.addChunk(hash_tree_root(elem).data)
|
||||||
|
yield mixInLength(merkelizer.getFinalHash(), i + 1)
|
||||||
|
|
||||||
func lastFieldName(RecordType: type): string {.compileTime.} =
|
func lastFieldName(RecordType: type): string {.compileTime.} =
|
||||||
enumAllSerializedFields(RecordType):
|
enumAllSerializedFields(RecordType):
|
||||||
result = fieldName
|
result = fieldName
|
||||||
|
|
||||||
func hasSigningRoot*(T: type): bool {.compileTime.} =
|
func hasSigningRoot(T: type): bool {.compileTime.} =
|
||||||
lastFieldName(T) == "signature"
|
lastFieldName(T) == "signature"
|
||||||
|
|
||||||
func signingRoot*(obj: object): Eth2Digest =
|
func signingRoot*(obj: object): Eth2Digest =
|
||||||
|
|
|
@ -60,7 +60,7 @@ func indexableNavigatorImpl[T](m: MemRange, idx: int): MemRange =
|
||||||
getMemRange(typedNavigator[idx])
|
getMemRange(typedNavigator[idx])
|
||||||
|
|
||||||
func fieldNavigatorImpl[RecordType; FieldType;
|
func fieldNavigatorImpl[RecordType; FieldType;
|
||||||
fieldName: static string](m: MemRange): MemRange {.raises: [Defect, MalformedSszError].} =
|
fieldName: static string](m: MemRange): MemRange {.raises: [MalformedSszError].} =
|
||||||
# TODO: Make sure this doesn't fail with a Defect when
|
# TODO: Make sure this doesn't fail with a Defect when
|
||||||
# navigating to an inactive field in a case object.
|
# navigating to an inactive field in a case object.
|
||||||
var typedNavigator = sszMount(m, RecordType)
|
var typedNavigator = sszMount(m, RecordType)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# State transition, as described in
|
# State transition, as described in
|
||||||
|
@ -43,7 +43,7 @@ declareGauge beacon_previous_validators, """Number of status="pending|active|exi
|
||||||
# Canonical state transition functions
|
# Canonical state transition functions
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function
|
||||||
func process_slot*(state: var BeaconState) =
|
func process_slot*(state: var BeaconState) =
|
||||||
# Cache state root
|
# Cache state root
|
||||||
let previous_state_root = hash_tree_root(state)
|
let previous_state_root = hash_tree_root(state)
|
||||||
|
@ -80,7 +80,7 @@ func get_epoch_validator_count(state: BeaconState): int64 =
|
||||||
validator.withdrawable_epoch > get_current_epoch(state):
|
validator.withdrawable_epoch > get_current_epoch(state):
|
||||||
result += 1
|
result += 1
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function
|
||||||
proc process_slots*(state: var BeaconState, slot: Slot) =
|
proc process_slots*(state: var BeaconState, slot: Slot) =
|
||||||
doAssert state.slot <= slot
|
doAssert state.slot <= slot
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ proc process_slots*(state: var BeaconState, slot: Slot) =
|
||||||
if is_epoch_transition:
|
if is_epoch_transition:
|
||||||
beacon_current_validators.set(get_epoch_validator_count(state))
|
beacon_current_validators.set(get_epoch_validator_count(state))
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function
|
||||||
proc verifyStateRoot(state: BeaconState, blck: BeaconBlock): bool =
|
proc verifyStateRoot(state: BeaconState, blck: BeaconBlock): bool =
|
||||||
# This is inlined in state_transition(...) in spec.
|
# This is inlined in state_transition(...) in spec.
|
||||||
let state_root = hash_tree_root(state)
|
let state_root = hash_tree_root(state)
|
||||||
|
@ -170,7 +170,7 @@ proc state_transition*(
|
||||||
# Hashed-state transition functions
|
# Hashed-state transition functions
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function
|
||||||
func process_slot(state: var HashedBeaconState) =
|
func process_slot(state: var HashedBeaconState) =
|
||||||
# Cache state root
|
# Cache state root
|
||||||
let previous_slot_state_root = state.root
|
let previous_slot_state_root = state.root
|
||||||
|
@ -185,7 +185,7 @@ func process_slot(state: var HashedBeaconState) =
|
||||||
state.data.block_roots[state.data.slot mod SLOTS_PER_HISTORICAL_ROOT] =
|
state.data.block_roots[state.data.slot mod SLOTS_PER_HISTORICAL_ROOT] =
|
||||||
signing_root(state.data.latest_block_header)
|
signing_root(state.data.latest_block_header)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function
|
||||||
proc process_slots*(state: var HashedBeaconState, slot: Slot) =
|
proc process_slots*(state: var HashedBeaconState, slot: Slot) =
|
||||||
# TODO: Eth specs strongly assert that state.data.slot <= slot
|
# TODO: Eth specs strongly assert that state.data.slot <= slot
|
||||||
# This prevents receiving attestation in any order
|
# This prevents receiving attestation in any order
|
||||||
|
|
|
@ -49,7 +49,7 @@ func loadLayout(layout: string): Layout {.raises: [Defect, ValueError].} =
|
||||||
result.cellsLeft = loadCellsLayout(sections[0])
|
result.cellsLeft = loadCellsLayout(sections[0])
|
||||||
if sections.len == 2: result.cellsRight = loadCellsLayout(sections[1])
|
if sections.len == 2: result.cellsRight = loadCellsLayout(sections[1])
|
||||||
|
|
||||||
proc updateContent(cell: var StatusBarCell, model: DataItemResolver) =
|
func updateContent(cell: var StatusBarCell, model: DataItemResolver) =
|
||||||
cell.content.setLen 0
|
cell.content.setLen 0
|
||||||
for fragment in cell.contentFragments:
|
for fragment in cell.contentFragments:
|
||||||
case fragment[0]
|
case fragment[0]
|
||||||
|
@ -58,11 +58,11 @@ proc updateContent(cell: var StatusBarCell, model: DataItemResolver) =
|
||||||
of ikExpr, ikVar:
|
of ikExpr, ikVar:
|
||||||
cell.content.add model(fragment[1])
|
cell.content.add model(fragment[1])
|
||||||
|
|
||||||
proc updateCells(cells: var seq[StatusBarCell], model: DataItemResolver) =
|
func updateCells(cells: var seq[StatusBarCell], model: DataItemResolver) =
|
||||||
for cell in mitems(cells):
|
for cell in mitems(cells):
|
||||||
cell.updateContent(model)
|
cell.updateContent(model)
|
||||||
|
|
||||||
proc update*(s: var StatusBarView) =
|
func update*(s: var StatusBarView) =
|
||||||
updateCells s.layout.cellsLeft, s.model
|
updateCells s.layout.cellsLeft, s.model
|
||||||
updateCells s.layout.cellsRight, s.model
|
updateCells s.layout.cellsRight, s.model
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import
|
||||||
options, tables, sets, macros,
|
options, tables, sets, macros,
|
||||||
chronicles, chronos, metrics, stew/ranges/bitranges,
|
chronicles, chronos, metrics, stew/ranges/bitranges,
|
||||||
spec/[datatypes, crypto, digest, helpers], eth/rlp,
|
spec/[datatypes, crypto, digest, helpers], eth/rlp,
|
||||||
beacon_node_types, eth2_network, beacon_chain_db, block_pool, ssz
|
beacon_node_types, eth2_network, block_pool, ssz
|
||||||
|
|
||||||
when networkBackend == rlpxBackend:
|
when networkBackend == rlpxBackend:
|
||||||
import eth/rlp/options as rlpOptions
|
import eth/rlp/options as rlpOptions
|
||||||
|
@ -25,11 +25,11 @@ type
|
||||||
else:
|
else:
|
||||||
index: uint32
|
index: uint32
|
||||||
|
|
||||||
ValidatorSet = seq[Validator]
|
BeaconBlockCallback* = proc(blck: BeaconBlock) {.gcsafe.}
|
||||||
|
|
||||||
BeaconSyncNetworkState* = ref object
|
BeaconSyncNetworkState* = ref object
|
||||||
node*: BeaconNode
|
blockPool*: BlockPool
|
||||||
db*: BeaconChainDB
|
forkVersion*: array[4, byte]
|
||||||
|
onBeaconBlock*: BeaconBlockCallback
|
||||||
|
|
||||||
BeaconSyncPeerState* = ref object
|
BeaconSyncPeerState* = ref object
|
||||||
initialStatusReceived: bool
|
initialStatusReceived: bool
|
||||||
|
@ -40,29 +40,18 @@ type
|
||||||
|
|
||||||
const
|
const
|
||||||
MAX_REQUESTED_BLOCKS = 20'u64
|
MAX_REQUESTED_BLOCKS = 20'u64
|
||||||
MaxAncestorBlocksResponse = 256
|
|
||||||
|
|
||||||
func toHeader(b: BeaconBlock): BeaconBlockHeader =
|
func init*(
|
||||||
BeaconBlockHeader(
|
v: BeaconSyncNetworkState, blockPool: BlockPool,
|
||||||
slot: b.slot,
|
forkVersion: array[4, byte], onBeaconBlock: BeaconBlockCallback) =
|
||||||
parent_root: b.parent_root,
|
v.blockPool = blockPool
|
||||||
state_root: b.state_root,
|
v.forkVersion = forkVersion
|
||||||
body_root: hash_tree_root(b.body),
|
v.onBeaconBlock = onBeaconBlock
|
||||||
signature: b.signature
|
|
||||||
)
|
|
||||||
|
|
||||||
proc fromHeaderAndBody(b: var BeaconBlock, h: BeaconBlockHeader, body: BeaconBlockBody) =
|
proc importBlocks(state: BeaconSyncNetworkState,
|
||||||
doAssert(hash_tree_root(body) == h.body_root)
|
blocks: openarray[BeaconBlock]) {.gcsafe.} =
|
||||||
b.slot = h.slot
|
|
||||||
b.parent_root = h.parent_root
|
|
||||||
b.state_root = h.state_root
|
|
||||||
b.body = body
|
|
||||||
b.signature = h.signature
|
|
||||||
|
|
||||||
proc importBlocks(node: BeaconNode,
|
|
||||||
blocks: openarray[BeaconBlock]) =
|
|
||||||
for blk in blocks:
|
for blk in blocks:
|
||||||
node.onBeaconBlock(node, blk)
|
state.onBeaconBlock(blk)
|
||||||
info "Forward sync imported blocks", len = blocks.len
|
info "Forward sync imported blocks", len = blocks.len
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -73,9 +62,9 @@ type
|
||||||
headRoot*: Eth2Digest
|
headRoot*: Eth2Digest
|
||||||
headSlot*: Slot
|
headSlot*: Slot
|
||||||
|
|
||||||
proc getCurrentStatus(node: BeaconNode): StatusMsg =
|
proc getCurrentStatus(state: BeaconSyncNetworkState): StatusMsg {.gcsafe.} =
|
||||||
let
|
let
|
||||||
blockPool = node.blockPool
|
blockPool = state.blockPool
|
||||||
finalizedHead = blockPool.finalizedHead
|
finalizedHead = blockPool.finalizedHead
|
||||||
headBlock = blockPool.head.blck
|
headBlock = blockPool.head.blck
|
||||||
headRoot = headBlock.root
|
headRoot = headBlock.root
|
||||||
|
@ -83,14 +72,14 @@ proc getCurrentStatus(node: BeaconNode): StatusMsg =
|
||||||
finalizedEpoch = finalizedHead.slot.compute_epoch_at_slot()
|
finalizedEpoch = finalizedHead.slot.compute_epoch_at_slot()
|
||||||
|
|
||||||
StatusMsg(
|
StatusMsg(
|
||||||
fork_version: node.forkVersion,
|
fork_version: state.forkVersion,
|
||||||
finalizedRoot: finalizedHead.blck.root,
|
finalizedRoot: finalizedHead.blck.root,
|
||||||
finalizedEpoch: finalizedEpoch,
|
finalizedEpoch: finalizedEpoch,
|
||||||
headRoot: headRoot,
|
headRoot: headRoot,
|
||||||
headSlot: headSlot)
|
headSlot: headSlot)
|
||||||
|
|
||||||
proc handleInitialStatus(peer: Peer,
|
proc handleInitialStatus(peer: Peer,
|
||||||
node: BeaconNode,
|
state: BeaconSyncNetworkState,
|
||||||
ourStatus: StatusMsg,
|
ourStatus: StatusMsg,
|
||||||
theirStatus: StatusMsg) {.async, gcsafe.}
|
theirStatus: StatusMsg) {.async, gcsafe.}
|
||||||
|
|
||||||
|
@ -102,14 +91,13 @@ p2pProtocol BeaconSync(version = 1,
|
||||||
onPeerConnected do (peer: Peer):
|
onPeerConnected do (peer: Peer):
|
||||||
if peer.wasDialed:
|
if peer.wasDialed:
|
||||||
let
|
let
|
||||||
node = peer.networkState.node
|
ourStatus = peer.networkState.getCurrentStatus()
|
||||||
ourStatus = node.getCurrentStatus
|
|
||||||
# TODO: The timeout here is so high only because we fail to
|
# TODO: The timeout here is so high only because we fail to
|
||||||
# respond in time due to high CPU load in our single thread.
|
# respond in time due to high CPU load in our single thread.
|
||||||
theirStatus = await peer.status(ourStatus, timeout = 60.seconds)
|
theirStatus = await peer.status(ourStatus, timeout = 60.seconds)
|
||||||
|
|
||||||
if theirStatus.isSome:
|
if theirStatus.isSome:
|
||||||
await peer.handleInitialStatus(node, ourStatus, theirStatus.get)
|
await peer.handleInitialStatus(peer.networkState, ourStatus, theirStatus.get)
|
||||||
else:
|
else:
|
||||||
warn "Status response not received in time"
|
warn "Status response not received in time"
|
||||||
|
|
||||||
|
@ -119,14 +107,14 @@ p2pProtocol BeaconSync(version = 1,
|
||||||
requestResponse:
|
requestResponse:
|
||||||
proc status(peer: Peer, theirStatus: StatusMsg) {.libp2pProtocol("status", 1).} =
|
proc status(peer: Peer, theirStatus: StatusMsg) {.libp2pProtocol("status", 1).} =
|
||||||
let
|
let
|
||||||
node = peer.networkState.node
|
ourStatus = peer.networkState.getCurrentStatus()
|
||||||
ourStatus = node.getCurrentStatus
|
|
||||||
|
|
||||||
|
trace "Sending status msg", ourStatus
|
||||||
await response.send(ourStatus)
|
await response.send(ourStatus)
|
||||||
|
|
||||||
if not peer.state.initialStatusReceived:
|
if not peer.state.initialStatusReceived:
|
||||||
peer.state.initialStatusReceived = true
|
peer.state.initialStatusReceived = true
|
||||||
await peer.handleInitialStatus(node, ourStatus, theirStatus)
|
await peer.handleInitialStatus(peer.networkState, ourStatus, theirStatus)
|
||||||
|
|
||||||
proc statusResp(peer: Peer, msg: StatusMsg)
|
proc statusResp(peer: Peer, msg: StatusMsg)
|
||||||
|
|
||||||
|
@ -144,7 +132,7 @@ p2pProtocol BeaconSync(version = 1,
|
||||||
|
|
||||||
if count > 0'u64:
|
if count > 0'u64:
|
||||||
let count = if step != 0: min(count, MAX_REQUESTED_BLOCKS.uint64) else: 1
|
let count = if step != 0: min(count, MAX_REQUESTED_BLOCKS.uint64) else: 1
|
||||||
let pool = peer.networkState.node.blockPool
|
let pool = peer.networkState.blockPool
|
||||||
var results: array[MAX_REQUESTED_BLOCKS, BlockRef]
|
var results: array[MAX_REQUESTED_BLOCKS, BlockRef]
|
||||||
let
|
let
|
||||||
lastPos = min(count.int, results.len) - 1
|
lastPos = min(count.int, results.len) - 1
|
||||||
|
@ -159,8 +147,7 @@ p2pProtocol BeaconSync(version = 1,
|
||||||
blockRoots: openarray[Eth2Digest]) {.
|
blockRoots: openarray[Eth2Digest]) {.
|
||||||
libp2pProtocol("beacon_blocks_by_root", 1).} =
|
libp2pProtocol("beacon_blocks_by_root", 1).} =
|
||||||
let
|
let
|
||||||
pool = peer.networkState.node.blockPool
|
pool = peer.networkState.blockPool
|
||||||
db = peer.networkState.db
|
|
||||||
|
|
||||||
for root in blockRoots:
|
for root in blockRoots:
|
||||||
let blockRef = pool.getRef(root)
|
let blockRef = pool.getRef(root)
|
||||||
|
@ -172,11 +159,13 @@ p2pProtocol BeaconSync(version = 1,
|
||||||
blocks: openarray[BeaconBlock])
|
blocks: openarray[BeaconBlock])
|
||||||
|
|
||||||
proc handleInitialStatus(peer: Peer,
|
proc handleInitialStatus(peer: Peer,
|
||||||
node: BeaconNode,
|
state: BeaconSyncNetworkState,
|
||||||
ourStatus: StatusMsg,
|
ourStatus: StatusMsg,
|
||||||
theirStatus: StatusMsg) {.async, gcsafe.} =
|
theirStatus: StatusMsg) {.async, gcsafe.} =
|
||||||
|
|
||||||
if theirStatus.forkVersion != node.forkVersion:
|
if theirStatus.forkVersion != state.forkVersion:
|
||||||
|
notice "Irrelevant peer",
|
||||||
|
peer, theirFork = theirStatus.forkVersion, ourFork = state.forkVersion
|
||||||
await peer.disconnect(IrrelevantNetwork)
|
await peer.disconnect(IrrelevantNetwork)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -203,7 +192,7 @@ proc handleInitialStatus(peer: Peer,
|
||||||
var s = ourStatus.headSlot + 1
|
var s = ourStatus.headSlot + 1
|
||||||
var theirStatus = theirStatus
|
var theirStatus = theirStatus
|
||||||
while s <= theirStatus.headSlot:
|
while s <= theirStatus.headSlot:
|
||||||
let numBlocksToRequest = min(uint64(theirStatus.headSlot - s),
|
let numBlocksToRequest = min(uint64(theirStatus.headSlot - s) + 1,
|
||||||
MAX_REQUESTED_BLOCKS)
|
MAX_REQUESTED_BLOCKS)
|
||||||
|
|
||||||
debug "Requesting blocks", peer, remoteHeadSlot = theirStatus.headSlot,
|
debug "Requesting blocks", peer, remoteHeadSlot = theirStatus.headSlot,
|
||||||
|
@ -221,7 +210,7 @@ proc handleInitialStatus(peer: Peer,
|
||||||
info "Got 0 blocks while syncing", peer
|
info "Got 0 blocks while syncing", peer
|
||||||
break
|
break
|
||||||
|
|
||||||
node.importBlocks blocks.get
|
state.importBlocks(blocks.get)
|
||||||
let lastSlot = blocks.get[^1].slot
|
let lastSlot = blocks.get[^1].slot
|
||||||
if lastSlot <= s:
|
if lastSlot <= s:
|
||||||
info "Slot did not advance during sync", peer
|
info "Slot did not advance during sync", peer
|
||||||
|
@ -231,7 +220,8 @@ proc handleInitialStatus(peer: Peer,
|
||||||
|
|
||||||
# TODO: Maybe this shouldn't happen so often.
|
# TODO: Maybe this shouldn't happen so often.
|
||||||
# The alternative could be watching up a timer here.
|
# The alternative could be watching up a timer here.
|
||||||
let statusResp = await peer.status(node.getCurrentStatus)
|
|
||||||
|
let statusResp = await peer.status(state.getCurrentStatus())
|
||||||
if statusResp.isSome:
|
if statusResp.isSome:
|
||||||
theirStatus = statusResp.get
|
theirStatus = statusResp.get
|
||||||
else:
|
else:
|
||||||
|
@ -245,4 +235,3 @@ proc handleInitialStatus(peer: Peer,
|
||||||
|
|
||||||
except CatchableError:
|
except CatchableError:
|
||||||
warn "Failed to sync with peer", peer, err = getCurrentExceptionMsg()
|
warn "Failed to sync with peer", peer, err = getCurrentExceptionMsg()
|
||||||
|
|
||||||
|
|
|
@ -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.9.1/specs/core/0_fork-choice.md#fork-choice
|
## https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_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:
|
||||||
|
@ -60,6 +60,8 @@ func toSlot*(c: BeaconClock, t: Time): tuple[afterGenesis: bool, slot: Slot] =
|
||||||
func toBeaconTime*(s: Slot, offset = chronos.seconds(0)): BeaconTime =
|
func toBeaconTime*(s: Slot, offset = chronos.seconds(0)): BeaconTime =
|
||||||
BeaconTime(int64(uint64(s) * SECONDS_PER_SLOT) + seconds(offset))
|
BeaconTime(int64(uint64(s) * SECONDS_PER_SLOT) + seconds(offset))
|
||||||
|
|
||||||
|
# TODO on Travis ARM64 CIs, this claims to have side effects, but neither Linux
|
||||||
|
# nor Mac OS x86 CIs exhibit this behavior.
|
||||||
proc now*(c: BeaconClock): BeaconTime =
|
proc now*(c: BeaconClock): BeaconTime =
|
||||||
## Current time, in slots - this may end up being less than GENESIS_SLOT(!)
|
## Current time, in slots - this may end up being less than GENESIS_SLOT(!)
|
||||||
toBeaconTime(c, getTime())
|
toBeaconTime(c, getTime())
|
||||||
|
@ -75,7 +77,7 @@ proc fromNow*(c: BeaconClock, t: BeaconTime): tuple[inFuture: bool, offset: Dura
|
||||||
proc fromNow*(c: BeaconClock, slot: Slot): tuple[inFuture: bool, offset: Duration] =
|
proc fromNow*(c: BeaconClock, slot: Slot): tuple[inFuture: bool, offset: Duration] =
|
||||||
c.fromNow(slot.toBeaconTime())
|
c.fromNow(slot.toBeaconTime())
|
||||||
|
|
||||||
proc saturate*(d: tuple[inFuture: bool, offset: Duration]): Duration =
|
func saturate*(d: tuple[inFuture: bool, offset: Duration]): Duration =
|
||||||
if d.inFuture: d.offset else: seconds(0)
|
if d.inFuture: d.offset else: seconds(0)
|
||||||
|
|
||||||
proc addTimer*(fromNow: Duration, cb: CallbackFunc, udata: pointer = nil) =
|
proc addTimer*(fromNow: Duration, cb: CallbackFunc, udata: pointer = nil) =
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
import terminal
|
import terminal
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
import
|
import
|
||||||
ospaths, chronos, json_serialization,
|
os, chronos, json_serialization,
|
||||||
spec/[datatypes], beacon_chain_db
|
spec/[datatypes], beacon_chain_db
|
||||||
|
|
||||||
const
|
|
||||||
WEAK_SUBJECTVITY_PERIOD* =
|
|
||||||
Slot(uint64(4 * 30 * 24 * 60 * 60) div SECONDS_PER_SLOT)
|
|
||||||
# TODO: This needs revisiting.
|
|
||||||
# Why was the validator WITHDRAWAL_PERIOD altered in the spec?
|
|
||||||
|
|
||||||
proc obtainTrustedStateSnapshot*(db: BeaconChainDB): Future[BeaconState] {.async.} =
|
proc obtainTrustedStateSnapshot*(db: BeaconChainDB): Future[BeaconState] {.async.} =
|
||||||
# In case our latest state is too old, we must obtain a recent snapshot
|
# In case our latest state is too old, we must obtain a recent snapshot
|
||||||
# of the state from a trusted location. This is explained in detail here:
|
# of the state from a trusted location. This is explained in detail here:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import
|
import
|
||||||
os, ospaths, strutils,
|
os, strutils,
|
||||||
chronicles, chronos, blscurve, nimcrypto, json_serialization, serialization,
|
chronicles, chronos, blscurve, nimcrypto, json_serialization, serialization,
|
||||||
web3, stint, eth/keys,
|
web3, stint, eth/keys,
|
||||||
spec/[datatypes, digest, crypto], conf, ssz, interop
|
spec/[datatypes, digest, crypto], conf, ssz, interop
|
||||||
|
|
|
@ -4,29 +4,27 @@ import
|
||||||
spec/[datatypes, crypto, digest, helpers], ssz,
|
spec/[datatypes, crypto, digest, helpers], ssz,
|
||||||
beacon_node_types
|
beacon_node_types
|
||||||
|
|
||||||
proc init*(T: type ValidatorPool): T =
|
func init*(T: type ValidatorPool): T =
|
||||||
result.validators = initTable[ValidatorPubKey, AttachedValidator]()
|
result.validators = initTable[ValidatorPubKey, AttachedValidator]()
|
||||||
|
|
||||||
template count*(pool: ValidatorPool): int =
|
template count*(pool: ValidatorPool): int =
|
||||||
pool.validators.len
|
pool.validators.len
|
||||||
|
|
||||||
proc addLocalValidator*(pool: var ValidatorPool,
|
proc addLocalValidator*(pool: var ValidatorPool,
|
||||||
idx: ValidatorIndex,
|
|
||||||
pubKey: ValidatorPubKey,
|
pubKey: ValidatorPubKey,
|
||||||
privKey: ValidatorPrivKey) =
|
privKey: ValidatorPrivKey) =
|
||||||
let v = AttachedValidator(idx: idx,
|
let v = AttachedValidator(pubKey: pubKey,
|
||||||
pubKey: pubKey,
|
|
||||||
kind: inProcess,
|
kind: inProcess,
|
||||||
privKey: privKey)
|
privKey: privKey)
|
||||||
pool.validators[pubKey] = v
|
pool.validators[pubKey] = v
|
||||||
|
|
||||||
info "Local validator attached", pubKey, validator = shortLog(v)
|
info "Local validator attached", pubKey, validator = shortLog(v)
|
||||||
|
|
||||||
proc getValidator*(pool: ValidatorPool,
|
func getValidator*(pool: ValidatorPool,
|
||||||
validatorKey: ValidatorPubKey): AttachedValidator =
|
validatorKey: ValidatorPubKey): AttachedValidator =
|
||||||
pool.validators.getOrDefault(validatorKey)
|
pool.validators.getOrDefault(validatorKey)
|
||||||
|
|
||||||
proc signBlockProposal*(v: AttachedValidator, state: BeaconState, slot: Slot,
|
proc signBlockProposal*(v: AttachedValidator, fork: Fork, slot: Slot,
|
||||||
blockRoot: Eth2Digest): Future[ValidatorSig] {.async.} =
|
blockRoot: Eth2Digest): Future[ValidatorSig] {.async.} =
|
||||||
|
|
||||||
if v.kind == inProcess:
|
if v.kind == inProcess:
|
||||||
|
@ -34,7 +32,7 @@ proc signBlockProposal*(v: AttachedValidator, state: BeaconState, slot: Slot,
|
||||||
# care about this in here
|
# care about this in here
|
||||||
let
|
let
|
||||||
domain =
|
domain =
|
||||||
get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(slot))
|
get_domain(fork, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(slot))
|
||||||
# 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
|
||||||
|
@ -47,11 +45,11 @@ proc signBlockProposal*(v: AttachedValidator, state: BeaconState, slot: Slot,
|
||||||
|
|
||||||
proc signAttestation*(v: AttachedValidator,
|
proc signAttestation*(v: AttachedValidator,
|
||||||
attestation: AttestationData,
|
attestation: AttestationData,
|
||||||
state: BeaconState): Future[ValidatorSig] {.async.} =
|
fork: Fork): Future[ValidatorSig] {.async.} =
|
||||||
if v.kind == inProcess:
|
if v.kind == inProcess:
|
||||||
let
|
let
|
||||||
attestationRoot = hash_tree_root(attestation)
|
attestationRoot = hash_tree_root(attestation)
|
||||||
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation.target.epoch)
|
domain = get_domain(fork, DOMAIN_BEACON_ATTESTER, attestation.target.epoch)
|
||||||
|
|
||||||
# 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
|
||||||
|
@ -63,14 +61,14 @@ proc signAttestation*(v: AttachedValidator,
|
||||||
error "Unimplemented"
|
error "Unimplemented"
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
func genRandaoReveal*(k: ValidatorPrivKey, state: BeaconState, slot: Slot):
|
func genRandaoReveal*(k: ValidatorPrivKey, fork: Fork, slot: Slot):
|
||||||
ValidatorSig =
|
ValidatorSig =
|
||||||
let
|
let
|
||||||
domain = get_domain(state, DOMAIN_RANDAO, compute_epoch_at_slot(slot))
|
domain = get_domain(fork, DOMAIN_RANDAO, compute_epoch_at_slot(slot))
|
||||||
root = hash_tree_root(compute_epoch_at_slot(slot).uint64).data
|
root = hash_tree_root(compute_epoch_at_slot(slot).uint64).data
|
||||||
|
|
||||||
bls_sign(k, root, domain)
|
bls_sign(k, root, domain)
|
||||||
|
|
||||||
func genRandaoReveal*(v: AttachedValidator, state: BeaconState, slot: Slot):
|
func genRandaoReveal*(v: AttachedValidator, fork: Fork, slot: Slot):
|
||||||
ValidatorSig =
|
ValidatorSig =
|
||||||
genRandaoReveal(v.privKey, state, slot)
|
genRandaoReveal(v.privKey, fork, slot)
|
||||||
|
|
|
@ -26,7 +26,7 @@ RUN cd /root/nim-beacon-chain \
|
||||||
&& git fetch \
|
&& git fetch \
|
||||||
&& git reset --hard ${GIT_REVISION} \
|
&& git reset --hard ${GIT_REVISION} \
|
||||||
&& make -j$(nproc) update \
|
&& make -j$(nproc) update \
|
||||||
&& make LOG_LEVEL=DEBUG NIMFLAGS="-d:release -d:insecure -d:testnet_servers_image ${NETWORK_NIM_FLAGS}" beacon_node
|
&& make LOG_LEVEL=DEBUG NIMFLAGS="-d:debug -d:insecure -d:testnet_servers_image ${NETWORK_NIM_FLAGS}" beacon_node
|
||||||
|
|
||||||
# --------------------------------- #
|
# --------------------------------- #
|
||||||
# Starting new image to reduce size #
|
# Starting new image to reduce size #
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import
|
import
|
||||||
strformat, ospaths, confutils
|
strformat, os, confutils
|
||||||
|
|
||||||
type
|
type
|
||||||
Command = enum
|
Command = enum
|
||||||
|
@ -76,8 +76,10 @@ iterator validatorAssignments: tuple[node: Node; firstValidator, lastValidator:
|
||||||
0
|
0
|
||||||
,
|
,
|
||||||
"testnet1": proc (nodeIdx: int): int =
|
"testnet1": proc (nodeIdx: int): int =
|
||||||
if nodeIdx == 0: systemValidators
|
if nodeidx < 4:
|
||||||
else: 0
|
systemValidators div 4
|
||||||
|
else:
|
||||||
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
var nextValidatorIdx = conf.totalUserValidators
|
var nextValidatorIdx = conf.totalUserValidators
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import
|
import
|
||||||
confutils, ospaths, strutils, chronicles, json_serialization,
|
confutils, os, strutils, chronicles, json_serialization,
|
||||||
nimcrypto/utils,
|
nimcrypto/utils,
|
||||||
../beacon_chain/spec/[crypto, datatypes, digest],
|
../beacon_chain/spec/[crypto, datatypes, digest],
|
||||||
../beacon_chain/[ssz]
|
../beacon_chain/[ssz]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import
|
import
|
||||||
confutils, ospaths, strutils, chronicles, json_serialization,
|
confutils, os, strutils, chronicles, json_serialization,
|
||||||
../beacon_chain/spec/[crypto, datatypes, digest],
|
../beacon_chain/spec/[crypto, datatypes, digest],
|
||||||
../beacon_chain/[ssz]
|
../beacon_chain/[ssz]
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import
|
import
|
||||||
confutils, ospaths, strutils, chronicles, json_serialization,
|
confutils, os, strutils, chronicles, json_serialization,
|
||||||
nimcrypto/utils,
|
nimcrypto/utils,
|
||||||
../beacon_chain/spec/[crypto, datatypes, digest],
|
../beacon_chain/spec/[crypto, datatypes, digest],
|
||||||
../beacon_chain/[ssz]
|
../beacon_chain/[ssz]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py
|
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py
|
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py
|
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py
|
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py
|
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
# This file contains the implementation of the beacon chain fork choice rule.
|
# This file contains the implementation of the beacon chain fork choice rule.
|
||||||
|
|
|
@ -10,7 +10,7 @@ type Timers = enum
|
||||||
tBlock = "Process non-epoch slot with block"
|
tBlock = "Process non-epoch slot with block"
|
||||||
tEpoch = "Process epoch slot with block"
|
tEpoch = "Process epoch slot with block"
|
||||||
tHashBlock = "Tree-hash block"
|
tHashBlock = "Tree-hash block"
|
||||||
tShuffle = "Retrieve committee once using get_crosslink_committee"
|
tShuffle = "Retrieve committee once using get_beacon_committee"
|
||||||
tAttest = "Combine committee attestations"
|
tAttest = "Combine committee attestations"
|
||||||
|
|
||||||
template withTimer(stats: var RunningStat, body: untyped) =
|
template withTimer(stats: var RunningStat, body: untyped) =
|
||||||
|
|
|
@ -56,7 +56,7 @@ cli do (testnetName {.argument.}: string):
|
||||||
dataDirName = testnetName.replace("/", "_")
|
dataDirName = testnetName.replace("/", "_")
|
||||||
dataDir = buildDir / "data" / dataDirName
|
dataDir = buildDir / "data" / dataDirName
|
||||||
beaconNodeBinary = buildDir / "beacon_node_" & dataDirName
|
beaconNodeBinary = buildDir / "beacon_node_" & dataDirName
|
||||||
nimFlags = "-d:release --lineTrace:on -d:chronicles_log_level=DEBUG " & getEnv("NIM_PARAMS")
|
nimFlags = "-d:chronicles_log_level=DEBUG " & getEnv("NIM_PARAMS")
|
||||||
|
|
||||||
var depositContractOpt = ""
|
var depositContractOpt = ""
|
||||||
let depositContractFile = testnetDir / depositContractFile
|
let depositContractFile = testnetDir / depositContractFile
|
||||||
|
|
|
@ -9,30 +9,14 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
TMP_CACHE_DIR="tmpcache"
|
|
||||||
SUBREPO_DIR="tests/official/fixtures"
|
SUBREPO_DIR="tests/official/fixtures"
|
||||||
# verbosity level
|
# verbosity level
|
||||||
[[ -z "$V" ]] && V=0
|
[[ -z "$V" ]] && V=0
|
||||||
[[ -z "$BUILD_MSG" ]] && BUILD_MSG="Downloading official test vectors"
|
[[ -z "$BUILD_MSG" ]] && BUILD_MSG="Downloading official test vectors"
|
||||||
CACHE_DIR="$1" # optional parameter pointing to a CI cache dir. Without it, we just download the LFS files for a local `make test`.
|
CACHE_DIR="$1" # optional parameter pointing to a CI cache dir. Without it, we just download the test vectors for a local `make test`.
|
||||||
|
|
||||||
[[ -d "${SUBREPO_DIR}" ]] || { echo "This script should be run from the \"nim-beacon-chain\" repo top dir."; exit 1; }
|
[[ -d "${SUBREPO_DIR}" ]] || { echo "This script should be run from the \"nim-beacon-chain\" repo top dir."; exit 1; }
|
||||||
|
|
||||||
# macOS quirks
|
|
||||||
if uname | grep -qi "darwin"; then
|
|
||||||
ON_MACOS=1
|
|
||||||
STAT_FORMAT="-f %m"
|
|
||||||
else
|
|
||||||
ON_MACOS=0
|
|
||||||
STAT_FORMAT="-c %Y"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# to and from stdout
|
|
||||||
DECOMPRESS_XZ="false"
|
|
||||||
COMPRESS_XZ="false"
|
|
||||||
which 7z &>/dev/null && { DECOMPRESS_XZ="7z e -txz -bd -so"; COMPRESS_XZ="7z a -txz -an -bd -si -so"; }
|
|
||||||
which xz &>/dev/null && { DECOMPRESS_XZ="xz -d -c -T 0"; COMPRESS_XZ="xz -c -T 0"; }
|
|
||||||
|
|
||||||
# script output
|
# script output
|
||||||
echo -e "$BUILD_MSG"
|
echo -e "$BUILD_MSG"
|
||||||
[[ "$V" == "0" ]] && exec 3>&1 4>&2 &>/dev/null # save stdout and stderr before sending them into oblivion
|
[[ "$V" == "0" ]] && exec 3>&1 4>&2 &>/dev/null # save stdout and stderr before sending them into oblivion
|
||||||
|
@ -41,10 +25,14 @@ echo -e "$BUILD_MSG"
|
||||||
# Main()
|
# Main()
|
||||||
|
|
||||||
if [[ -n "${CACHE_DIR}" ]]; then
|
if [[ -n "${CACHE_DIR}" ]]; then
|
||||||
|
# delete old cache entries we no longer use (let this run for a month or so)
|
||||||
|
rm -f "${CACHE_DIR}"/*.tar.xz
|
||||||
|
|
||||||
# Ethereum Foundation test vectors
|
# Ethereum Foundation test vectors
|
||||||
mkdir -p "${CACHE_DIR}/tarballs"
|
mkdir -p "${CACHE_DIR}/tarballs"
|
||||||
rm -rf "${SUBREPO_DIR}/tarballs"
|
rm -rf "${SUBREPO_DIR}/tarballs"
|
||||||
ln -s "$(pwd -P)/${CACHE_DIR}/tarballs" "${SUBREPO_DIR}"
|
ln -s "$(pwd -P)/${CACHE_DIR}/tarballs" "${SUBREPO_DIR}"
|
||||||
|
# (the dir symlink above also takes care of updating the cache)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
pushd "${SUBREPO_DIR}"
|
pushd "${SUBREPO_DIR}"
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
CONST_PRESET=minimal
|
CONST_PRESET=minimal
|
||||||
NETWORK_TYPE=libp2p_daemon
|
NETWORK_TYPE=libp2p_daemon
|
||||||
SLOTS_PER_EPOCH=16
|
QUICKSTART_VALIDATORS=8
|
||||||
SECONDS_PER_SLOT=16
|
RANDOM_VALIDATORS=120
|
||||||
MAX_COMMITTEES_PER_SLOT=8
|
|
||||||
QUICKSTART_VALIDATORS=40
|
|
||||||
RANDOM_VALIDATORS=960
|
|
||||||
BOOTSTRAP_PORT=9100
|
BOOTSTRAP_PORT=9100
|
||||||
WEB3_URL=wss://goerli.infura.io/ws/v3/809a18497dd74102b5f37d25aae3c85a
|
WEB3_URL=wss://goerli.infura.io/ws/v3/809a18497dd74102b5f37d25aae3c85a
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
|
import # Official constants
|
||||||
|
./official/test_fixture_const_sanity_check
|
||||||
|
|
||||||
import # Unit test
|
import # Unit test
|
||||||
./test_attestation_pool,
|
./test_attestation_pool,
|
||||||
./test_beacon_chain_db,
|
./test_beacon_chain_db,
|
||||||
|
@ -25,7 +28,9 @@ import # Refactor state transition unit tests
|
||||||
./spec_block_processing/test_process_attestation,
|
./spec_block_processing/test_process_attestation,
|
||||||
./spec_epoch_processing/test_process_justification_and_finalization
|
./spec_epoch_processing/test_process_justification_and_finalization
|
||||||
|
|
||||||
import # Official fixtures that don't require SSZ parsing of invalid BLS signatures
|
# TODO: json tests were removed
|
||||||
# https://github.com/status-im/nim-beacon-chain/issues/374
|
|
||||||
./official/test_fixture_shuffling,
|
# import # Official fixtures that don't require SSZ parsing of invalid BLS signatures
|
||||||
./official/test_fixture_bls
|
# # https://github.com/status-im/nim-beacon-chain/issues/374
|
||||||
|
# ./official/test_fixture_shuffling,
|
||||||
|
# ./official/test_fixture_bls
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
# beacon_chain
|
||||||
|
# Copyright (c) 2018-Present 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.
|
||||||
|
|
||||||
|
import
|
||||||
|
# Standard library
|
||||||
|
os, unittest, strutils, streams,
|
||||||
|
# Status libraries
|
||||||
|
stint, stew/bitseqs,
|
||||||
|
# Third-party
|
||||||
|
yaml,
|
||||||
|
# Beacon chain internals
|
||||||
|
../../beacon_chain/spec/[datatypes, digest, crypto],
|
||||||
|
../../beacon_chain/ssz
|
||||||
|
|
||||||
|
# Config
|
||||||
|
# ---------------------------------------------
|
||||||
|
|
||||||
|
const
|
||||||
|
FixturesDir = currentSourcePath.rsplit(DirSep, 1)[0] / ".." / "official"/"fixtures"
|
||||||
|
SSZDir = FixturesDir/"tests-v0.9.1"/const_preset/"phase0"/"ssz_static"
|
||||||
|
UnitTestDir = SSZDir/"Validator"/"ssz_zero"/"case_0"
|
||||||
|
|
||||||
|
type
|
||||||
|
SSZHashTreeRoot = object
|
||||||
|
# The test files have the values at the "root"
|
||||||
|
# so we **must** use "root" as a field name
|
||||||
|
root: string
|
||||||
|
# Some have a signing_root field
|
||||||
|
signing_root: string
|
||||||
|
|
||||||
|
# Make signing root optional
|
||||||
|
setDefaultValue(SSZHashTreeRoot, signing_root, "")
|
||||||
|
|
||||||
|
# Parsing + Test
|
||||||
|
# ---------------------------------------------
|
||||||
|
|
||||||
|
type Skip = enum
|
||||||
|
SkipNone
|
||||||
|
SkipHashTreeRoot
|
||||||
|
SkipSigningRoot
|
||||||
|
|
||||||
|
proc checkSSZ(T: typedesc, dir: string, expectedHash: SSZHashTreeRoot, skip = SkipNone) =
|
||||||
|
# Deserialize into a ref object to not fill Nim stack
|
||||||
|
var deserialized: ref T
|
||||||
|
new deserialized
|
||||||
|
deserialized[] = SSZ.loadFile(dir/"serialized.ssz", T)
|
||||||
|
|
||||||
|
echo "\n\nObject: ", T
|
||||||
|
echo "---------------------------------------"
|
||||||
|
echo deserialized[]
|
||||||
|
|
||||||
|
if not(skip == SkipHashTreeRoot):
|
||||||
|
check: expectedHash.root == "0x" & toLowerASCII($deserialized.hashTreeRoot())
|
||||||
|
if expectedHash.signing_root != "" and not(skip == SkipSigningRoot):
|
||||||
|
check: expectedHash.signing_root == "0x" & toLowerASCII($deserialized[].signingRoot())
|
||||||
|
|
||||||
|
proc loadExpectedHashTreeRoot(dir: string): SSZHashTreeRoot =
|
||||||
|
var s = openFileStream(dir/"roots.yaml")
|
||||||
|
yaml.load(s, result)
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
# Manual checks
|
||||||
|
# ---------------------------------------------
|
||||||
|
|
||||||
|
# Compile with -d:ssz_testing for consensus objects
|
||||||
|
# as they are always an Opaque Blob even if they might seem like a valid BLS signature
|
||||||
|
|
||||||
|
echo "Current preset: ", const_preset
|
||||||
|
|
||||||
|
let hash = loadExpectedHashTreeRoot(UnitTestDir)
|
||||||
|
checkSSZ(Validator, UnitTestDir, hash)
|
||||||
|
|
||||||
|
echo "\n\n"
|
||||||
|
var deserialized: ref Validator
|
||||||
|
new deserialized
|
||||||
|
deserialized[] = SSZ.loadFile(UnitTestDir/"serialized.ssz", Validator)
|
||||||
|
|
||||||
|
echo deserialized[].hashTreeRoot()
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
@ -92,7 +92,7 @@ proc inspectType(tImpl, xSubField, ySubField: NimNode, stmts: var NimNode) =
|
||||||
inspectType(tImpl[0], xSubField, ySubField, stmts)
|
inspectType(tImpl[0], xSubField, ySubField, stmts)
|
||||||
of {nnkSym, nnkBracketExpr}:
|
of {nnkSym, nnkBracketExpr}:
|
||||||
if tImpl.kind == nnkBracketExpr:
|
if tImpl.kind == nnkBracketExpr:
|
||||||
assert tImpl[0].eqIdent"seq" or tImpl[0].eqIdent"array", "Error: unsupported generic type: " & $tImpl[0]
|
doAssert tImpl[0].eqIdent"List" or tImpl[0].eqIdent"seq" or tImpl[0].eqIdent"array", "Error: unsupported generic type: " & $tImpl[0]
|
||||||
compareContainerStmt(xSubField, ySubField, stmts)
|
compareContainerStmt(xSubField, ySubField, stmts)
|
||||||
elif $tImpl in builtinTypes:
|
elif $tImpl in builtinTypes:
|
||||||
compareStmt(xSubField, ySubField, stmts)
|
compareStmt(xSubField, ySubField, stmts)
|
||||||
|
@ -107,7 +107,7 @@ proc inspectType(tImpl, xSubField, ySubField: NimNode, stmts: var NimNode) =
|
||||||
"\" of type \"" & tImpl.repr
|
"\" of type \"" & tImpl.repr
|
||||||
|
|
||||||
macro reportDiff*(x, y: typed{`var`|`let`|`const`}): untyped =
|
macro reportDiff*(x, y: typed{`var`|`let`|`const`}): untyped =
|
||||||
assert sameType(x, y)
|
doAssert sameType(x, y)
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
|
|
||||||
let typeImpl = x.getTypeImpl
|
let typeImpl = x.getTypeImpl
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
import
|
import
|
||||||
../../beacon_chain/spec/digest
|
../../beacon_chain/spec/digest
|
||||||
|
|
||||||
proc `*`*(a: static array[1, byte], n: static int): static Eth2Digest =
|
proc `*`*(a: static array[1, byte], n: static int): static Eth2Digest =
|
||||||
assert n == 32
|
doAssert n == 32
|
||||||
for mbyte in result.data.mitems:
|
for mbyte in result.data.mitems:
|
||||||
mbyte = a[0]
|
mbyte = a[0]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
func round_multiple_down*(x: uint64, n: uint64): uint64 {.inline.} =
|
func round_multiple_down*(x: uint64, n: uint64): uint64 {.inline.} =
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# Merkle tree helpers
|
# Merkle tree helpers
|
||||||
|
@ -11,9 +11,7 @@
|
||||||
import
|
import
|
||||||
# Specs
|
# Specs
|
||||||
../../beacon_chain/spec/[datatypes, digest],
|
../../beacon_chain/spec/[datatypes, digest],
|
||||||
../../beacon_chain/ssz,
|
../../beacon_chain/ssz
|
||||||
# shims
|
|
||||||
stew/objects
|
|
||||||
|
|
||||||
func round_step_down*(x: Natural, step: static Natural): int {.inline.} =
|
func round_step_down*(x: Natural, step: static Natural): int {.inline.} =
|
||||||
## Round the input to the previous multiple of "step"
|
## Round the input to the previous multiple of "step"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# Mocking attestations
|
# Mocking attestations
|
||||||
|
@ -11,7 +11,6 @@
|
||||||
import
|
import
|
||||||
# Standard library
|
# Standard library
|
||||||
sets,
|
sets,
|
||||||
# 0.19.6 shims
|
|
||||||
# Specs
|
# Specs
|
||||||
../../beacon_chain/spec/[datatypes, beaconstate, helpers, validator, crypto],
|
../../beacon_chain/spec/[datatypes, beaconstate, helpers, validator, crypto],
|
||||||
# Internals
|
# Internals
|
||||||
|
@ -131,13 +130,13 @@ proc mockAttestation*(
|
||||||
|
|
||||||
proc fillAggregateAttestation*(state: BeaconState, attestation: var Attestation) =
|
proc fillAggregateAttestation*(state: BeaconState, attestation: var Attestation) =
|
||||||
var cache = get_empty_per_epoch_cache()
|
var cache = get_empty_per_epoch_cache()
|
||||||
let crosslink_committee = get_beacon_committee(
|
let beacon_committee = get_beacon_committee(
|
||||||
state,
|
state,
|
||||||
attestation.data.slot,
|
attestation.data.slot,
|
||||||
attestation.data.index,
|
attestation.data.index,
|
||||||
cache
|
cache
|
||||||
)
|
)
|
||||||
for i in 0 ..< crosslink_committee.len:
|
for i in 0 ..< beacon_committee.len:
|
||||||
attestation.aggregation_bits[i] = true
|
attestation.aggregation_bits[i] = true
|
||||||
|
|
||||||
proc add*(state: var BeaconState, attestation: Attestation, slot: Slot) =
|
proc add*(state: var BeaconState, attestation: Attestation, slot: Slot) =
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# Mocking deposits and genesis deposits
|
# Mocking deposits and genesis deposits
|
||||||
|
@ -11,8 +11,6 @@
|
||||||
import
|
import
|
||||||
# Standard library
|
# Standard library
|
||||||
math, random,
|
math, random,
|
||||||
# 0.19.6 shims
|
|
||||||
stew/objects, # import default
|
|
||||||
# Specs
|
# Specs
|
||||||
../../beacon_chain/spec/[datatypes, crypto, helpers, digest, beaconstate],
|
../../beacon_chain/spec/[datatypes, crypto, helpers, digest, beaconstate],
|
||||||
# Internals
|
# Internals
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# Mocking a genesis state
|
# Mocking a genesis state
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# Mocking helpers for BeaconState
|
# Mocking helpers for BeaconState
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
# Copyright (c) 2018-2019 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 http://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 http://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.
|
||||||
|
|
||||||
# Mocking validator public and private keys
|
# Mocking validator public and private keys
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
# All non-pure SSZ tests that require the -d:ssz_testing
|
# All non-pure SSZ tests that require the -d:ssz_testing
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c84c56a2fb4167f79d987b84d74a78246d0ab6b1
|
Subproject commit 0a51654000c7066fa2d89105044367a748ae5db0
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
# Copyright (c) 2018-Present 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 http://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 http://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.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
@ -36,8 +36,7 @@ proc readValue*(r: var JsonReader, a: var seq[byte]) {.inline.} =
|
||||||
|
|
||||||
const
|
const
|
||||||
FixturesDir* = currentSourcePath.rsplit(DirSep, 1)[0] / "fixtures"
|
FixturesDir* = currentSourcePath.rsplit(DirSep, 1)[0] / "fixtures"
|
||||||
JsonTestsDir* = FixturesDir/"json_tests_v0.8.3"
|
SszTestsDir* = FixturesDir/"tests-v0.9.2"
|
||||||
SszTestsDir* = FixturesDir/"tests-v0.9.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:
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
@ -46,6 +46,7 @@ proc readValue*(r: var JsonReader, a: var Domain) {.inline.} =
|
||||||
# (0.20)
|
# (0.20)
|
||||||
a = hexToPaddedByteArray[8](r.readValue(string))
|
a = hexToPaddedByteArray[8](r.readValue(string))
|
||||||
|
|
||||||
|
# TODO: json tests were removed
|
||||||
const BLSDir = JsonTestsDir/"general"/"phase0"/"bls"
|
const BLSDir = JsonTestsDir/"general"/"phase0"/"bls"
|
||||||
|
|
||||||
suite "Official - BLS tests":
|
suite "Official - BLS tests":
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
# Sanity check on constants
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
|
||||||
|
{.used.}
|
||||||
|
|
||||||
|
import
|
||||||
|
# Standard library
|
||||||
|
macros, os, strutils, tables, math, json, streams,
|
||||||
|
strformat, unittest,
|
||||||
|
# Third party
|
||||||
|
yaml,
|
||||||
|
# Status libraries
|
||||||
|
stew/[byteutils, endians2],
|
||||||
|
# Internals
|
||||||
|
../../beacon_chain/spec/[datatypes, digest],
|
||||||
|
# Test utilities
|
||||||
|
../testutil
|
||||||
|
|
||||||
|
const
|
||||||
|
SpecDir = currentSourcePath.rsplit(DirSep, 1)[0] /
|
||||||
|
".."/".."/"beacon_chain"/"spec"
|
||||||
|
FixturesDir = currentSourcePath.rsplit(DirSep, 1)[0] / "fixtures"
|
||||||
|
Config = FixturesDir/"tests-v0.9.2"/const_preset/"config.yaml"
|
||||||
|
|
||||||
|
type
|
||||||
|
CheckedType = SomeInteger or Slot or Epoch
|
||||||
|
# Only test numerical types, constants
|
||||||
|
# defined for other type will get a placeholder low(int64) value
|
||||||
|
|
||||||
|
macro parseNumConsts(file: static string): untyped =
|
||||||
|
## Important: All const are assumed to be top-level
|
||||||
|
## i.e. not hidden behind a "when" statement
|
||||||
|
|
||||||
|
var constsToCheck: seq[(string, NimNode)]
|
||||||
|
# We can't create a table directly and quote do it
|
||||||
|
# Nim complains about the "data" field not being accessible
|
||||||
|
|
||||||
|
let fileAST = parseStmt(slurp(file))
|
||||||
|
for statement in fileAST:
|
||||||
|
if statement.kind == nnkConstSection:
|
||||||
|
for constDef in statement:
|
||||||
|
if constDef.len == 0 or
|
||||||
|
constDef[0].kind notin {nnkPragmaExpr, nnkPostfix}:
|
||||||
|
# Comments in a const section need to be skipped.
|
||||||
|
# And we only want exported constants.
|
||||||
|
continue
|
||||||
|
# Note: we assume that all const with a pragma are exported
|
||||||
|
# 1. Simple statement
|
||||||
|
#
|
||||||
|
# ConstDef
|
||||||
|
# Postfix
|
||||||
|
# Ident "*"
|
||||||
|
# Ident "HISTORICAL_ROOTS_LIMIT"
|
||||||
|
# Empty
|
||||||
|
# IntLit 16777216
|
||||||
|
#
|
||||||
|
# 2. with intdefine pragma
|
||||||
|
#
|
||||||
|
# ConstDef
|
||||||
|
# PragmaExpr
|
||||||
|
# Postfix
|
||||||
|
# Ident "*"
|
||||||
|
# Ident "MIN_GENESIS_ACTIVE_VALIDATOR_COUNT"
|
||||||
|
# Pragma
|
||||||
|
# Ident "intdefine"
|
||||||
|
# Empty
|
||||||
|
# IntLit 99
|
||||||
|
let name = if constDef[0].kind == nnkPostfix: $constDef[0][1]
|
||||||
|
else: $constDef[0][0][1]
|
||||||
|
|
||||||
|
# ConstsToCheck["HISTORICAL_ROOTS_LIMIT"} = uint64(16777216)
|
||||||
|
# Put a placeholder values for strings
|
||||||
|
let value = block:
|
||||||
|
let node = constDef[2]
|
||||||
|
quote do:
|
||||||
|
when `node` is CheckedType:
|
||||||
|
uint64(`node`)
|
||||||
|
else:
|
||||||
|
high(uint64)
|
||||||
|
constsToCheck.add (name, value)
|
||||||
|
|
||||||
|
result = quote do: `constsToCheck`
|
||||||
|
|
||||||
|
const
|
||||||
|
datatypesConsts = @(parseNumConsts(SpecDir/"datatypes.nim"))
|
||||||
|
mainnetConsts = @(parseNumConsts(SpecDir/"presets"/"mainnet.nim"))
|
||||||
|
minimalConsts = @(parseNumConsts(SpecDir/"presets"/"minimal.nim"))
|
||||||
|
|
||||||
|
const IgnoreKeys = [
|
||||||
|
# Ignore all non-numeric types
|
||||||
|
"DEPOSIT_CONTRACT_ADDRESS"
|
||||||
|
]
|
||||||
|
|
||||||
|
func parseU32LEHex(hexValue: string): uint32 =
|
||||||
|
## Parse little-endian uint32 hex string
|
||||||
|
result = uint32.fromBytesLE hexToByteArray[4](hexValue)
|
||||||
|
|
||||||
|
proc checkConfig() =
|
||||||
|
let ConstsToCheck = toTable(
|
||||||
|
when const_preset == "minimal":
|
||||||
|
minimalConsts & datatypesConsts
|
||||||
|
else:
|
||||||
|
mainnetConsts & datatypesConsts
|
||||||
|
)
|
||||||
|
|
||||||
|
var yamlStream = openFileStream(Config)
|
||||||
|
defer: yamlStream.close()
|
||||||
|
var config = yamlStream.loadToJson()
|
||||||
|
doAssert config.len == 1
|
||||||
|
for constant, value in config[0]:
|
||||||
|
test &"{constant:<50}{value:<20}{preset()}":
|
||||||
|
if constant in IgnoreKeys:
|
||||||
|
echo &" ↶↶ Skipping {constant}"
|
||||||
|
continue
|
||||||
|
if constant.startsWith("DOMAIN"):
|
||||||
|
let domain = parseEnum[DomainType](constant)
|
||||||
|
let value = parseU32LEHex(value.getStr())
|
||||||
|
check: uint32(domain) == value
|
||||||
|
else:
|
||||||
|
check: ConstsToCheck[constant] == value.getBiggestInt().uint64()
|
||||||
|
|
||||||
|
suite "Official - 0.9.2 - constants & config " & preset():
|
||||||
|
checkConfig()
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
# Copyright (c) 2018-Present 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 http://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 http://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.
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
# Copyright (c) 2018-Present 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 http://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 http://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.
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
# Copyright (c) 2018-Present 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 http://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 http://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.
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
# Copyright (c) 2018-Present 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 http://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 http://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.
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
# Copyright (c) 2018-Present 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 http://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 http://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.
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
# Copyright (c) 2018-Present 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 http://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 http://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.
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
# Copyright (c) 2018-Present 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 http://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 http://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.
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
# Copyright (c) 2018-Present 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 http://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 http://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.
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
# Copyright (c) 2018-Present 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 http://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 http://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.
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
@ -22,6 +22,7 @@ type
|
||||||
count*: uint64
|
count*: uint64
|
||||||
mapping*: seq[uint64]
|
mapping*: seq[uint64]
|
||||||
|
|
||||||
|
# TODO: json tests were removed
|
||||||
const ShufflingDir = JsonTestsDir/const_preset/"phase0"/"shuffling"/"core"/"shuffle"
|
const ShufflingDir = JsonTestsDir/const_preset/"phase0"/"shuffling"/"core"/"shuffle"
|
||||||
|
|
||||||
suite "Official - Shuffling tests [Preset: " & preset():
|
suite "Official - Shuffling tests [Preset: " & preset():
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
@ -26,7 +26,7 @@ import
|
||||||
|
|
||||||
const
|
const
|
||||||
FixturesDir = currentSourcePath.rsplit(DirSep, 1)[0] / "fixtures"
|
FixturesDir = currentSourcePath.rsplit(DirSep, 1)[0] / "fixtures"
|
||||||
SSZDir = FixturesDir/"tests-v0.9.1"/const_preset/"phase0"/"ssz_static"
|
SSZDir = FixturesDir/"tests-v0.9.2"/const_preset/"phase0"/"ssz_static"
|
||||||
|
|
||||||
type
|
type
|
||||||
SSZHashTreeRoot = object
|
SSZHashTreeRoot = object
|
||||||
|
@ -43,44 +43,16 @@ setDefaultValue(SSZHashTreeRoot, signing_root, "")
|
||||||
# Checking the values against the yaml file is TODO (require more flexible Yaml parser)
|
# Checking the values against the yaml file is TODO (require more flexible Yaml parser)
|
||||||
const Unsupported = toHashSet([
|
const Unsupported = toHashSet([
|
||||||
"AggregateAndProof", # Type for signature aggregation - not implemented
|
"AggregateAndProof", # Type for signature aggregation - not implemented
|
||||||
"Attestation", # RangeError on deserialization
|
|
||||||
# "AttestationData",
|
|
||||||
"AttesterSlashing", # RangeError on deserialization
|
|
||||||
"BeaconBlock", # RangeError on deserialization
|
|
||||||
"BeaconBlockBody", # RangeError on deserialization
|
|
||||||
# "BeaconBlockHeader", # HashTreeRoot KO - SigningRook OK
|
|
||||||
"BeaconState", # HashTreeRoot KO
|
|
||||||
# "Checkpoint",
|
|
||||||
"Deposit", # HashTreeRoot KO
|
|
||||||
"DepositData", # HashTreeRoot KO - SigningRoot KO
|
|
||||||
# "Eth1Data",
|
|
||||||
# "Fork",
|
|
||||||
# "HistoricalBatch", # OK
|
|
||||||
"IndexedAttestation", # RangeError on deserialization
|
|
||||||
# "PendingAttestation", # OK
|
|
||||||
"ProposerSlashing", # HashTreeRoot KO
|
|
||||||
"Validator", # HashTreeRoot KO
|
|
||||||
# "VoluntaryExit" # hashTreeRoot KO - SigningRoot OK
|
|
||||||
])
|
])
|
||||||
|
|
||||||
const UnsupportedMainnet = toHashSet([
|
proc checkSSZ(T: typedesc, dir: string, expectedHash: SSZHashTreeRoot) =
|
||||||
"PendingAttestation", # HashTreeRoot KO
|
|
||||||
])
|
|
||||||
|
|
||||||
type Skip = enum
|
|
||||||
SkipNone
|
|
||||||
SkipHashTreeRoot
|
|
||||||
SkipSigningRoot
|
|
||||||
|
|
||||||
proc checkSSZ(T: typedesc, dir: string, expectedHash: SSZHashTreeRoot, skip = SkipNone) =
|
|
||||||
# Deserialize into a ref object to not fill Nim stack
|
# Deserialize into a ref object to not fill Nim stack
|
||||||
var deserialized: ref T
|
var deserialized: ref T
|
||||||
new deserialized
|
new deserialized
|
||||||
deserialized[] = SSZ.loadFile(dir/"serialized.ssz", T)
|
deserialized[] = SSZ.loadFile(dir/"serialized.ssz", T)
|
||||||
|
|
||||||
if not(skip == SkipHashTreeRoot):
|
check: expectedHash.root == "0x" & toLowerASCII($deserialized.hashTreeRoot())
|
||||||
check: expectedHash.root == "0x" & toLowerASCII($deserialized.hashTreeRoot())
|
if expectedHash.signing_root != "":
|
||||||
if expectedHash.signing_root != "" and not(skip == SkipSigningRoot):
|
|
||||||
check: expectedHash.signing_root == "0x" & toLowerASCII($deserialized[].signingRoot())
|
check: expectedHash.signing_root == "0x" & toLowerASCII($deserialized[].signingRoot())
|
||||||
|
|
||||||
# TODO check the value
|
# TODO check the value
|
||||||
|
@ -96,26 +68,16 @@ proc loadExpectedHashTreeRoot(dir: string): SSZHashTreeRoot =
|
||||||
proc runSSZtests() =
|
proc runSSZtests() =
|
||||||
doAssert existsDir(SSZDir), "You need to run the \"download_test_vectors.sh\" script to retrieve the official test vectors."
|
doAssert existsDir(SSZDir), "You need to run the \"download_test_vectors.sh\" script to retrieve the official test vectors."
|
||||||
for pathKind, sszType in walkDir(SSZDir, relative = true):
|
for pathKind, sszType in walkDir(SSZDir, relative = true):
|
||||||
assert pathKind == pcDir
|
doAssert pathKind == pcDir
|
||||||
if sszType in Unsupported:
|
if sszType in Unsupported:
|
||||||
test &" Skipping {sszType:20} consensus object ✗✗✗":
|
test &" Skipping {sszType:20} ✗✗✗":
|
||||||
discard
|
discard
|
||||||
continue
|
continue
|
||||||
|
|
||||||
when const_preset == "mainnet":
|
test &" Testing {sszType}":
|
||||||
if sszType in UnsupportedMainnet:
|
|
||||||
test &" Skipping {sszType:20} consensus object ✗✗✗ (skipped on mainnet-only)":
|
|
||||||
discard
|
|
||||||
continue
|
|
||||||
|
|
||||||
let signingRootOnly = &" ↶↶↶ {sszType} - Skipping HashTreeRoot and testing SigningRoot only"
|
|
||||||
if sszType == "BeaconBlockHeader" or sszType == "VoluntaryExit":
|
|
||||||
echo signingRootOnly
|
|
||||||
|
|
||||||
test &" Testing {sszType:20} consensus object ✓✓✓":
|
|
||||||
let path = SSZDir/sszType
|
let path = SSZDir/sszType
|
||||||
for pathKind, sszTestKind in walkDir(path, relative = true):
|
for pathKind, sszTestKind in walkDir(path, relative = true):
|
||||||
assert pathKind == pcDir
|
doAssert pathKind == pcDir
|
||||||
let path = SSZDir/sszType/sszTestKind
|
let path = SSZDir/sszType/sszTestKind
|
||||||
for pathKind, sszTestCase in walkDir(path, relative = true):
|
for pathKind, sszTestCase in walkDir(path, relative = true):
|
||||||
let path = SSZDir/sszType/sszTestKind/sszTestCase
|
let path = SSZDir/sszType/sszTestKind/sszTestCase
|
||||||
|
@ -128,7 +90,7 @@ proc runSSZtests() =
|
||||||
of "AttesterSlashing": checkSSZ(AttesterSlashing, path, hash)
|
of "AttesterSlashing": checkSSZ(AttesterSlashing, path, hash)
|
||||||
of "BeaconBlock": checkSSZ(BeaconBlock, path, hash)
|
of "BeaconBlock": checkSSZ(BeaconBlock, path, hash)
|
||||||
of "BeaconBlockBody": checkSSZ(BeaconBlockBody, path, hash)
|
of "BeaconBlockBody": checkSSZ(BeaconBlockBody, path, hash)
|
||||||
of "BeaconBlockHeader": checkSSZ(BeaconBlockHeader, path, hash, SkipHashTreeRoot) # TODO
|
of "BeaconBlockHeader": checkSSZ(BeaconBlockHeader, path, hash)
|
||||||
of "BeaconState": checkSSZ(BeaconState, path, hash)
|
of "BeaconState": checkSSZ(BeaconState, path, hash)
|
||||||
of "Checkpoint": checkSSZ(Checkpoint, path, hash)
|
of "Checkpoint": checkSSZ(Checkpoint, path, hash)
|
||||||
of "Deposit": checkSSZ(Deposit, path, hash)
|
of "Deposit": checkSSZ(Deposit, path, hash)
|
||||||
|
@ -139,10 +101,10 @@ proc runSSZtests() =
|
||||||
of "IndexedAttestation": checkSSZ(IndexedAttestation, path, hash)
|
of "IndexedAttestation": checkSSZ(IndexedAttestation, path, hash)
|
||||||
of "PendingAttestation": checkSSZ(PendingAttestation, path, hash)
|
of "PendingAttestation": checkSSZ(PendingAttestation, path, hash)
|
||||||
of "ProposerSlashing": checkSSZ(ProposerSlashing, path, hash)
|
of "ProposerSlashing": checkSSZ(ProposerSlashing, path, hash)
|
||||||
of "Validator": checkSSZ(VoluntaryExit, path, hash)
|
of "Validator": checkSSZ(Validator, path, hash)
|
||||||
of "VoluntaryExit": checkSSZ(VoluntaryExit, path, hash, SkipHashTreeRoot) # TODO
|
of "VoluntaryExit": checkSSZ(VoluntaryExit, path, hash)
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError, "Unsupported test: " & sszType)
|
raise newException(ValueError, "Unsupported test: " & sszType)
|
||||||
|
|
||||||
suite "Official - 0.9.1 - SSZ consensus objects " & preset():
|
suite "Official - 0.9.2 - SSZ consensus objects " & preset():
|
||||||
runSSZtests()
|
runSSZtests()
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
-d:ssz_testing
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
@ -23,7 +23,7 @@ import
|
||||||
|
|
||||||
const
|
const
|
||||||
FixturesDir = currentSourcePath.rsplit(DirSep, 1)[0] / "fixtures"
|
FixturesDir = currentSourcePath.rsplit(DirSep, 1)[0] / "fixtures"
|
||||||
SSZDir = FixturesDir/"tests-v0.9.1"/"general"/"phase0"/"ssz_generic"
|
SSZDir = FixturesDir/"tests-v0.9.2"/"general"/"phase0"/"ssz_generic"
|
||||||
|
|
||||||
type
|
type
|
||||||
SSZHashTreeRoot = object
|
SSZHashTreeRoot = object
|
||||||
|
@ -133,7 +133,7 @@ proc checkVector(sszSubType, dir: string, expectedHash: SSZHashTreeRoot) =
|
||||||
var typeIdent: string
|
var typeIdent: string
|
||||||
var size: int
|
var size: int
|
||||||
let wasMatched = scanf(sszSubType, "vec_$+_$i", typeIdent, size)
|
let wasMatched = scanf(sszSubType, "vec_$+_$i", typeIdent, size)
|
||||||
assert wasMatched
|
doAssert wasMatched
|
||||||
testVector(typeIdent, size)
|
testVector(typeIdent, size)
|
||||||
|
|
||||||
type BitContainer[N: static int] = BitList[N] or BitArray[N]
|
type BitContainer[N: static int] = BitList[N] or BitArray[N]
|
||||||
|
@ -147,7 +147,7 @@ proc testBitContainer(T: typedesc[BitContainer], dir: string, expectedHash: SSZH
|
||||||
proc checkBitVector(sszSubType, dir: string, expectedHash: SSZHashTreeRoot) =
|
proc checkBitVector(sszSubType, dir: string, expectedHash: SSZHashTreeRoot) =
|
||||||
var size: int
|
var size: int
|
||||||
let wasMatched = scanf(sszSubType, "bitvec_$i", size)
|
let wasMatched = scanf(sszSubType, "bitvec_$i", size)
|
||||||
assert wasMatched
|
doAssert wasMatched
|
||||||
case size
|
case size
|
||||||
of 1: testBitContainer(BitArray[1], dir, expectedHash)
|
of 1: testBitContainer(BitArray[1], dir, expectedHash)
|
||||||
of 2: testBitContainer(BitArray[2], dir, expectedHash)
|
of 2: testBitContainer(BitArray[2], dir, expectedHash)
|
||||||
|
@ -199,7 +199,7 @@ proc sszCheck(sszType, sszSubType: string) =
|
||||||
of "uints":
|
of "uints":
|
||||||
var bitsize: int
|
var bitsize: int
|
||||||
let wasMatched = scanf(sszSubType, "uint_$i", bitsize)
|
let wasMatched = scanf(sszSubType, "uint_$i", bitsize)
|
||||||
assert wasMatched
|
doAssert wasMatched
|
||||||
case bitsize
|
case bitsize
|
||||||
of 8: checkBasic(uint8, dir, expectedHash)
|
of 8: checkBasic(uint8, dir, expectedHash)
|
||||||
of 16: checkBasic(uint16, dir, expectedHash)
|
of 16: checkBasic(uint16, dir, expectedHash)
|
||||||
|
@ -219,7 +219,7 @@ proc sszCheck(sszType, sszSubType: string) =
|
||||||
of "containers":
|
of "containers":
|
||||||
var name: string
|
var name: string
|
||||||
let wasMatched = scanf(sszSubtype, "$+_", name)
|
let wasMatched = scanf(sszSubtype, "$+_", name)
|
||||||
assert wasMatched
|
doAssert wasMatched
|
||||||
case name
|
case name
|
||||||
of "SingleFieldTestStruct": checkBasic(SingleFieldTestStruct, dir, expectedHash)
|
of "SingleFieldTestStruct": checkBasic(SingleFieldTestStruct, dir, expectedHash)
|
||||||
of "SmallTestStruct": checkBasic(SmallTestStruct, dir, expectedHash)
|
of "SmallTestStruct": checkBasic(SmallTestStruct, dir, expectedHash)
|
||||||
|
@ -249,7 +249,7 @@ proc sszCheck(sszType, sszSubType: string) =
|
||||||
proc runSSZtests() =
|
proc runSSZtests() =
|
||||||
doAssert existsDir(SSZDir), "You need to run the \"download_test_vectors.sh\" script to retrieve the official test vectors."
|
doAssert existsDir(SSZDir), "You need to run the \"download_test_vectors.sh\" script to retrieve the official test vectors."
|
||||||
for pathKind, sszType in walkDir(SSZDir, relative = true):
|
for pathKind, sszType in walkDir(SSZDir, relative = true):
|
||||||
assert pathKind == pcDir
|
doAssert pathKind == pcDir
|
||||||
if sszType == "bitlist":
|
if sszType == "bitlist":
|
||||||
test &"**Skipping** {sszType} inputs - valid - skipped altogether":
|
test &"**Skipping** {sszType} inputs - valid - skipped altogether":
|
||||||
# TODO: serialization of "type BitList[maxLen] = distinct BitSeq is not supported"
|
# TODO: serialization of "type BitList[maxLen] = distinct BitSeq is not supported"
|
||||||
|
@ -269,7 +269,7 @@ proc runSSZtests() =
|
||||||
test &"Testing {sszType:12} inputs - valid" & skipped:
|
test &"Testing {sszType:12} inputs - valid" & skipped:
|
||||||
let path = SSZDir/sszType/"valid"
|
let path = SSZDir/sszType/"valid"
|
||||||
for pathKind, sszSubType in walkDir(path, relative = true):
|
for pathKind, sszSubType in walkDir(path, relative = true):
|
||||||
assert pathKind == pcDir
|
doAssert pathKind == pcDir
|
||||||
sszCheck(sszType, sszSubType)
|
sszCheck(sszType, sszSubType)
|
||||||
|
|
||||||
# TODO: nim-serialization forces us to use exceptions as control flow
|
# TODO: nim-serialization forces us to use exceptions as control flow
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
# Copyright (c) 2018-Present 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 http://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 http://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.
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
|
@ -9,6 +9,15 @@ shift
|
||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
source "$(dirname "$0")/vars.sh"
|
source "$(dirname "$0")/vars.sh"
|
||||||
|
|
||||||
|
if [[ ! -z "$1" ]]; then
|
||||||
|
BOOTSTRAP_NODE_ID=$1
|
||||||
|
BOOTSTRAP_ADDRESS_FILE="${SIMULATION_DIR}/node-${BOOTSTRAP_NODE_ID}/beacon_node.address"
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
BOOTSTRAP_NODE_ID=$MASTER_NODE
|
||||||
|
BOOTSTRAP_ADDRESS_FILE=$NETWORK_BOOTSTRAP_FILE
|
||||||
|
fi
|
||||||
|
|
||||||
# set up the environment
|
# set up the environment
|
||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
source "${SIM_ROOT}/../../env.sh"
|
source "${SIM_ROOT}/../../env.sh"
|
||||||
|
@ -23,20 +32,20 @@ if [ "${NAT:-}" == "1" ]; then
|
||||||
NAT_FLAG="--nat:any"
|
NAT_FLAG="--nat:any"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p $DATA_DIR/validators
|
mkdir -p "$DATA_DIR/validators"
|
||||||
rm -f $DATA_DIR/validators/*
|
rm -f $DATA_DIR/validators/*
|
||||||
|
|
||||||
if [[ $NODE_ID -lt $TOTAL_NODES ]]; then
|
if [[ $NODE_ID -lt $TOTAL_NODES ]]; then
|
||||||
FIRST_VALIDATOR_IDX=$(( (NUM_VALIDATORS / TOTAL_NODES) * NODE_ID ))
|
FIRST_VALIDATOR_IDX=$(( (NUM_VALIDATORS / TOTAL_NODES) * NODE_ID ))
|
||||||
LAST_VALIDATOR_IDX=$(( (NUM_VALIDATORS / TOTAL_NODES) * (NODE_ID + 1) - 1 ))
|
LAST_VALIDATOR_IDX=$(( (NUM_VALIDATORS / TOTAL_NODES) * (NODE_ID + 1) - 1 ))
|
||||||
|
|
||||||
pushd $VALIDATORS_DIR >/dev/null
|
pushd "$VALIDATORS_DIR" >/dev/null
|
||||||
cp $(seq -s " " -f v%07g.privkey $FIRST_VALIDATOR_IDX $LAST_VALIDATOR_IDX) $DATA_DIR/validators
|
cp $(seq -s " " -f v%07g.privkey $FIRST_VALIDATOR_IDX $LAST_VALIDATOR_IDX) "$DATA_DIR/validators"
|
||||||
popd >/dev/null
|
popd >/dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$BEACON_NODE_BIN \
|
$BEACON_NODE_BIN \
|
||||||
--bootstrap-file=$NETWORK_BOOTSTRAP_FILE \
|
--bootstrap-file=$BOOTSTRAP_ADDRESS_FILE \
|
||||||
--data-dir=$DATA_DIR \
|
--data-dir=$DATA_DIR \
|
||||||
--node-name=$NODE_ID \
|
--node-name=$NODE_ID \
|
||||||
--tcp-port=$PORT \
|
--tcp-port=$PORT \
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
# Read in variables
|
# Read in variables
|
||||||
set -a
|
set -a
|
||||||
|
# shellcheck source=/dev/null
|
||||||
source "$(dirname "$0")/vars.sh"
|
source "$(dirname "$0")/vars.sh"
|
||||||
|
|
||||||
cd $(dirname "$0")
|
cd $(dirname "$0")
|
||||||
|
|
|
@ -1,22 +1,26 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# https://github.com/koalaman/shellcheck/wiki/SC2034
|
||||||
|
# shellcheck disable=2034
|
||||||
|
true
|
||||||
|
|
||||||
PWD_CMD="pwd"
|
PWD_CMD="pwd"
|
||||||
# get native Windows paths on Mingw
|
# get native Windows paths on Mingw
|
||||||
uname | grep -qi mingw && PWD_CMD="pwd -W"
|
uname | grep -qi mingw && PWD_CMD="pwd -W"
|
||||||
|
|
||||||
cd $(dirname $0)
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
SIM_ROOT="$($PWD_CMD)"
|
SIM_ROOT="$($PWD_CMD)"
|
||||||
|
|
||||||
# Set a default value for the env vars usually supplied by a Makefile
|
# Set a default value for the env vars usually supplied by a Makefile
|
||||||
cd $(git rev-parse --show-toplevel)
|
cd "$(git rev-parse --show-toplevel)"
|
||||||
: ${GIT_ROOT:="$($PWD_CMD)"}
|
: ${GIT_ROOT:="$($PWD_CMD)"}
|
||||||
cd - &>/dev/null
|
cd - &>/dev/null
|
||||||
|
|
||||||
# When changing these, also update the readme section on running simulation
|
# When changing these, also update the readme section on running simulation
|
||||||
# so that the run_node example is correct!
|
# so that the run_node example is correct!
|
||||||
NUM_VALIDATORS=${VALIDATORS:-192}
|
NUM_VALIDATORS=${VALIDATORS:-192}
|
||||||
TOTAL_NODES=${NODES:-4}
|
TOTAL_NODES=${NODES:-2}
|
||||||
TOTAL_USER_NODES=${USER_NODES:-0}
|
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 ))
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
|
|
||||||
# initialize_beacon_state_from_eth1 (beaconstate.nim)
|
# initialize_beacon_state_from_eth1 (beaconstate.nim)
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.8.1/specs/core/0_beacon-chain.md#genesis
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#genesis
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
@ -44,15 +44,17 @@ suite "[Unit - Spec - Genesis] Genesis block checks " & preset():
|
||||||
)
|
)
|
||||||
discard "TODO"
|
discard "TODO"
|
||||||
|
|
||||||
|
test "Validators with more than 32 ETH":
|
||||||
|
discard "TODO"
|
||||||
|
|
||||||
|
test "More validators than minimum":
|
||||||
|
discard "TODO"
|
||||||
|
|
||||||
|
when false:
|
||||||
|
# TODO causes possible stack overflow in mainnet
|
||||||
test "Not enough validators":
|
test "Not enough validators":
|
||||||
discard initGenesisState(
|
discard initGenesisState(
|
||||||
num_validators = MIN_GENESIS_ACTIVE_VALIDATOR_COUNT.uint64 - 1,
|
num_validators = MIN_GENESIS_ACTIVE_VALIDATOR_COUNT.uint64 - 1,
|
||||||
genesis_time = MIN_GENESIS_TIME.uint64 - 1
|
genesis_time = MIN_GENESIS_TIME.uint64 - 1
|
||||||
)
|
)
|
||||||
discard "TODO"
|
discard "TODO"
|
||||||
|
|
||||||
test "Validators with more than 32 ETH":
|
|
||||||
discard "TODO"
|
|
||||||
|
|
||||||
test "More validators than minimum":
|
|
||||||
discard "TODO"
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
# process_attestation (beaconstate.nim)
|
# process_attestation (beaconstate.nim)
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.8.1/specs/core/0_beacon-chain.md#attestations
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#attestations
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
@ -14,8 +14,6 @@
|
||||||
import
|
import
|
||||||
# Standard library
|
# Standard library
|
||||||
unittest,
|
unittest,
|
||||||
# shims 0.19.6
|
|
||||||
stew/objects, # import default
|
|
||||||
# Specs
|
# Specs
|
||||||
../../beacon_chain/spec/[beaconstate, datatypes, helpers, validator],
|
../../beacon_chain/spec/[beaconstate, datatypes, helpers, validator],
|
||||||
# Mock helpers
|
# Mock helpers
|
||||||
|
@ -109,10 +107,6 @@ suite "[Unit - Spec - Block processing] Attestations " & preset():
|
||||||
# - source epoch in the future
|
# - source epoch in the future
|
||||||
# - invalid current source root
|
# - invalid current source root
|
||||||
# - bad source root
|
# - bad source root
|
||||||
# - non-zero crosslink data root
|
|
||||||
# - bad parent crosslink
|
|
||||||
# - bad crosslink start epoch
|
|
||||||
# - bad crosslink end epoch
|
|
||||||
# - inconsistent custody bits length
|
# - inconsistent custody bits length
|
||||||
# - non-empty custody bits in phase 0
|
# - non-empty custody bits in phase 0
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
|
|
||||||
# process_deposit (beaconstate.nim)
|
# process_deposit (beaconstate.nim)
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.8.1/specs/core/0_beacon-chain.md#deposits
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#deposits
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
|
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018 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 http://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 http://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.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue