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
environment:
# disable LFS file downloading during regular cloning
GIT_LFS_SKIP_SMUDGE: 1
init: # Scripts called at the very beginning
# Enable paths > 260 characters
- 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%" == "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
build_script:
@ -41,6 +37,6 @@ build_script:
test_script:
# 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_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

View File

@ -13,8 +13,6 @@ cache:
git:
# when multiple CI builds are queued, the tested commit needs to be in the last X commits cloned with "--depth X"
depth: 10
# disable LFS file downloading during regular cloning
lfs_skip_smudge: true
go:
- "1.12.x"
@ -39,7 +37,7 @@ matrix:
before_install:
- export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
- 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
env:
- NPROC=2
@ -50,11 +48,12 @@ matrix:
install:
# LFS test fixtures
# official test fixtures
- scripts/setup_official_tests.sh jsonTestsCache
script:
- 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}"
- 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",
"type": "shell",
"command": "nimble build",
"command": "make",
"group": {
"kind": "build",
"isDefault": true
@ -18,7 +18,7 @@
{
"label": "nim-beacon-chain test",
"type": "shell",
"command": "nimble test",
"command": "make test",
"group": {
"kind": "build",
"isDefault": true
@ -28,4 +28,4 @@
]
}
]
}
}

1
Jenkinsfile vendored
View File

