-
Notifications
You must be signed in to change notification settings - Fork 9
Beacon chain simulator
A simulator is a tool that runs a standalone beacon chain instance with a number of assumptions and limitations. The main goal of simulator is to try beacon chain consensus algorithms execution in different circumstances, say, with 100% honest validator set and some bad actors in it, network drops and delays. The other goal is to measure performance, check out bottlenecks and discover new ways of design improvement and optimizations.
There is a number of parameters affecting beacon chain runtime. Some of them are hard coded in the simulator, but valuable consensus parameters are configurable by the user.
There is a set of immutable simulation parameters:
-
time - beacon chain time is driven by a routine called
ControlledSchedulers
which methodaddTime
adds a slot to overall system time and processes all the events that correspond to this time slot; during simulationaddTime
is triggered by infinite loop adding 1 millisecond in each iteration. -
thread model - all the system (including all peers asynchronous tasks) runs on a single
main
thread. This makes the simulator runs deterministic (alongside with fixed random seed) and preserves same behaviour across different runs. - network - there is a special storage in memory that aids network simulation; attestations and blocks are simply propagated to all peers in the "network".
- database - simulator doesn't store anything on disk, each time it starts with clean in-memory database.
- eth1 chain - simulator starts with a set of initial validators defined by user, validator registration is not handled by simulation.
- genesis-time - sets Genesis time in seconds using Unix timestamp notation.
-
seed - an integer number that will be used as a seed to generate credentials of initial validator set, setting this parameter preserves validator credentials between simulations. Taking into account the single-threaded model different runs with same
seed
should be absolutely identical. If it's not specified, random value will be used. - bls-verify - whether BLS verification is enabled during simulation or not, disabled by default; this flag doesn't affect BLS signature creation, skipping only verification part and making simulation run faster.
- beacon chain parameters - values of beacon chain constants defined by the spec could be overridden.
- peers - describes groups of peers with different behavior, participants of the simulation.
- validator - a flag indicating whether it's a validator group or passive chain observers.
- count - number of peers in the group.
- systemTimeShift - system clock shift for this peer(s) in milliseconds.
- wireInboundDelay - network lag of inbound messages for this peer(s) in milliseconds.
- wireOutboundDelay - network lag of outbound messages for this peer(s) in milliseconds.
To run a simulator you need to install Java 8 or later. There are many guidelines in Internet, even the official one, from Oracle.
Clone the repo and execute build command:
git clone https://github.com/harmony-dev/beacon-chain-java.git
cd beacon-chain-java
./gradlew clean build -x test
Unpack the distribution:
unzip start/simulator/build/distributions/simulator-0.1.0.zip
Use default setup to check it out:
cd simulator-0.1.0/bin
./simulator run default
To run simulation with simple plan create plan.yml
file:
genesis-time: 600
peers:
- count: 64
validator: true
Then execute following command to start simulation:
./simulator run plan.yml
Do not wait too long, just cancel that run cause it's gonna take a while before something shows up in the output.
Disable BLS verification and set random seed:
genesis-time: 600
bls-verify: false
seed: 1
peers:
- count: 64
validator: true
Re-run the command, the output should be similar to:
./simulator run plan.yml
18:39:23.135 # INFO - Simulation parameters:
---
peers:
- count: 64
validator: true
seed: 1
bls-verify: false
genesis-time: 600
18:39:24.485 # INFO - Creating validators...
[DEBUG] (main) Using Console logging
18:39:35.747 # INFO - Validators created
18:39:35.926 # INFO - Creating observer peer...
18:39:36.089 # INFO - Time starts running ...
18:39:50.922 # INFO - Slot 1, committee: [ShardCommittee[1: [16]]], blocks: 2, attestations: 2, peers states differ: 5bee3827: 1 peers, 00000000: 1 peers, 5214b336: 65 peers
18:40:06.414 # INFO - Slot 2, committee: [ShardCommittee[2: [17]]], blocks: 1, attestations: 1, peers states differ: 52182f4c: 1 peers, 27062150: 65 peers
18:40:23.699 # INFO - Slot 3, committee: [ShardCommittee[3: [35]]], blocks: 1, attestations: 1, peers states differ: e1df0cc2: 1 peers, 87e0fbee: 65 peers
For overview of plan parameters, check Configurable parameters section.
To see more detailed output use --loglevel
option:
./simulator run --loglevel=debug plan.yml
Or even:
./simulator run --loglevel=all plan.yml
Detailed output produced by the simulation can be, also, found in a ./logs
directory.
Beacon chain constants defined by the spec can be printed with the command:
./simulator spec
The output of this command, also, illustrates the format for a file with spec overrides. To override some of those values create a spec.yml
file:
specConstants:
initialValues:
GENESIS_SLOT: 1000000
miscParameters:
SHARD_COUNT: 4
TARGET_COMMITTEE_SIZE: 2
timeParameters:
SECONDS_PER_SLOT: 10
MIN_ATTESTATION_INCLUSION_DELAY: 1
SLOTS_PER_EPOCH: 4
honestValidatorParameters:
ETH1_FOLLOW_DISTANCE: 1
stateListLengths:
LATEST_BLOCK_ROOTS_LENGTH: 64
LATEST_RANDAO_MIXES_LENGTH: 64
LATEST_ACTIVE_INDEX_ROOTS_LENGTH: 64
LATEST_SLASHED_EXIT_LENGTH: 64
And pass this file as a parameter to a simulator:
./simulator run --spec=spec.yml plan.yml
In the current implementation the simulation of the network is pretty simple and straightforward, there are just 2 'messages': newBlock
and newAttestation
which are immediately propagated from the sender to other 'peers'. With a single-threaded model this gives absolutely deterministic simulated network behavior.