Merge pull request #593 from status-im/devel

Testnet0 release 2019-11-25
This commit is contained in:
zah 2019-11-26 02:48:43 +02:00 committed by GitHub
commit 752369b6bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
118 changed files with 1208 additions and 803 deletions

View File

@ -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

View File

@ -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
.vscode/tasks.json vendored
View File

@ -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
Jenkinsfile vendored
View File

@ -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') {

View File

@ -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

View File

@ -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).

View File

@ -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'

View File

@ -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"

View File

@ -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)

View File

@ -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?

View File

@ -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

View File

@ -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

View File

@ -1,4 +0,0 @@
import
spec/datatypes, beacon_node_types
proc onBeaconBlock*(node: BeaconNode, blck: BeaconBlock) {.gcsafe.}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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 =

View File

@ -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)

View File

@ -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 =

View File

@ -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``.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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] =

View File

@ -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.

View File

@ -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 =

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -14,7 +14,7 @@ type
## which blocks are valid - in particular, blocks are not valid if they ## which blocks are valid - in particular, blocks are not valid if they
## come from the future as seen from the local clock. ## come from the future as seen from the local clock.
## ##
## https://github.com/ethereum/eth2.0-specs/blob/v0.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) =

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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 #

View File

@ -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

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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) =

View File

@ -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

View File

@ -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}"

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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]

View File

@ -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.} =

View File

@ -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"

View File

@ -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) =

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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":

View File

@ -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()

View File

@ -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.}

View File

@ -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.}

View File

@ -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.}

View File

@ -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.}

View File

@ -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.}

View File

@ -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.}

View File

@ -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.}

View File

@ -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.}

View File

@ -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():

View File

@ -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()

View File

@ -0,0 +1 @@
-d:ssz_testing

View File

@ -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

View File

@ -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.}

View File

@ -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 \

View File

@ -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")

View File

@ -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 ))

View File

@ -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"

View File

@ -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

View File

@ -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.}

View File

@ -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

View File

@ -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