@ -1,6 +1,5 @@
node('linux') {
stage('Clone') {
env.GIT_LFS_SKIP_SMUDGE = 1
checkout scm
}
stage('Build') {

View File

@ -24,7 +24,7 @@ all: | build-system-checks $(TOOLS)
# must be included after the default target
-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:
@[[ -e "$(BUILD_SYSTEM_DIR)/makefiles" ]] || { \
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
# 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
ifeq ($(DISABLE_LFS_SCRIPT), 0)
ifeq ($(DISABLE_TEST_FIXTURES_SCRIPT), 0)
V=$(V) scripts/setup_official_tests.sh
endif
$(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
* [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
* [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
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
- task: CacheBeta@1
displayName: 'cache LFS JSON fixtures'
displayName: 'cache official test fixtures'
inputs:
key: jsonTestsCache
path: jsonTestsCache
@ -64,12 +64,11 @@ jobs:
export PATH="/c/custom/${MINGW_DIR}/bin:$PATH"
echo "Fetching submodules"
git config --global core.longpaths true
export GIT_LFS_SKIP_SMUDGE=1
git submodule --quiet update --init --recursive
scripts/setup_official_tests.sh jsonTestsCache
mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} CI_CACHE=NimBinaries update
mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} fetch-dlls
mingw32-make -j2 ARCH_OVERRIDE=${PLATFORM} P2PD_CACHE=p2pdCache
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'

View File

@ -46,7 +46,7 @@ proc buildBinary(name: string, srcDir = "./", params = "", cmdParams = "", lang
### tasks
task test, "Run all tests":
# 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
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
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
deques, options, sequtils, tables,
deques, sequtils, tables,
chronicles, stew/bitseqs, json_serialization/std/sets,
./spec/[beaconstate, datatypes, crypto, digest, helpers, validator],
./extras, ./ssz, ./block_pool,
@ -7,7 +7,7 @@ import
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
# probably be removed as a dependency of AttestationPool (or some other
# smart refactoring)
@ -129,7 +129,7 @@ proc slotIndex(
int(attestationSlot - pool.startingSlot)
proc updateLatestVotes(
func updateLatestVotes(
pool: var AttestationPool, state: BeaconState, attestationSlot: Slot,
participants: seq[ValidatorIndex], blck: BlockRef) =
for validator in participants:
@ -245,7 +245,7 @@ proc add*(pool: var AttestationPool,
validations = 1,
cat = "filtering"
proc addUnresolved*(pool: var AttestationPool, attestation: Attestation) =
func addUnresolved*(pool: var AttestationPool, attestation: Attestation) =
pool.unresolved[attestation.data.beacon_block_root] =
UnresolvedAttestation(
attestation: attestation,
@ -333,15 +333,6 @@ proc getAttestationsForBlock*(
if result.len >= MAX_ATTESTATIONS:
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) =
var
done: seq[Eth2Digest]
@ -365,6 +356,6 @@ proc resolve*(pool: var AttestationPool, cache: var StateData) =
pool.add(cache.data.data, a.blck, a.attestation)
proc latestAttestation*(
func latestAttestation*(
pool: AttestationPool, pubKey: ValidatorPubKey): BlockRef =
pool.latestAttestations.getOrDefault(pubKey)

View File

@ -86,6 +86,12 @@ proc putStateRoot*(db: BeaconChainDB, root: Eth2Digest, slot: Slot,
proc putBlock*(db: BeaconChainDB, value: BeaconBlock) =
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) =
db.backend.put(subkey(kHeadBlock), key.data) # TODO head block?

View File

@ -40,6 +40,34 @@ declareCounter beacon_blocks_received,
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.}
func localValidatorsDir(conf: BeaconNodeConf): string =
@ -81,7 +109,7 @@ proc getStateFromSnapshot(node: BeaconNode, state: var BeaconState): bool =
dataDir = conf.dataDir.string, snapshot = snapshotPath
quit 1
else:
error "missing genesis file"
debug "No genesis file in data directory", genesisPath
writeGenesisFile = true
genesisPath = snapshotPath
else:
@ -93,16 +121,19 @@ proc getStateFromSnapshot(node: BeaconNode, state: var BeaconState): bool =
try:
state = SSZ.decode(snapshotContents, BeaconState)
except SerializationError as err:
except SerializationError:
error "Failed to import genesis file", path = genesisPath
quit 1
info "Loaded genesis state", path = genesisPath
if writeGenesisFile:
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)
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
result = true
@ -131,16 +162,11 @@ proc useBootstrapFile(node: BeaconNode, bootstrapFile: string) =
proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async.} =
new result
result.onBeaconBlock = onBeaconBlock
result.config = conf
result.networkIdentity = getPersistentNetIdentity(conf)
result.nickname = if conf.nodeName == "auto": shortForm(result.networkIdentity)
else: conf.nodeName
template fail(args: varargs[untyped]) =
stderr.write args, "\n"
quit 1
for bootNode in conf.bootstrapNodes:
result.addBootstrapNode BootstrapAddr.init(bootNode)
@ -164,22 +190,25 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async
var eth1MonitorStartBlock: Eth2Digest
if result.db.getHeadBlock().isNone():
var state: BeaconState
if not result.getStateFromSnapshot(state):
var state = new BeaconState
# TODO getStateFromSnapshot never returns false - it quits..
if not result.getStateFromSnapshot(state[]):
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()
else:
stderr.write "No state snapshot (or web3 URL) provided\n"
quit 1
state = await result.mainchainMonitor.getGenesis()
state[] = await result.mainchainMonitor.getGenesis()
else:
eth1MonitorStartBlock = state.eth1Data.block_hash
result.commitGenesisState(state)
result.commitGenesisState(state[])
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.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
# time to do so?
let sync = result.network.protocolState(BeaconSync)
sync.node = result
sync.db = result.db
sync.init(
result.blockPool, result.forkVersion,
proc(blck: BeaconBlock) = onBeaconBlock(result, blck))
result.stateCache = result.blockPool.loadTailState()
result.justifiedStateCache = result.stateCache
@ -245,9 +275,11 @@ proc addLocalValidator(
let idx = state.validators.findIt(it.pubKey == pubKey)
if idx == -1:
warn "Validator not in registry", pubKey
else:
node.attachedValidators.addLocalValidator(ValidatorIndex(idx), pubKey, privKey)
# We allow adding a validator even if its key is not in the state registry:
# it might be that the deposit for this validator has not yet been processed
warn "Validator not in registry (yet?)", pubKey
node.attachedValidators.addLocalValidator(pubKey, privKey)
proc addLocalValidators(node: BeaconNode, state: BeaconState) =
for validatorKeyFile in node.config.validators:
@ -259,7 +291,7 @@ proc addLocalValidators(node: BeaconNode, state: BeaconState) =
info "Local validators attached ", count = node.attachedValidators.count
proc getAttachedValidator(node: BeaconNode,
func getAttachedValidator(node: BeaconNode,
state: BeaconState,
idx: ValidatorIndex): AttachedValidator =
let validatorKey = state.validators[idx].pubkey
@ -287,7 +319,7 @@ proc updateHead(node: BeaconNode, slot: Slot): BlockRef =
newHead
proc sendAttestation(node: BeaconNode,
state: BeaconState,
fork: Fork,
validator: AttachedValidator,
attestationData: AttestationData,
committeeLen: int,
@ -295,7 +327,7 @@ proc sendAttestation(node: BeaconNode,
logScope: pcs = "send_attestation"
let
validatorSignature = await validator.signAttestation(attestationData, state)
validatorSignature = await validator.signAttestation(attestationData, fork)
var aggregationBits = CommitteeValidatorsBits.init(committeeLen)
aggregationBits.raiseBit indexInCommittee
@ -353,29 +385,25 @@ proc proposeBlock(node: BeaconNode,
doAssert false, "head slot matches proposal slot (!)"
# return
# Get eth1data which may be async
# TODO it's a bad idea to get eth1data async because that might delay block
# 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())
# Advance state to the slot immediately preceding the one we're creating a
# block for - potentially we will be processing empty slots along the way.
let (nroot, nblck) = node.blockPool.withState(
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
# some validations.
let
fork = state.fork
blockBody = BeaconBlockBody(
randao_reveal: validator.genRandaoReveal(state, slot),
randao_reveal: validator.genRandaoReveal(fork, slot),
eth1_data: eth1data,
attestations:
node.attestationPool.getAttestationsForBlock(state, slot),
@ -388,10 +416,7 @@ proc proposeBlock(node: BeaconNode,
body: blockBody,
# TODO: This shouldn't be necessary if OpaqueBlob is the default
signature: ValidatorSig(kind: OpaqueBlob))
var
tmpState = hashedState
discard state_transition(tmpState, newBlock, {skipValidation})
# TODO only enable in fast-fail debugging situations
# otherwise, bad attestations can bring down network
@ -402,8 +427,11 @@ proc proposeBlock(node: BeaconNode,
let blockRoot = signing_root(newBlock)
# 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 =
await validator.signBlockProposal(state, slot, blockRoot)
await validator.signBlockProposal(fork, slot, blockRoot)
(blockRoot, newBlock)
@ -551,7 +579,7 @@ proc handleAttestations(node: BeaconNode, head: BlockRef, slot: Slot) =
for a in attestations:
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):
Future[BlockRef] {.async.} =
@ -786,19 +814,26 @@ proc createPidFile(filename: string) =
gPidFile = filename
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
# actually need to make this part of normal application flow -
# losing all connections might happen at any time and we should be
# prepared to handle it.
waitFor node.connectToNetwork()
let
head = node.blockPool.head
finalizedHead = node.blockPool.finalizedHead
info "Starting beacon node",
version = fullVersionStr,
timeSinceFinalization =
int64(node.blockPool.finalizedHead.slot.toBeaconTime()) -
int64(finalizedHead.slot.toBeaconTime()) -
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,
SECONDS_PER_SLOT,
SPEC_VERSION,
@ -806,7 +841,12 @@ proc start(node: BeaconNode, headState: BeaconState) =
cat = "init",
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()
func formatGwei(amount: uint64): string =
@ -896,8 +936,11 @@ when hasPrompt:
of "attached_validators_balance":
var balance = uint64(0)
for _, validator in node.attachedValidators.validators:
balance += node.stateCache.data.data.balances[validator.idx]
# TODO slow linear scan!
for idx, b in node.stateCache.data.data.balances:
if node.getAttachedValidator(
node.stateCache.data.data, ValidatorIndex(idx)) != nil:
balance += b
formatGwei(balance)
else:
@ -923,7 +966,7 @@ when hasPrompt:
proc statusBarUpdatesPollingLoop() {.async.} =
while true:
update statusBar
await sleepAsync(1000)
await sleepAsync(chronos.seconds(1))
traceAsyncErrors statusBarUpdatesPollingLoop()
@ -1027,11 +1070,10 @@ when isMainModule:
var node = waitFor BeaconNode.init(config)
when hasPrompt: initPrompt(node)
# TODO slightly ugly to rely on node.stateCache state here..
if node.nickname != "":
dynamicLogScope(node = node.nickname): node.start(node.stateCache.data.data)
dynamicLogScope(node = node.nickname): node.start()
else:
node.start(node.stateCache.data.data)
node.start()
of makeDeposits:
createDir(config.depositsDir)
@ -1052,9 +1094,6 @@ when isMainModule:
config.depositPrivateKey)
of query:
var
trieDB = trieDB newChainDb(config.databaseDir)
case config.queryCmd
of QueryCmd.nimQuery:
# TODO: This will handle a simple subset of Nim using

View File

@ -1,45 +1,10 @@
import
sets, deques, tables, options,
stew/[endians2],
deques, tables, options,
stew/[endians2], chronicles,
spec/[datatypes, crypto, digest],
beacon_chain_db, conf, mainchain_monitor, eth2_network, time
beacon_chain_db
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
@ -153,7 +118,7 @@ type
## Tree of blocks pointing back to a finalized block on the chain we're
## interested in - we call that block the tail
blocksBySlot*: Table[uint64, seq[BlockRef]]
blocksBySlot*: Table[Slot, seq[BlockRef]]
tail*: BlockRef ##\
## The earliest finalized block we know about
@ -207,6 +172,10 @@ type
## 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,
## 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
slot*: Slot
@ -226,7 +195,6 @@ type
ValidatorConnection* = object
AttachedValidator* = ref object
idx*: ValidatorIndex
pubKey*: ValidatorPubKey
case kind*: ValidatorKind
@ -238,12 +206,15 @@ type
ValidatorPool* = object
validators*: Table[ValidatorPubKey, AttachedValidator]
RequestManager* = object
network*: Eth2Node
FetchRecord* = object
root*: Eth2Digest
historySlots*: uint64
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"
proc parent*(bs: BlockSlot): BlockSlot =
func parent*(bs: BlockSlot): BlockSlot =
BlockSlot(
blck: if bs.slot > bs.blck.slot: bs.blck else: bs.blck.parent,
slot: bs.slot - 1
)
proc link(parent, child: BlockRef) =
func link(parent, child: BlockRef) =
doAssert (not (parent.root == Eth2Digest() or child.root == Eth2Digest())),
"blocks missing root!"
doAssert parent.root != child.root, "self-references not allowed"
@ -22,18 +22,18 @@ proc link(parent, child: BlockRef) =
child.parent = parent
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(
root: root,
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)
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`
assert(not blck.isNil)
doAssert(not blck.isNil)
var ret = blck
while ret.parent != nil and ret.slot > slot:
@ -81,6 +81,7 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
link(newRef, curRef)
curRef = curRef.parent
blocks[curRef.root] = curRef
trace "Populating block pool", key = curRef.root, val = curRef
if latestStateRoot.isNone() and db.containsState(blck.state_root):
latestStateRoot = some(blck.state_root)
@ -90,10 +91,10 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
else:
headRef = tailRef
var blocksBySlot = initTable[uint64, seq[BlockRef]]()
var blocksBySlot = initTable[Slot, seq[BlockRef]]()
for _, b in tables.pairs(blocks):
let slot = db.getBlock(b.root).get().slot
blocksBySlot.mgetOrPut(slot.uint64, @[]).add(b)
blocksBySlot.mgetOrPut(slot, @[]).add(b)
let
# 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,
"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(
pending: initTable[Eth2Digest, BeaconBlock](),
missing: initTable[Eth2Digest, MissingBlock](),
@ -132,11 +137,21 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
heads: @[head]
)
proc addSlotMapping(pool: BlockPool, slot: uint64, br: BlockRef) =
proc addSlotMapping(pool: BlockPool, br: BlockRef) =
proc addIfMissing(s: var seq[BlockRef], v: BlockRef) =
if v notin s:
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*(
pool: BlockPool, state: var StateData, bs: BlockSlot) {.gcsafe.}
@ -154,8 +169,9 @@ proc addResolvedBlock(
link(parent, 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
pool.db.putBlock(blockRoot, blck)
@ -306,9 +322,9 @@ proc add*(
(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
pool.blocks.getOrDefault(root)
pool.blocks.getOrDefault(root, nil)
proc getBlockRange*(pool: BlockPool, headBlock: Eth2Digest,
startSlot: Slot, skipStep: Natural,
@ -337,13 +353,20 @@ proc getBlockRange*(pool: BlockPool, headBlock: Eth2Digest,
result = output.len
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
template skip(n: int) =
for i in 0 ..< n:
if b.parent == nil:
trace "stopping at parentless block", slot = b.slot, root = b.root
return
b = b.parent
if b == nil: return
# 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
@ -365,6 +388,7 @@ proc getBlockRange*(pool: BlockPool, headBlock: Eth2Digest,
while b != nil and result > 0:
dec result
output[result] = b
trace "getBlockRange result", position = result, blockSlot = b.slot
skip skipStep
proc get*(pool: BlockPool, blck: BlockRef): BlockData =
@ -385,7 +409,7 @@ proc get*(pool: BlockPool, root: Eth2Digest): Option[BlockData] =
else:
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
## blocks-to-resolve)
result = pool.getRef(root)
@ -393,11 +417,11 @@ proc getOrResolve*(pool: var BlockPool, root: Eth2Digest): BlockRef =
if result.isNil:
pool.missing[root] = MissingBlock(slots: 1)
iterator blockRootsForSlot*(pool: BlockPool, slot: uint64|Slot): Eth2Digest =
for br in pool.blocksBySlot.getOrDefault(slot.uint64, @[]):
iterator blockRootsForSlot*(pool: BlockPool, slot: Slot): Eth2Digest =
for br in pool.blocksBySlot.getOrDefault(slot, @[]):
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 -
## to be called periodically but not too often (once per slot?)
var done: seq[Eth2Digest]
@ -580,6 +604,44 @@ func isAncestorOf*(a, b: BlockRef): bool =
else:
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) =
## Update what we consider to be the current head, as given by the fork
## choice.
@ -587,6 +649,7 @@ proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
## of operations naturally becomes important here - after updating the head,
## blocks that were once considered potential candidates for a tree will
## now fall from grace, or no longer be considered resolved.
doAssert blck.parent != nil or blck.slot == 0
logScope: pcs = "fork_choice"
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))
if lastHead.blck != blck.parent:
info "Updated No head block (new parent)",
info "Updated head block (new parent)",
lastHeadRoot = shortLog(lastHead.blck.root),
parentRoot = shortLog(blck.parent.root),
stateRoot = shortLog(state.data.root),
@ -625,7 +688,7 @@ proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
# spurious times
beacon_reorgs_total.inc()
else:
info "Updated No head block",
info "Updated head block",
stateRoot = shortLog(state.data.root),
headBlockRoot = shortLog(state.blck.root),
stateSlot = shortLog(state.data.data.slot),
@ -634,10 +697,9 @@ proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
cat = "fork_choice"
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?
finalizedHead =
blck.findAncestorBySlot(
state.data.data.finalized_checkpoint.epoch.compute_start_slot_at_epoch())
finalizedHead = blck.findAncestorBySlot(finalizedEpochStartSlot)
doAssert (not finalizedHead.blck.isNil),
"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),
cat = "fork_choice"
pool.finalizedHead = finalizedHead
var cur = finalizedHead.blck
while cur != pool.finalizedHead.blck:
# 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:
if child != cur:
pool.blocks.del(child.root)
pool.delBlockAndState(child.root)
pool.delSlotMapping(child)
else:
pool.delFinalizedStateIfNeeded(child)
cur.parent.children = @[cur]
cur = cur.parent
pool.finalizedHead = finalizedHead
let hlen = pool.heads.len
for i in 0..<hlen:
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):
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
## as the latest finalized block

View File

@ -31,7 +31,7 @@ type
BeaconNodeConf* = object
logLevel* {.
defaultValue: enabledLogLevel
defaultValue: LogLevel.DEBUG
desc: "Sets the log level."
name: "log-level" }: LogLevel

View File

@ -70,7 +70,7 @@ proc main() {.async.} =
web3.privateKey = initPrivateKey(cfg.privateKey)
else:
let accounts = await web3.provider.eth_accounts()
assert(accounts.len > 0)
doAssert(accounts.len > 0)
web3.defaultAccount = accounts[0]
case cfg.cmd

View File

@ -272,7 +272,7 @@ else:
proc saveConnectionAddressFile*(node: Eth2Node, filename: string) =
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 =
Json.loadFile(filename, PeerInfo)

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# Temporary dumping ground for extra types and helpers that could make it into

View File

@ -4,7 +4,7 @@ import
./spec/[datatypes, crypto, helpers],
./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:
blck
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
# strategy for storing states and justification points - it should nonetheless
# be close in terms of functionality.
proc lmdGhost*(
func lmdGhost*(
pool: AttestationPool, start_state: BeaconState,
start_block: BlockRef): BlockRef =
# TODO: a Fenwick Tree datastructure to keep track of cumulated votes

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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 strutils, os, tables
import confutils, chronicles, chronos, libp2p/daemon/daemonapi,

View File

@ -1,5 +1,4 @@
import
ospaths,
stew/endians2, stint,
./extras, ./ssz,
spec/[crypto, datatypes, digest, helpers]
@ -41,7 +40,7 @@ const eth1BlockHash* = block:
x
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())
bytes.data[0] = BLS_WITHDRAWAL_PREFIX.uint8
bytes

View File

@ -85,8 +85,6 @@ type
TransmissionError* = object of CatchableError
ResponseSizeLimitReached* = object of CatchableError
const
defaultIncomingReqTimeout = 5000
HandshakeTimeout = FaultOrError
@ -337,9 +335,6 @@ proc sendNotificationMsg(peer: Peer, protocolId: string, requestBytes: Bytes) {.
if sent != bytes.len:
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
# I hope to reduce this when I increse the reliance on output streams.
proc sendResponseChunkBytes(responder: UntypedResponder, payload: Bytes) {.async.} =
@ -604,12 +599,6 @@ proc p2pProtocolBackendImpl*(p: P2PProtocol): Backend =
try:
`tracing`
`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`:
`await` sendErrorResponse(`peerVar`, `streamVar`, ServerError, `errVar`.msg)

View File

@ -85,8 +85,6 @@ type
TransmissionError* = object of CatchableError
ResponseSizeLimitReached* = object of CatchableError
const
defaultIncomingReqTimeout = 5000
HandshakeTimeout = FaultOrError
@ -187,21 +185,26 @@ proc readChunk(stream: P2PStream,
proc readSizePrefix(transp: StreamTransport,
deadline: Future[void]): Future[int] {.async.} =
trace "about to read msg size prefix"
var parser: VarintParser[uint64, ProtoBuf]
while true:
var nextByte: byte
var readNextByte = transp.readExactly(addr nextByte, 1)
await readNextByte or deadline
if not readNextByte.finished:
trace "size prefix byte not received in time"
return -1
case parser.feedByte(nextByte)
of Done:
let res = parser.getResult
if res > uint64(REQ_RESP_MAX_SIZE):
trace "size prefix outside of range", res
return -1
else:
trace "got size prefix", res
return int(res)
of Overflow:
trace "size prefix overflow"
return -1
of Incomplete:
continue
@ -209,26 +212,39 @@ proc readSizePrefix(transp: StreamTransport,
proc readMsgBytes(stream: P2PStream,
withResponseCode: bool,
deadline: Future[void]): Future[Bytes] {.async.} =
trace "about to read message bytes", withResponseCode
try:
if withResponseCode:
var responseCode: byte
trace "about to read response code"
var readResponseCode = stream.transp.readExactly(addr responseCode, 1)
await readResponseCode or deadline
if not readResponseCode.finished:
trace "response code not received in time"
return
if responseCode > ResponseCode.high.byte:
trace "invalid response code", responseCode
return
if responseCode > ResponseCode.high.byte: return
logScope: responseCode = ResponseCode(responseCode)
trace "got response code"
case ResponseCode(responseCode)
of InvalidRequest, ServerError:
let responseErrMsg = await readChunk(stream, string, false, deadline)
debug "P2P request resulted in error", responseErrMsg
return
of Success:
# The response is OK, the execution continues below
discard
var sizePrefix = await readSizePrefix(stream.transp, deadline)
trace "got msg size prefix", sizePrefix
if sizePrefix == -1:
debug "Failed to read an incoming message size prefix", peer = stream.peer
return
@ -237,12 +253,17 @@ proc readMsgBytes(stream: P2PStream,
debug "Received SSZ with zero size", peer = stream.peer
return
trace "about to read msg bytes"
var msgBytes = newSeq[byte](sizePrefix)
var readBody = stream.transp.readExactly(addr msgBytes[0], sizePrefix)
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
except TransportIncompleteError:
return @[]
@ -337,9 +358,6 @@ proc sendNotificationMsg(peer: Peer, protocolId: string, requestBytes: Bytes) {.
if sent != bytes.len:
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
# I hope to reduce this when I increse the reliance on output streams.
proc sendResponseChunkBytes(responder: UntypedResponder, payload: Bytes) {.async.} =
@ -572,6 +590,11 @@ proc p2pProtocolBackendImpl*(p: P2PProtocol): Backend =
msg.defineThunk quote do:
proc `thunkName`(`daemonVar`: `DaemonAPI`,
`streamVar`: `P2PStream`) {.async, gcsafe.} =
when chronicles.runtimeFilteringEnabled:
setLogLevel(LogLevel.TRACE)
defer: setLogLevel(LogLevel.DEBUG)
trace "incoming " & `msgNameLit` & " stream"
defer:
`await` safeClose(`streamVar`)
@ -587,6 +610,7 @@ proc p2pProtocolBackendImpl*(p: P2PProtocol): Backend =
var `msgVar`: `msgRecName`
try:
trace "about to decode incoming msg"
`msgVar` = decode(`Format`, `msgBytesVar`, `msgRecName`)
except SerializationError as `errVar`:
`await` sendErrorResponse(`peerVar`, `streamVar`, `errVar`,
@ -603,13 +627,8 @@ proc p2pProtocolBackendImpl*(p: P2PProtocol): Backend =
try:
`tracing`
trace "about to execute user handler"
`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`:
try:
`await` sendErrorResponse(`peerVar`, `streamVar`, ServerError, `errVar`.msg)

View File

@ -1,12 +1,11 @@
import
chronos, web3, json,
chronos, web3, json, chronicles,
spec/[datatypes, digest, crypto, beaconstate, helpers],
./extras
type
MainchainMonitor* = ref object
web3Url: string
web3: Web3
depositContractAddress: Address
genesisState: ref BeaconState
@ -21,6 +20,8 @@ type
eth1Block: BlockHash
eth1Data*: Eth1Data
runFut: Future[void]
QueueElement = (BlockHash, DepositData)
@ -39,32 +40,48 @@ contract(DepositContract):
const MIN_GENESIS_TIME = 0
proc updateEth1Data*(m: MainchainMonitor) {.async.} =
let ns = m.web3.contractSender(DepositContract, m.depositContractAddress)
# 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)
proc updateEth1Data(m: MainchainMonitor, count: uint64, root: FixedBytes[32]) =
m.eth1Data.deposit_count = count
m.eth1Data.deposit_root.data = array[32, byte](root)
m.eth1Data.block_hash.data = array[32, byte](m.eth1Block)
proc processDeposits(m: MainchainMonitor) {.async.} =
proc processDeposits(m: MainchainMonitor, web3: Web3) {.async.} =
while true:
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)
m.pendingDeposits.add(dep)
inc m.depositCount
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
var h: Eth2Digest
h.data = array[32, byte](blkHash)
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):
# 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 = nil
# TODO: Set curBlock to blk number
# TODO: This should be progressing in more independent way.
# 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 =
not m.web3.isNil
not m.runFut.isNil
proc getGenesis*(m: MainchainMonitor): Future[BeaconState] {.async.} =
if m.genesisState.isNil:
@ -95,11 +112,33 @@ proc getGenesis*(m: MainchainMonitor): Future[BeaconState] {.async.} =
doAssert(not m.genesisState.isNil)
return m.genesisState[]
proc run(m: MainchainMonitor) {.async.} =
m.web3 = await newWeb3(m.web3Url)
let ns = m.web3.contractSender(DepositContract, m.depositContractAddress)
proc getBlockNumber(web3: Web3, hash: BlockHash): Future[Quantity] {.async.} =
let blk = await web3.provider.eth_getBlockByHash(hash, false)
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 amount = bytes_to_int(array[8, byte](amount))
@ -111,14 +150,27 @@ proc run(m: MainchainMonitor) {.async.} =
signature: ValidatorSig.init(array[96, byte](signature)))))
try:
await m.processDeposits()
await processFut
finally:
await s.unsubscribe()
# await m.web3.close()
m.web3 = nil
proc start*(m: MainchainMonitor) =
asyncCheck m.run()
proc start(m: MainchainMonitor, delayBeforeStart: Duration) =
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] =
# 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,
eth/async_utils
type
RequestManager* = object
network*: Eth2Node
proc init*(T: type RequestManager, network: Eth2Node): T =
T(network: network)

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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
@ -11,7 +11,7 @@ import
../extras, ../ssz,
./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 =
## Check if ``leaf`` at ``index`` verifies against the Merkle ``root`` and
## ``branch``.
@ -29,13 +29,13 @@ func is_valid_merkle_branch*(leaf: Eth2Digest, branch: openarray[Eth2Digest], de
value = eth2hash(buf)
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*(
state: var BeaconState, index: ValidatorIndex, delta: Gwei) =
# Increase the validator balance at index ``index`` by ``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*(
state: var BeaconState, index: ValidatorIndex, delta: Gwei) =
## Decrease the validator balance at index ``index`` by ``delta``, with
@ -46,7 +46,7 @@ func decrease_balance*(
else:
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*(
state: var BeaconState, deposit: Deposit, flags: UpdateFlags = {}): bool =
# Process an Eth1 deposit, registering a validator or increasing its balance.
@ -102,13 +102,13 @@ func process_deposit*(
true
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#compute_activation_exit_epoch
func compute_activation_exit_epoch*(epoch: Epoch): 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 =
## Return the epoch during which validator activations and exits initiated in
## ``epoch`` take effect.
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 =
# Return the validator churn limit for the current epoch.
let active_validator_indices =
@ -116,7 +116,7 @@ func get_validator_churn_limit(state: BeaconState): uint64 =
max(MIN_PER_EPOCH_CHURN_LIMIT,
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,
index: ValidatorIndex) =
# Initiate the exit of the validator with index ``index``.
@ -146,13 +146,23 @@ func initiate_validator_exit*(state: var BeaconState,
validator.withdrawable_epoch =
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
func slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex,
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#slash_validator
proc slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex,
stateCache: var StateCache) =
# Slash the validator with index ``index``.
let epoch = get_current_epoch(state)
initiate_validator_exit(state, 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.withdrawable_epoch =
max(validator.withdrawable_epoch, epoch + EPOCHS_PER_SLASHINGS_VECTOR)
@ -174,7 +184,7 @@ func slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex,
increase_balance(
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*(
eth1_block_hash: Eth2Digest,
eth1_timestamp: uint64,
@ -213,14 +223,18 @@ func initialize_beacon_state_from_eth1*(
)
)
# Process deposits
let leaves = deposits.mapIt(it.data)
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))
# Seed RANDAO with Eth1 entropy
state.randao_mixes.fill(eth1_block_hash)
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
for validator_index in 0 ..< state.validators.len:
@ -237,7 +251,7 @@ func initialize_beacon_state_from_eth1*(
state
proc is_valid_genesis_state*(state: BeaconState): bool =
func is_valid_genesis_state*(state: BeaconState): bool =
if state.genesis_time < MIN_GENESIS_TIME:
return false
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
# 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,
slot: Slot): Eth2Digest =
# Return the block root at a recent ``slot``.
@ -267,12 +281,12 @@ func get_block_root_at_slot*(state: BeaconState,
doAssert slot < state.slot
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 =
# Return the block root at the start of a recent ``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 =
## Return the combined effective balance of the ``indices``. (1 Gwei minimum
## 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?
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#registry-updates
func process_registry_updates*(state: var BeaconState) =
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#registry-updates
proc process_registry_updates*(state: var BeaconState) =
## Process activation eligibility and ejections
## 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
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)
## Queue validators eligible for activation and not dequeued for activation
@ -321,7 +343,7 @@ func process_registry_updates*(state: var BeaconState) =
validator.activation_epoch =
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*(
state: BeaconState, indexed_attestation: IndexedAttestation): bool =
## Check if ``indexed_attestation`` has valid indices and signature.
@ -342,17 +364,19 @@ proc is_valid_indexed_attestation*(
return false
# Verify aggregate signature
result = bls_verify(
if not bls_verify(
bls_aggregate_pubkeys(mapIt(indices, state.validators[it.int].pubkey)),
hash_tree_root(indexed_attestation.data).data,
indexed_attestation.signature,
get_domain(
state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch)
)
if not result:
):
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,
data: AttestationData,
bits: CommitteeValidatorsBits,
@ -365,8 +389,8 @@ func get_attesting_indices*(state: BeaconState,
if bits[i]:
result.incl index
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/specs/core/0_beacon-chain.md#get_indexed_attestation
func get_indexed_attestation*(state: BeaconState, attestation: 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,
stateCache: var StateCache): IndexedAttestation =
# Return the indexed attestation corresponding to ``attestation``.
let
@ -389,7 +413,7 @@ func get_indexed_attestation*(state: BeaconState, attestation: Attestation,
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*(
state: BeaconState, attestation: Attestation, flags: UpdateFlags,
stateCache: var StateCache): bool =
@ -486,7 +510,7 @@ proc process_attestation*(
else:
false
proc makeAttestationData*(
func makeAttestationData*(
state: BeaconState, slot: Slot, committee_index: uint64,
beacon_block_root: Eth2Digest): AttestationData =
## Create an attestation / vote for the block `beacon_block_root` using the

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# 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 =
($x)[0..7]
proc hash*(x: BlsValue): Hash {.inline.} =
func hash*(x: BlsValue): Hash {.inline.} =
if x.kind == Real:
hash x.blsValue.getBytes()
else:
@ -145,27 +145,27 @@ func pubKey*(pk: ValidatorPrivKey): ValidatorPubKey =
else:
pk.getKey
proc init(T: type VerKey): VerKey =
func init(T: type VerKey): VerKey =
result.point.inf()
proc init(T: type SigKey): SigKey =
func init(T: type SigKey): SigKey =
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())
for value in values:
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
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 =
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*(
pubkey: ValidatorPubKey, msg: openArray[byte], sig: ValidatorSig,
domain: Domain): bool =
@ -215,7 +215,7 @@ func fromBytes*[T](R: type BlsValue[T], bytes: openarray[byte]): R =
if not success:
# TODO: chronicles trace
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
func fromHex*[T](R: type BlsValue[T], hexStr: string): R =

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# 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.".}
const
SPEC_VERSION* = "0.9.1" ## \
SPEC_VERSION* = "0.9.2" ## \
## Spec version we're aiming to be compatible with, right now
## TODO: improve this scheme once we can negotiate versions in protocol
# 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 ##\
## compute_epoch_at_slot(GENESIS_SLOT)
@ -67,11 +67,34 @@ const
# Not part of spec. Still useful, pending removing usage if appropriate.
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.}
type
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
# 32-bit and 64-bit word platforms.
# TODO VALIDATOR_REGISTRY_LIMIT is 1 shl 40 in 0.8.3, and
@ -84,18 +107,18 @@ type
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
proposer_index*: uint64
header_1*: 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
attestation_1*: 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
# TODO ValidatorIndex, but that doesn't serialize properly
attesting_indices*: List[uint64, MAX_VALIDATORS_PER_COMMITTEE]
@ -104,18 +127,18 @@ type
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
aggregation_bits*: CommitteeValidatorsBits
data*: AttestationData
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
epoch*: Epoch
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
slot*: Slot
index*: uint64
@ -127,21 +150,21 @@ type
source*: 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
proof*: array[DEPOSIT_CONTRACT_TREE_DEPTH + 1, Eth2Digest] ##\
## Merkle path to deposit data list root
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
pubkey*: ValidatorPubKey
withdrawal_credentials*: Eth2Digest
amount*: uint64
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
epoch*: Epoch ##\
## Earliest epoch when voluntary exit can be processed
@ -149,7 +172,7 @@ type
validator_index*: uint64
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
## 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
@ -170,7 +193,7 @@ type
signature*: ValidatorSig ##\
## 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
slot*: Slot
parent_root*: Eth2Digest
@ -178,7 +201,7 @@ type
body_root*: Eth2Digest
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
randao_reveal*: ValidatorSig
eth1_data*: Eth1Data
@ -191,7 +214,7 @@ type
deposits*: List[Deposit, MAX_DEPOSITS]
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
# Versioning
genesis_time*: uint64
@ -243,7 +266,7 @@ type
current_justified_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
pubkey*: ValidatorPubKey
@ -266,7 +289,7 @@ type
withdrawable_epoch*: Epoch ##\
## 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
aggregation_bits*: CommitteeValidatorsBits
data*: AttestationData
@ -276,12 +299,12 @@ type
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
block_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
# TODO: Spec introduced an alias for Version = array[4, byte]
# and a default parameter to compute_domain
@ -291,7 +314,7 @@ type
epoch*: Epoch ##\
## 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
deposit_root*: Eth2Digest
deposit_count*: uint64
@ -352,15 +375,20 @@ macro fieldMaxLen*(x: typed): untyped =
return newLit(0)
let size = case $x[1]
# Obsolete
of "pubkeys",
"compact_validators",
"aggregation_bits",
"custody_bits": int64(MAX_VALIDATORS_PER_COMMITTEE)
# IndexedAttestation
of "attesting_indices": MAX_VALIDATORS_PER_COMMITTEE
# BeaconBlockBody
of "proposer_slashings": MAX_PROPOSER_SLASHINGS
of "attester_slashings": MAX_ATTESTER_SLASHINGS
of "attestations": MAX_ATTESTATIONS
of "deposits": MAX_DEPOSITS
of "voluntary_exits": MAX_VOLUNTARY_EXITS
# BeaconState
of "historical_roots": HISTORICAL_ROOTS_LIMIT
of "eth1_data_votes": SLOTS_PER_ETH1_VOTING_PERIOD
of "validators": VALIDATOR_REGISTRY_LIMIT
@ -424,6 +452,12 @@ template ethTimeUnit(typ: type) {.dirty.} =
proc readValue*(reader: var JsonReader, value: var typ) =
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 =
% int(i)

View File

@ -1,13 +1,13 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# 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).
# Note that is is different from Keccak256 (often mistakenly called SHA3-256)
@ -33,7 +33,7 @@ type
chronicles.formatIt Eth2Digest:
mixin toHex
it.data.toHex(true)
it.data.toHex(true)[0..7]
func shortLog*(x: Eth2Digest): string =
x.data.toHex(true)[0..7]
@ -50,7 +50,7 @@ func eth2hash*(v: openArray[byte]): Eth2Digest {.inline.} =
ctx.update(v)
ctx.finish()
proc update*(ctx: var Sha2Context; digest: Eth2Digest) =
func update*(ctx: var Sha2Context; digest: Eth2Digest) =
ctx.update digest.data
template withEth2Hash*(body: untyped): Eth2Digest =

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# Uncategorized helper functions from the spec
@ -15,7 +15,7 @@ import
# Internal
./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 =
# Return the largest integer ``x`` such that ``x**2 <= n``.
doAssert n >= 0'u64
@ -28,7 +28,7 @@ func integer_squareroot*(n: SomeInteger): SomeInteger =
y = (x + n div x) div 2
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 =
# Return the epoch number of the given ``slot``.
(slot div SLOTS_PER_EPOCH).Epoch
@ -36,17 +36,17 @@ func compute_epoch_at_slot*(slot: Slot|uint64): Epoch =
template epoch*(slot: Slot): Epoch =
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 =
# Return the start slot of ``epoch``.
(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 =
### Check if ``validator`` is active
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):
seq[ValidatorIndex] =
# 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):
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 =
# Return the number of committees at ``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.
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 =
# Return the current epoch.
doAssert state.slot >= GENESIS_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,
epoch: Epoch): Eth2Digest =
## 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[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*(
domain_type: DomainType,
fork_version: array[4, byte] = [0'u8, 0, 0, 0]): Domain =
result[0..3] = int_to_bytes4(domain_type.uint64)
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*(
state: BeaconState, domain_type: DomainType, message_epoch: Epoch): Domain =
## Return the signature domain (fork version concatenated with domain type)
## of a message.
let
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)
get_domain(state.fork, domain_type, message_epoch)
func get_domain*(state: BeaconState, domain_type: DomainType): Domain =
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 =
# Generate a seed for the given ``epoch``.

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
const

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# This file contains constants that are part of the spec and thus subject to
@ -20,7 +20,7 @@ type
const
# 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
@ -35,24 +35,24 @@ const
## with a Verifiable Delay Function (VDF) will improve committee robustness
## and lower the safe minimum committee size.)
MAX_VALIDATORS_PER_COMMITTEE* = 2^12 ##\
MAX_VALIDATORS_PER_COMMITTEE* = 2048 ##\
## votes
MIN_PER_EPOCH_CHURN_LIMIT* = 4
CHURN_LIMIT_QUOTIENT* = 2^16
SHUFFLE_ROUND_COUNT* = 90
MIN_GENESIS_TIME* {.intdefine.} = 1578009600
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT* {.intdefine.} = 16384
# 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
DEPOSIT_CONTRACT_TREE_DEPTH* = 32
# 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 ##\
## Minimum amounth of ETH that can be deposited in one call - deposits can
@ -69,16 +69,16 @@ const
# 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
BLS_WITHDRAWAL_PREFIX* = 0'u8
# 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?
MIN_ATTESTATION_INCLUSION_DELAY* = 1 ##\
@ -127,7 +127,7 @@ const
# 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_SLASHINGS_VECTOR* = 8192
HISTORICAL_ROOTS_LIMIT* = 16777216
@ -135,7 +135,7 @@ const
# 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
WHISTLEBLOWER_REWARD_QUOTIENT* = 2'u64^9
PROPOSER_REWARD_QUOTIENT* = 2'u64^3
@ -144,23 +144,41 @@ const
# 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_ATTESTER_SLASHINGS* = 2^0
MAX_ATTESTATIONS* = 2^7
MAX_DEPOSITS* = 2^4
MAX_VOLUNTARY_EXITS* = 2^4
MIN_GENESIS_TIME* {.intdefine.} = 0
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT* {.intdefine.} = 99
type
# Domains
# Fork choice
# ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/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
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_fork-choice.md#configuration
SAFE_SLOTS_TO_UPDATE_JUSTIFIED* = 8 # 96 seconds
# Validators
# ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/validator/0_beacon-chain-validator.md#misc
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
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# This file contains constants that are part of the spec and thus subject to
@ -20,7 +20,7 @@ type
const
# 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
MAX_COMMITTEES_PER_SLOT* = 4
@ -34,11 +34,11 @@ const
# Changed
SHUFFLE_ROUND_COUNT* = 10
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT* {.intdefine.} = 64
MIN_GENESIS_TIME* {.intdefine.} = 0
MIN_GENESIS_TIME* {.intdefine.} = 1578009600 # 3 Jan, 2020
# 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" ...
# Unchanged
BASE_REWARDS_PER_EPOCH* = 4
@ -47,7 +47,7 @@ const
# 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
MIN_DEPOSIT_AMOUNT* = 2'u64^0 * 10'u64^9
@ -57,7 +57,7 @@ const
# 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
GENESIS_SLOT* = 0.Slot
@ -65,7 +65,7 @@ const
# 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
SECONDS_PER_SLOT*{.intdefine.} = 6'u64
@ -87,11 +87,13 @@ const
MIN_VALIDATOR_WITHDRAWABILITY_DELAY* = 2'u64^8
PERSISTENT_COMMITTEE_PERIOD* = 2'u64^11
MAX_EPOCHS_PER_CROSSLINK* = 4
# Changed
MIN_EPOCHS_TO_INACTIVITY_PENALTY* = 2'u64^2
# 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
EPOCHS_PER_HISTORICAL_VECTOR* = 64
@ -101,7 +103,7 @@ const
# 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
WHISTLEBLOWER_REWARD_QUOTIENT* = 2'u64^9
@ -111,7 +113,7 @@ const
# 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_ATTESTER_SLASHINGS* = 2^0
@ -119,14 +121,40 @@ const
MAX_DEPOSITS* = 2^4
MAX_VOLUNTARY_EXITS* = 2^4
type
# Domains
# Fork choice
# ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/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
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_fork-choice.md#configuration
# Changed
SAFE_SLOTS_TO_UPDATE_JUSTIFIED* = 2
# Validators
# ---------------------------------------------------------------
# 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
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# 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_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*(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
stateCache: var StateCache): bool =
@ -98,7 +98,7 @@ proc process_block_header*(
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(
state: var BeaconState, body: BeaconBlockBody, flags: UpdateFlags,
stateCache: var StateCache): bool =
@ -131,21 +131,21 @@ proc process_randao(
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) =
state.eth1_data_votes.add body.eth1_data
if state.eth1_data_votes.count(body.eth1_data) * 2 >
SLOTS_PER_ETH1_VOTING_PERIOD:
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 =
# Check if ``validator`` is slashable.
(not validator.slashed) and
(validator.activation_epoch <= epoch) and
(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*(
state: var BeaconState, proposer_slashing: ProposerSlashing,
flags: UpdateFlags, stateCache: var StateCache): bool =
@ -204,7 +204,7 @@ proc processProposerSlashings(
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(
data_1: AttestationData, data_2: AttestationData): bool =
## 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_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*(
state: var BeaconState,
attester_slashing: AttesterSlashing,
@ -256,7 +256,7 @@ proc process_attester_slashing*(
return false
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,
stateCache: var StateCache): bool =
# Process ``AttesterSlashing`` operation.
@ -269,8 +269,8 @@ proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock,
return false
return true
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.3/specs/core/0_beacon-chain.md#attestations
proc processAttestations*(
# https://github.com/ethereum/eth2.0-specs/blob/v0.8.4/specs/core/0_beacon-chain.md#attestations
proc processAttestations(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
stateCache: var StateCache): bool =
## Each block includes a number of attestations that the proposer chose. Each
@ -291,7 +291,7 @@ proc processAttestations*(
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 =
if not (len(blck.body.deposits) <= MAX_DEPOSITS):
notice "processDeposits: too many deposits"
@ -304,7 +304,7 @@ proc processDeposits(state: var BeaconState, blck: BeaconBlock): bool =
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*(
state: var BeaconState,
exit: VoluntaryExit,
@ -353,6 +353,15 @@ proc process_voluntary_exit*(
return false
# 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)
true

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# State transition - epoch processing, as described in
@ -62,14 +62,14 @@ declareGauge epoch_transition_final_updates, "Epoch transition final updates tim
# 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 =
# Return the combined effective balance of the active validators.
return get_total_balance(
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):
seq[PendingAttestation] =
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(
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*(
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
## tracks current_epoch_attestations and previous_epoch_attestations only
## 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
## 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
## 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.
trace "Non-attesting indices in previous epoch",
missing_all_validators=
@ -231,7 +231,7 @@ proc process_justification_and_finalization*(
checkpoint = shortLog(state.finalized_checkpoint),
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,
total_balance: auto): Gwei =
# 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
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):
tuple[a: seq[Gwei], b: seq[Gwei]] =
let
@ -336,7 +336,7 @@ func get_attestation_deltas(state: BeaconState, stateCache: var StateCache):
(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(
state: var BeaconState, cache: var StateCache) =
if get_current_epoch(state) == GENESIS_EPOCH:
@ -348,7 +348,7 @@ func process_rewards_and_penalties(
increase_balance(state, i.ValidatorIndex, rewards[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) =
let
epoch = get_current_epoch(state)
@ -365,8 +365,8 @@ func process_slashings*(state: var BeaconState) =
let penalty = penalty_numerator div total_balance * increment
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
proc process_final_updates*(state: var BeaconState) =
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#final-updates
func process_final_updates*(state: var BeaconState) =
let
current_epoch = get_current_epoch(state)
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.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 are placeholders
@ -414,16 +414,16 @@ proc process_epoch*(state: var BeaconState) =
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)
trace "ran process_justification_and_finalization",
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)
# 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.
process_registry_updates(state)
@ -434,12 +434,12 @@ proc process_epoch*(state: var BeaconState) =
# @process_reveal_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)
# @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)
# @after_process_final_updates

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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
@ -22,17 +22,17 @@ func shortLog*(x: Checkpoint): string =
# 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
# TODO there's another one of these, check for redundancy
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/core/0_beacon-chain.md#helper-functions-1
func get_attesting_indices*(
state: BeaconState, attestations: openarray[PendingAttestation],
stateCache: var StateCache): HashSet[ValidatorIndex] =
# This is part of get_unslashed_attesting_indices(...) in spec.
result = initHashSet[ValidatorIndex]()
for a in attestations:
result = result.union(get_attesting_indices(
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*(
state: BeaconState, attestations: openarray[PendingAttestation],
stateCache: var StateCache): HashSet[ValidatorIndex] =

View File

@ -1,7 +1,7 @@
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# Helpers and functions pertaining to managing the validator set
@ -11,13 +11,13 @@ import
./datatypes, ./digest, ./helpers
# 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.1/specs/core/0_beacon-chain.md#compute_committee
func get_shuffled_seq*(seed: Eth2Digest,
list_size: uint64,
): seq[ValidatorIndex] =
# 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.2/specs/core/0_beacon-chain.md#compute_committee
func get_shuffled_seq(seed: Eth2Digest,
list_size: uint64,
): seq[ValidatorIndex] =
## 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``.
## Returns a list of ``SLOTS_PER_EPOCH * committees_per_slot`` committees
## 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
# 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 =
# Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
let current_epoch = get_current_epoch(state)
@ -87,7 +87,7 @@ func get_previous_epoch*(state: BeaconState): Epoch =
else:
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,
index: uint64, count: uint64, stateCache: var StateCache): seq[ValidatorIndex] =
## 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),
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] =
# Return the beacon committee at ``slot`` for ``index``.
let
@ -146,8 +146,8 @@ func get_empty_per_epoch_cache*(): StateCache =
initTable[Epoch, seq[ValidatorIndex]]()
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
func compute_proposer_index*(state: BeaconState, indices: seq[ValidatorIndex],
# 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],
seed: Eth2Digest, stateCache: var StateCache): ValidatorIndex =
# Return from ``indices`` a random index sampled by effective balance.
const MAX_RANDOM_BYTE = 255
@ -178,7 +178,7 @@ func compute_proposer_index*(state: BeaconState, indices: seq[ValidatorIndex],
return candidate_index
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):
ValidatorIndex =
# Return the beacon proposer index at the current slot.

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# SSZ Serialization (simple serialize)
@ -269,7 +269,7 @@ template fromSszBytes*[T; N](_: type TypeWithMaxLen[T, N],
mixin fromSszBytes
fromSszBytes(T, bytes)
func fromSszBytes*(T: type BlsCurveType, bytes: openarray[byte]): auto =
func fromSszBytes(T: type BlsCurveType, bytes: openarray[byte]): auto =
init(T, bytes)
proc readValue*(r: var SszReader, val: var auto) =
@ -327,7 +327,7 @@ func getZeroHashWithoutSideEffect(idx: int): Eth2Digest =
{.noSideEffect.}:
zeroHashes[idx]
func addChunk*(merkelizer: SszChunksMerkelizer, data: openarray[byte]) =
func addChunk(merkelizer: SszChunksMerkelizer, data: openarray[byte]) =
doAssert data.len > 0 and data.len <= bytesPerChunk
if not getBitLE(merkelizer.totalChunks, 0):
@ -350,7 +350,7 @@ func addChunk*(merkelizer: SszChunksMerkelizer, data: openarray[byte]) =
inc merkelizer.totalChunks
func getFinalHash*(merkelizer: SszChunksMerkelizer): Eth2Digest =
func getFinalHash(merkelizer: SszChunksMerkelizer): Eth2Digest =
let limit = merkelizer.limit
if merkelizer.totalChunks == 0:
@ -395,7 +395,7 @@ func getFinalHash*(merkelizer: SszChunksMerkelizer): Eth2Digest =
let HashingStreamVTable = OutputStreamVTable(
writePage: proc (s: OutputStreamVar, data: openarray[byte])
{.nimcall, gcsafe, raises: [IOError, Defect].} =
{.nimcall, gcsafe, raises: [IOError].} =
trs "ADDING STREAM CHUNK ", 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
# effects analysis of Nim - reading from global let variables
# is considered a side-effect.
# Nim 0.19 doesnt have the `{.noSideEffect.}:` override, so
# we should revisit this in Nim 0.20.2.
{.emit: "`result` = &`HashingStreamVTable`;".}
{.noSideEffect.}:
unsafeAddr HashingStreamVTable
func newSszHashingStream(merkelizer: SszChunksMerkelizer): ref OutputStream =
new result
@ -574,11 +573,23 @@ func hash_tree_root*(x: auto): Eth2Digest =
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.} =
enumAllSerializedFields(RecordType):
result = fieldName
func hasSigningRoot*(T: type): bool {.compileTime.} =
func hasSigningRoot(T: type): bool {.compileTime.} =
lastFieldName(T) == "signature"
func signingRoot*(obj: object): Eth2Digest =

View File

@ -60,7 +60,7 @@ func indexableNavigatorImpl[T](m: MemRange, idx: int): MemRange =
getMemRange(typedNavigator[idx])
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
# navigating to an inactive field in a case object.
var typedNavigator = sszMount(m, RecordType)

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# State transition, as described in
@ -43,7 +43,7 @@ declareGauge beacon_previous_validators, """Number of status="pending|active|exi
# 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) =
# Cache state root
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):
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) =
doAssert state.slot <= slot
@ -96,7 +96,7 @@ proc process_slots*(state: var BeaconState, slot: Slot) =
if is_epoch_transition:
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 =
# This is inlined in state_transition(...) in spec.
let state_root = hash_tree_root(state)
@ -170,7 +170,7 @@ proc state_transition*(
# 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) =
# Cache 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] =
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) =
# TODO: Eth specs strongly assert that state.data.slot <= slot
# 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])
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
for fragment in cell.contentFragments:
case fragment[0]
@ -58,11 +58,11 @@ proc updateContent(cell: var StatusBarCell, model: DataItemResolver) =
of ikExpr, ikVar:
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):
cell.updateContent(model)
proc update*(s: var StatusBarView) =
func update*(s: var StatusBarView) =
updateCells s.layout.cellsLeft, s.model
updateCells s.layout.cellsRight, s.model

View File

@ -2,7 +2,7 @@ import
options, tables, sets, macros,
chronicles, chronos, metrics, stew/ranges/bitranges,
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:
import eth/rlp/options as rlpOptions
@ -25,11 +25,11 @@ type
else:
index: uint32
ValidatorSet = seq[Validator]
BeaconBlockCallback* = proc(blck: BeaconBlock) {.gcsafe.}
BeaconSyncNetworkState* = ref object
node*: BeaconNode
db*: BeaconChainDB
blockPool*: BlockPool
forkVersion*: array[4, byte]
onBeaconBlock*: BeaconBlockCallback
BeaconSyncPeerState* = ref object
initialStatusReceived: bool
@ -40,29 +40,18 @@ type
const
MAX_REQUESTED_BLOCKS = 20'u64
MaxAncestorBlocksResponse = 256
func toHeader(b: BeaconBlock): BeaconBlockHeader =
BeaconBlockHeader(
slot: b.slot,
parent_root: b.parent_root,
state_root: b.state_root,
body_root: hash_tree_root(b.body),
signature: b.signature
)
func init*(
v: BeaconSyncNetworkState, blockPool: BlockPool,
forkVersion: array[4, byte], onBeaconBlock: BeaconBlockCallback) =
v.blockPool = blockPool
v.forkVersion = forkVersion
v.onBeaconBlock = onBeaconBlock
proc fromHeaderAndBody(b: var BeaconBlock, h: BeaconBlockHeader, body: BeaconBlockBody) =
doAssert(hash_tree_root(body) == h.body_root)
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]) =
proc importBlocks(state: BeaconSyncNetworkState,
blocks: openarray[BeaconBlock]) {.gcsafe.} =
for blk in blocks:
node.onBeaconBlock(node, blk)
state.onBeaconBlock(blk)
info "Forward sync imported blocks", len = blocks.len
type
@ -73,9 +62,9 @@ type
headRoot*: Eth2Digest
headSlot*: Slot
proc getCurrentStatus(node: BeaconNode): StatusMsg =
proc getCurrentStatus(state: BeaconSyncNetworkState): StatusMsg {.gcsafe.} =
let
blockPool = node.blockPool
blockPool = state.blockPool
finalizedHead = blockPool.finalizedHead
headBlock = blockPool.head.blck
headRoot = headBlock.root
@ -83,14 +72,14 @@ proc getCurrentStatus(node: BeaconNode): StatusMsg =
finalizedEpoch = finalizedHead.slot.compute_epoch_at_slot()
StatusMsg(
fork_version: node.forkVersion,
fork_version: state.forkVersion,
finalizedRoot: finalizedHead.blck.root,
finalizedEpoch: finalizedEpoch,
headRoot: headRoot,
headSlot: headSlot)
proc handleInitialStatus(peer: Peer,
node: BeaconNode,
state: BeaconSyncNetworkState,
ourStatus: StatusMsg,
theirStatus: StatusMsg) {.async, gcsafe.}
@ -102,14 +91,13 @@ p2pProtocol BeaconSync(version = 1,
onPeerConnected do (peer: Peer):
if peer.wasDialed:
let
node = peer.networkState.node
ourStatus = node.getCurrentStatus
ourStatus = peer.networkState.getCurrentStatus()
# TODO: The timeout here is so high only because we fail to
# respond in time due to high CPU load in our single thread.
theirStatus = await peer.status(ourStatus, timeout = 60.seconds)
if theirStatus.isSome:
await peer.handleInitialStatus(node, ourStatus, theirStatus.get)
await peer.handleInitialStatus(peer.networkState, ourStatus, theirStatus.get)
else:
warn "Status response not received in time"
@ -119,14 +107,14 @@ p2pProtocol BeaconSync(version = 1,
requestResponse:
proc status(peer: Peer, theirStatus: StatusMsg) {.libp2pProtocol("status", 1).} =
let
node = peer.networkState.node
ourStatus = node.getCurrentStatus
ourStatus = peer.networkState.getCurrentStatus()
trace "Sending status msg", ourStatus
await response.send(ourStatus)
if not peer.state.initialStatusReceived:
peer.state.initialStatusReceived = true
await peer.handleInitialStatus(node, ourStatus, theirStatus)
await peer.handleInitialStatus(peer.networkState, ourStatus, theirStatus)
proc statusResp(peer: Peer, msg: StatusMsg)
@ -144,7 +132,7 @@ p2pProtocol BeaconSync(version = 1,
if count > 0'u64:
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]
let
lastPos = min(count.int, results.len) - 1
@ -159,8 +147,7 @@ p2pProtocol BeaconSync(version = 1,
blockRoots: openarray[Eth2Digest]) {.
libp2pProtocol("beacon_blocks_by_root", 1).} =
let
pool = peer.networkState.node.blockPool
db = peer.networkState.db
pool = peer.networkState.blockPool
for root in blockRoots:
let blockRef = pool.getRef(root)
@ -172,11 +159,13 @@ p2pProtocol BeaconSync(version = 1,
blocks: openarray[BeaconBlock])
proc handleInitialStatus(peer: Peer,
node: BeaconNode,
state: BeaconSyncNetworkState,
ourStatus: StatusMsg,
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)
return
@ -203,7 +192,7 @@ proc handleInitialStatus(peer: Peer,
var s = ourStatus.headSlot + 1
var theirStatus = theirStatus
while s <= theirStatus.headSlot:
let numBlocksToRequest = min(uint64(theirStatus.headSlot - s),
let numBlocksToRequest = min(uint64(theirStatus.headSlot - s) + 1,
MAX_REQUESTED_BLOCKS)
debug "Requesting blocks", peer, remoteHeadSlot = theirStatus.headSlot,
@ -221,7 +210,7 @@ proc handleInitialStatus(peer: Peer,
info "Got 0 blocks while syncing", peer
break
node.importBlocks blocks.get
state.importBlocks(blocks.get)
let lastSlot = blocks.get[^1].slot
if lastSlot <= s:
info "Slot did not advance during sync", peer
@ -231,7 +220,8 @@ proc handleInitialStatus(peer: Peer,
# TODO: Maybe this shouldn't happen so often.
# 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:
theirStatus = statusResp.get
else:
@ -245,4 +235,3 @@ proc handleInitialStatus(peer: Peer,
except CatchableError:
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
## 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
# 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 =
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 =
## Current time, in slots - this may end up being less than GENESIS_SLOT(!)
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] =
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)
proc addTimer*(fromNow: Duration, cb: CallbackFunc, udata: pointer = nil) =

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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 terminal

View File

@ -1,13 +1,7 @@
import
ospaths, chronos, json_serialization,
os, chronos, json_serialization,
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.} =
# 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:

View File

@ -1,5 +1,5 @@
import
os, ospaths, strutils,
os, strutils,
chronicles, chronos, blscurve, nimcrypto, json_serialization, serialization,
web3, stint, eth/keys,
spec/[datatypes, digest, crypto], conf, ssz, interop

View File

@ -4,29 +4,27 @@ import
spec/[datatypes, crypto, digest, helpers], ssz,
beacon_node_types
proc init*(T: type ValidatorPool): T =
func init*(T: type ValidatorPool): T =
result.validators = initTable[ValidatorPubKey, AttachedValidator]()
template count*(pool: ValidatorPool): int =
pool.validators.len
proc addLocalValidator*(pool: var ValidatorPool,
idx: ValidatorIndex,
pubKey: ValidatorPubKey,
privKey: ValidatorPrivKey) =
let v = AttachedValidator(idx: idx,
pubKey: pubKey,
let v = AttachedValidator(pubKey: pubKey,
kind: inProcess,
privKey: privKey)
pool.validators[pubKey] = v
info "Local validator attached", pubKey, validator = shortLog(v)
proc getValidator*(pool: ValidatorPool,
func getValidator*(pool: ValidatorPool,
validatorKey: ValidatorPubKey): AttachedValidator =
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.} =
if v.kind == inProcess:
@ -34,7 +32,7 @@ proc signBlockProposal*(v: AttachedValidator, state: BeaconState, slot: Slot,
# care about this in here
let
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
# for the purpose of testing the external validator delay - to be
# replaced by something more sensible
@ -47,11 +45,11 @@ proc signBlockProposal*(v: AttachedValidator, state: BeaconState, slot: Slot,
proc signAttestation*(v: AttachedValidator,
attestation: AttestationData,
state: BeaconState): Future[ValidatorSig] {.async.} =
fork: Fork): Future[ValidatorSig] {.async.} =
if v.kind == inProcess:
let
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
# for the purpose of testing the external validator delay - to be
@ -63,14 +61,14 @@ proc signAttestation*(v: AttachedValidator,
error "Unimplemented"
quit 1
func genRandaoReveal*(k: ValidatorPrivKey, state: BeaconState, slot: Slot):
func genRandaoReveal*(k: ValidatorPrivKey, fork: Fork, slot: Slot):
ValidatorSig =
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
bls_sign(k, root, domain)
func genRandaoReveal*(v: AttachedValidator, state: BeaconState, slot: Slot):
func genRandaoReveal*(v: AttachedValidator, fork: Fork, slot: Slot):
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 reset --hard ${GIT_REVISION} \
&& 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 #

View File

@ -1,5 +1,5 @@
import
strformat, ospaths, confutils
strformat, os, confutils
type
Command = enum
@ -76,8 +76,10 @@ iterator validatorAssignments: tuple[node: Node; firstValidator, lastValidator:
0
,
"testnet1": proc (nodeIdx: int): int =
if nodeIdx == 0: systemValidators
else: 0
if nodeidx < 4:
systemValidators div 4
else:
0
}
var nextValidatorIdx = conf.totalUserValidators

View File

@ -1,5 +1,5 @@
import
confutils, ospaths, strutils, chronicles, json_serialization,
confutils, os, strutils, chronicles, json_serialization,
nimcrypto/utils,
../beacon_chain/spec/[crypto, datatypes, digest],
../beacon_chain/[ssz]

View File

@ -1,5 +1,5 @@
import
confutils, ospaths, strutils, chronicles, json_serialization,
confutils, os, strutils, chronicles, json_serialization,
../beacon_chain/spec/[crypto, datatypes, digest],
../beacon_chain/[ssz]

View File

@ -1,5 +1,5 @@
import
confutils, ospaths, strutils, chronicles, json_serialization,
confutils, os, strutils, chronicles, json_serialization,
nimcrypto/utils,
../beacon_chain/spec/[crypto, datatypes, digest],
../beacon_chain/[ssz]

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# 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"
tEpoch = "Process epoch slot with 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"
template withTimer(stats: var RunningStat, body: untyped) =

View File

@ -56,7 +56,7 @@ cli do (testnetName {.argument.}: string):
dataDirName = testnetName.replace("/", "_")
dataDir = buildDir / "data" / 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 = ""
let depositContractFile = testnetDir / depositContractFile

View File

@ -9,30 +9,14 @@
set -e
TMP_CACHE_DIR="tmpcache"
SUBREPO_DIR="tests/official/fixtures"
# verbosity level
[[ -z "$V" ]] && V=0
[[ -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; }
# 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
echo -e "$BUILD_MSG"
[[ "$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()
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
mkdir -p "${CACHE_DIR}/tarballs"
rm -rf "${SUBREPO_DIR}/tarballs"
ln -s "$(pwd -P)/${CACHE_DIR}/tarballs" "${SUBREPO_DIR}"
# (the dir symlink above also takes care of updating the cache)
fi
pushd "${SUBREPO_DIR}"

View File

@ -1,9 +1,7 @@
CONST_PRESET=minimal
NETWORK_TYPE=libp2p_daemon
SLOTS_PER_EPOCH=16
SECONDS_PER_SLOT=16
MAX_COMMITTEES_PER_SLOT=8
QUICKSTART_VALIDATORS=40
RANDOM_VALIDATORS=960
QUICKSTART_VALIDATORS=8
RANDOM_VALIDATORS=120
BOOTSTRAP_PORT=9100
WEB3_URL=wss://goerli.infura.io/ws/v3/809a18497dd74102b5f37d25aae3c85a

View File

@ -1,10 +1,13 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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 # Official constants
./official/test_fixture_const_sanity_check
import # Unit test
./test_attestation_pool,
./test_beacon_chain_db,
@ -25,7 +28,9 @@ import # Refactor state transition unit tests
./spec_block_processing/test_process_attestation,
./spec_epoch_processing/test_process_justification_and_finalization
import # Official fixtures that don't require SSZ parsing of invalid BLS signatures
# https://github.com/status-im/nim-beacon-chain/issues/374
./official/test_fixture_shuffling,
./official/test_fixture_bls
# TODO: json tests were removed
# import # Official fixtures that don't require SSZ parsing of invalid BLS signatures
# # 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
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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
@ -92,7 +92,7 @@ proc inspectType(tImpl, xSubField, ySubField: NimNode, stmts: var NimNode) =
inspectType(tImpl[0], xSubField, ySubField, stmts)
of {nnkSym, 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)
elif $tImpl in builtinTypes:
compareStmt(xSubField, ySubField, stmts)
@ -107,7 +107,7 @@ proc inspectType(tImpl, xSubField, ySubField: NimNode, stmts: var NimNode) =
"\" of type \"" & tImpl.repr
macro reportDiff*(x, y: typed{`var`|`let`|`const`}): untyped =
assert sameType(x, y)
doAssert sameType(x, y)
result = newStmtList()
let typeImpl = x.getTypeImpl

View File

@ -1,14 +1,14 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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
../../beacon_chain/spec/digest
proc `*`*(a: static array[1, byte], n: static int): static Eth2Digest =
assert n == 32
doAssert n == 32
for mbyte in result.data.mitems:
mbyte = a[0]

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
func round_multiple_down*(x: uint64, n: uint64): uint64 {.inline.} =

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# Merkle tree helpers
@ -11,9 +11,7 @@
import
# Specs
../../beacon_chain/spec/[datatypes, digest],
../../beacon_chain/ssz,
# shims
stew/objects
../../beacon_chain/ssz
func round_step_down*(x: Natural, step: static Natural): int {.inline.} =
## Round the input to the previous multiple of "step"

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# Mocking attestations
@ -11,7 +11,6 @@
import
# Standard library
sets,
# 0.19.6 shims
# Specs
../../beacon_chain/spec/[datatypes, beaconstate, helpers, validator, crypto],
# Internals
@ -131,13 +130,13 @@ proc mockAttestation*(
proc fillAggregateAttestation*(state: BeaconState, attestation: var Attestation) =
var cache = get_empty_per_epoch_cache()
let crosslink_committee = get_beacon_committee(
let beacon_committee = get_beacon_committee(
state,
attestation.data.slot,
attestation.data.index,
cache
)
for i in 0 ..< crosslink_committee.len:
for i in 0 ..< beacon_committee.len:
attestation.aggregation_bits[i] = true
proc add*(state: var BeaconState, attestation: Attestation, slot: Slot) =

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# Mocking deposits and genesis deposits
@ -11,8 +11,6 @@
import
# Standard library
math, random,
# 0.19.6 shims
stew/objects, # import default
# Specs
../../beacon_chain/spec/[datatypes, crypto, helpers, digest, beaconstate],
# Internals

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# Mocking a genesis state

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# Mocking helpers for BeaconState

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# Mocking validator public and private keys

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# 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
# Copyright (c) 2018-Present Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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
@ -36,8 +36,7 @@ proc readValue*(r: var JsonReader, a: var seq[byte]) {.inline.} =
const
FixturesDir* = currentSourcePath.rsplit(DirSep, 1)[0] / "fixtures"
JsonTestsDir* = FixturesDir/"json_tests_v0.8.3"
SszTestsDir* = FixturesDir/"tests-v0.9.1"
SszTestsDir* = FixturesDir/"tests-v0.9.2"
proc parseTest*(path: string, Format: typedesc[Json or SSZ], T: typedesc): T =
try:

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}
@ -46,6 +46,7 @@ proc readValue*(r: var JsonReader, a: var Domain) {.inline.} =
# (0.20)
a = hexToPaddedByteArray[8](r.readValue(string))
# TODO: json tests were removed
const BLSDir = JsonTestsDir/"general"/"phase0"/"bls"
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
# Copyright (c) 2018-Present Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}

View File

@ -1,8 +1,8 @@
# 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 http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}

View File

@ -1,8 +1,8 @@
# 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 http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}

View File

@ -1,8 +1,8 @@
# 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 http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}

View File

@ -1,8 +1,8 @@
# 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 http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}

View File

@ -1,8 +1,8 @@
# 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 http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}

View File

@ -1,8 +1,8 @@
# 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 http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}

View File

@ -1,8 +1,8 @@
# 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 http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}

View File

@ -1,8 +1,8 @@
# 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 http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}
@ -22,6 +22,7 @@ type
count*: uint64
mapping*: seq[uint64]
# TODO: json tests were removed
const ShufflingDir = JsonTestsDir/const_preset/"phase0"/"shuffling"/"core"/"shuffle"
suite "Official - Shuffling tests [Preset: " & preset():

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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
@ -26,7 +26,7 @@ import
const
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
SSZHashTreeRoot = object
@ -43,44 +43,16 @@ setDefaultValue(SSZHashTreeRoot, signing_root, "")
# Checking the values against the yaml file is TODO (require more flexible Yaml parser)
const Unsupported = toHashSet([
"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([
"PendingAttestation", # HashTreeRoot KO
])
type Skip = enum
SkipNone
SkipHashTreeRoot
SkipSigningRoot
proc checkSSZ(T: typedesc, dir: string, expectedHash: SSZHashTreeRoot, skip = SkipNone) =
proc checkSSZ(T: typedesc, dir: string, expectedHash: SSZHashTreeRoot) =
# Deserialize into a ref object to not fill Nim stack
var deserialized: ref T
new deserialized
deserialized[] = SSZ.loadFile(dir/"serialized.ssz", T)
if not(skip == SkipHashTreeRoot):
check: expectedHash.root == "0x" & toLowerASCII($deserialized.hashTreeRoot())
if expectedHash.signing_root != "" and not(skip == SkipSigningRoot):
check: expectedHash.root == "0x" & toLowerASCII($deserialized.hashTreeRoot())
if expectedHash.signing_root != "":
check: expectedHash.signing_root == "0x" & toLowerASCII($deserialized[].signingRoot())
# TODO check the value
@ -96,26 +68,16 @@ proc loadExpectedHashTreeRoot(dir: string): SSZHashTreeRoot =
proc runSSZtests() =
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):
assert pathKind == pcDir
doAssert pathKind == pcDir
if sszType in Unsupported:
test &" Skipping {sszType:20} consensus object ✗✗✗":
test &" Skipping {sszType:20} ✗✗✗":
discard
continue
when const_preset == "mainnet":
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 ✓✓✓":
test &" Testing {sszType}":
let path = SSZDir/sszType
for pathKind, sszTestKind in walkDir(path, relative = true):
assert pathKind == pcDir
doAssert pathKind == pcDir
let path = SSZDir/sszType/sszTestKind
for pathKind, sszTestCase in walkDir(path, relative = true):
let path = SSZDir/sszType/sszTestKind/sszTestCase
@ -128,7 +90,7 @@ proc runSSZtests() =
of "AttesterSlashing": checkSSZ(AttesterSlashing, path, hash)
of "BeaconBlock": checkSSZ(BeaconBlock, 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 "Checkpoint": checkSSZ(Checkpoint, path, hash)
of "Deposit": checkSSZ(Deposit, path, hash)
@ -139,10 +101,10 @@ proc runSSZtests() =
of "IndexedAttestation": checkSSZ(IndexedAttestation, path, hash)
of "PendingAttestation": checkSSZ(PendingAttestation, path, hash)
of "ProposerSlashing": checkSSZ(ProposerSlashing, path, hash)
of "Validator": checkSSZ(VoluntaryExit, path, hash)
of "VoluntaryExit": checkSSZ(VoluntaryExit, path, hash, SkipHashTreeRoot) # TODO
of "Validator": checkSSZ(Validator, path, hash)
of "VoluntaryExit": checkSSZ(VoluntaryExit, path, hash)
else:
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()

View File

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

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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
@ -23,7 +23,7 @@ import
const
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
SSZHashTreeRoot = object
@ -133,7 +133,7 @@ proc checkVector(sszSubType, dir: string, expectedHash: SSZHashTreeRoot) =
var typeIdent: string
var size: int
let wasMatched = scanf(sszSubType, "vec_$+_$i", typeIdent, size)
assert wasMatched
doAssert wasMatched
testVector(typeIdent, size)
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) =
var size: int
let wasMatched = scanf(sszSubType, "bitvec_$i", size)
assert wasMatched
doAssert wasMatched
case size
of 1: testBitContainer(BitArray[1], dir, expectedHash)
of 2: testBitContainer(BitArray[2], dir, expectedHash)
@ -199,7 +199,7 @@ proc sszCheck(sszType, sszSubType: string) =
of "uints":
var bitsize: int
let wasMatched = scanf(sszSubType, "uint_$i", bitsize)
assert wasMatched
doAssert wasMatched
case bitsize
of 8: checkBasic(uint8, dir, expectedHash)
of 16: checkBasic(uint16, dir, expectedHash)
@ -219,7 +219,7 @@ proc sszCheck(sszType, sszSubType: string) =
of "containers":
var name: string
let wasMatched = scanf(sszSubtype, "$+_", name)
assert wasMatched
doAssert wasMatched
case name
of "SingleFieldTestStruct": checkBasic(SingleFieldTestStruct, dir, expectedHash)
of "SmallTestStruct": checkBasic(SmallTestStruct, dir, expectedHash)
@ -249,7 +249,7 @@ proc sszCheck(sszType, sszSubType: string) =
proc runSSZtests() =
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):
assert pathKind == pcDir
doAssert pathKind == pcDir
if sszType == "bitlist":
test &"**Skipping** {sszType} inputs - valid - skipped altogether":
# TODO: serialization of "type BitList[maxLen] = distinct BitSeq is not supported"
@ -269,7 +269,7 @@ proc runSSZtests() =
test &"Testing {sszType:12} inputs - valid" & skipped:
let path = SSZDir/sszType/"valid"
for pathKind, sszSubType in walkDir(path, relative = true):
assert pathKind == pcDir
doAssert pathKind == pcDir
sszCheck(sszType, sszSubType)
# TODO: nim-serialization forces us to use exceptions as control flow

View File

@ -1,8 +1,8 @@
# 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 http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}

View File

@ -9,6 +9,15 @@ shift
# shellcheck source=/dev/null
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
# shellcheck source=/dev/null
source "${SIM_ROOT}/../../env.sh"
@ -23,20 +32,20 @@ if [ "${NAT:-}" == "1" ]; then
NAT_FLAG="--nat:any"
fi
mkdir -p $DATA_DIR/validators
mkdir -p "$DATA_DIR/validators"
rm -f $DATA_DIR/validators/*
if [[ $NODE_ID -lt $TOTAL_NODES ]]; then
FIRST_VALIDATOR_IDX=$(( (NUM_VALIDATORS / TOTAL_NODES) * NODE_ID ))
LAST_VALIDATOR_IDX=$(( (NUM_VALIDATORS / TOTAL_NODES) * (NODE_ID + 1) - 1 ))
pushd $VALIDATORS_DIR >/dev/null
cp $(seq -s " " -f v%07g.privkey $FIRST_VALIDATOR_IDX $LAST_VALIDATOR_IDX) $DATA_DIR/validators
pushd "$VALIDATORS_DIR" >/dev/null
cp $(seq -s " " -f v%07g.privkey $FIRST_VALIDATOR_IDX $LAST_VALIDATOR_IDX) "$DATA_DIR/validators"
popd >/dev/null
fi
$BEACON_NODE_BIN \
--bootstrap-file=$NETWORK_BOOTSTRAP_FILE \
--bootstrap-file=$BOOTSTRAP_ADDRESS_FILE \
--data-dir=$DATA_DIR \
--node-name=$NODE_ID \
--tcp-port=$PORT \

View File

@ -2,6 +2,7 @@
# Read in variables
set -a
# shellcheck source=/dev/null
source "$(dirname "$0")/vars.sh"
cd $(dirname "$0")

View File

@ -1,22 +1,26 @@
#!/bin/bash
# https://github.com/koalaman/shellcheck/wiki/SC2034
# shellcheck disable=2034
true
PWD_CMD="pwd"
# get native Windows paths on Mingw
uname | grep -qi mingw && PWD_CMD="pwd -W"
cd $(dirname $0)
cd "$(dirname "$0")"
SIM_ROOT="$($PWD_CMD)"
# 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)"}
cd - &>/dev/null
# When changing these, also update the readme section on running simulation
# so that the run_node example is correct!
NUM_VALIDATORS=${VALIDATORS:-192}
TOTAL_NODES=${NODES:-4}
TOTAL_NODES=${NODES:-2}
TOTAL_USER_NODES=${USER_NODES:-0}
TOTAL_SYSTEM_NODES=$(( TOTAL_NODES - TOTAL_USER_NODES ))
MASTER_NODE=$(( TOTAL_NODES - 1 ))

View File

@ -1,13 +1,13 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# 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.}
@ -44,15 +44,17 @@ suite "[Unit - Spec - Genesis] Genesis block checks " & preset():
)
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":
discard initGenesisState(
num_validators = MIN_GENESIS_ACTIVE_VALIDATOR_COUNT.uint64 - 1,
genesis_time = MIN_GENESIS_TIME.uint64 - 1
)
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
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# 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.}
@ -14,8 +14,6 @@
import
# Standard library
unittest,
# shims 0.19.6
stew/objects, # import default
# Specs
../../beacon_chain/spec/[beaconstate, datatypes, helpers, validator],
# Mock helpers
@ -109,10 +107,6 @@ suite "[Unit - Spec - Block processing] Attestations " & preset():
# - source epoch in the future
# - invalid current 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
# - non-empty custody bits in phase 0

View File

@ -1,13 +1,13 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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.
# 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.}

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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

View File

@ -1,8 +1,8 @@
# beacon_chain
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# * 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

Some files were not shown because too many files have changed in this diff Show More