├── .env.example ├── .gitbook └── assets │ ├── coalition game.png │ ├── image (1).png │ ├── image (10) (1) (1).png │ ├── image (10) (1) (2).png │ ├── image (10) (1).png │ ├── image (10) (2).png │ ├── image (10).png │ ├── image (11) (1) (1).png │ ├── image (11) (1) (2).png │ ├── image (11) (1).png │ ├── image (11) (2).png │ ├── image (11).png │ ├── image (2).png │ ├── image (3).png │ ├── image (4).png │ ├── image (5).png │ ├── image (6).png │ ├── image (7).png │ ├── image (8).png │ ├── image (9).png │ └── image.png ├── .github └── workflows │ ├── ci_dev-v2.yml │ ├── ci_dev-v3.yml │ ├── ci_dev.yml │ └── ci_main.yml ├── .gitignore ├── .gitmodules ├── .vscode └── settings.json ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── README.md ├── SECURITY.md ├── boot_config └── boot_enrs.yaml ├── build.rs ├── common ├── dvf_directory │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── dvf_version │ ├── Cargo.toml │ └── src │ └── lib.rs ├── docker-compose-boot.yml ├── docker-compose-operator-mev.yml ├── docker-compose-operator.yml ├── docker-log-configure └── daemon.json ├── docs ├── SUMMARY.md ├── imgs │ ├── committe-size.png │ ├── infura-step1.png │ ├── infura-step2.png │ ├── infura-step3.png │ ├── infura-step4.png │ ├── operatpr-setup1.png │ ├── operatpr-setup2.png │ ├── operatpr-setup3.png │ ├── operatpr-setup4.png │ ├── operatpr-setup5.png │ ├── operatpr-setup6.png │ ├── validator-exit-upload.png │ └── validator-exit.png ├── safestake-ecosystem.md ├── safestake-license-attribution.md ├── safestake-running-a-boot-node.md ├── safestake-running-an-operator-node.md ├── safestake-tech-dkg.md ├── safestake-tech-stack.md └── safestake-tokenomics-ongoing.md ├── hotstuff ├── Cargo.toml ├── LICENSE ├── benchmark │ ├── .gitignore │ ├── benchmark │ │ ├── __init__ │ │ ├── aggregate.py │ │ ├── commands.py │ │ ├── config.py │ │ ├── instance.py │ │ ├── local.py │ │ ├── logs.py │ │ ├── plot.py │ │ ├── remote.py │ │ ├── settings.py │ │ └── utils.py │ ├── data │ │ ├── 2-chain │ │ │ ├── plots │ │ │ │ ├── faults-latency.pdf │ │ │ │ ├── faults-latency.png │ │ │ │ ├── faults-robustness.pdf │ │ │ │ ├── faults-robustness.png │ │ │ │ ├── latency.pdf │ │ │ │ ├── latency.png │ │ │ │ ├── robustness.pdf │ │ │ │ ├── robustness.png │ │ │ │ ├── tps.pdf │ │ │ │ └── tps.png │ │ │ └── results │ │ │ │ ├── bench-0-10-10000-512.txt │ │ │ │ ├── bench-0-10-100000-512.txt │ │ │ │ ├── bench-0-10-110000-512.txt │ │ │ │ ├── bench-0-10-120000-512.txt │ │ │ │ ├── bench-0-10-80000-512.txt │ │ │ │ ├── bench-0-20-10000-512.txt │ │ │ │ ├── bench-0-20-100000-512.txt │ │ │ │ ├── bench-0-20-130000-512.txt │ │ │ │ ├── bench-0-20-135000-512.txt │ │ │ │ ├── bench-0-20-140000-512.txt │ │ │ │ ├── bench-0-20-80000-512.txt │ │ │ │ ├── bench-0-50-10000-512.txt │ │ │ │ ├── bench-0-50-100000-512.txt │ │ │ │ ├── bench-0-50-20000-512.txt │ │ │ │ ├── bench-0-50-30000-512.txt │ │ │ │ ├── bench-0-50-40000-512.txt │ │ │ │ ├── bench-0-50-50000-512.txt │ │ │ │ ├── bench-0-50-60000-512.txt │ │ │ │ ├── bench-0-50-70000-512.txt │ │ │ │ ├── bench-0-50-80000-512.txt │ │ │ │ ├── bench-0-50-90000-512.txt │ │ │ │ ├── bench-1-10-10000-512.txt │ │ │ │ ├── bench-1-10-100000-512.txt │ │ │ │ ├── bench-1-10-110000-512.txt │ │ │ │ ├── bench-1-10-50000-512.txt │ │ │ │ ├── bench-1-10-60000-512.txt │ │ │ │ ├── bench-1-10-70000-512.txt │ │ │ │ ├── bench-1-10-80000-512.txt │ │ │ │ ├── bench-1-10-90000-512.txt │ │ │ │ ├── bench-3-10-1000-512.txt │ │ │ │ ├── bench-3-10-10000-512.txt │ │ │ │ ├── bench-3-10-5000-512.txt │ │ │ │ └── bench-3-10-60000-512.txt │ │ └── 3-chain │ │ │ ├── plots │ │ │ ├── faults-latency.pdf │ │ │ ├── faults-latency.png │ │ │ ├── faults-robustness.pdf │ │ │ ├── faults-robustness.png │ │ │ ├── latency.pdf │ │ │ ├── latency.png │ │ │ ├── robustness.pdf │ │ │ ├── robustness.png │ │ │ ├── tps.pdf │ │ │ └── tps.png │ │ │ └── results │ │ │ ├── bench-10-50000-512-0.txt │ │ │ ├── bench-10-60000-512-0.txt │ │ │ ├── bench-10-70000-512-0.txt │ │ │ ├── bench-10-80000-512-0.txt │ │ │ ├── bench-10-85000-512-0.txt │ │ │ ├── bench-20-10000-512-1.txt │ │ │ ├── bench-20-10000-512-3.txt │ │ │ ├── bench-20-100000-512-1.txt │ │ │ ├── bench-20-100000-512-3.txt │ │ │ ├── bench-20-20000-512-3.txt │ │ │ ├── bench-20-30000-512-1.txt │ │ │ ├── bench-20-30000-512-3.txt │ │ │ ├── bench-20-40000-512-0.txt │ │ │ ├── bench-20-50000-512-0.txt │ │ │ ├── bench-20-50000-512-1.txt │ │ │ ├── bench-20-50000-512-3.txt │ │ │ ├── bench-20-60000-512-0.txt │ │ │ ├── bench-20-70000-512-0.txt │ │ │ ├── bench-20-70000-512-1.txt │ │ │ ├── bench-20-70000-512-3.txt │ │ │ ├── bench-20-80000-512-0.txt │ │ │ ├── bench-20-80000-512-1.txt │ │ │ ├── bench-50-20000-512-0.txt │ │ │ ├── bench-50-30000-512-0.txt │ │ │ ├── bench-50-40000-512-0.txt │ │ │ └── bench-50-50000-512-0.txt │ ├── fabfile.py │ ├── requirements.txt │ └── settings.json ├── config │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── consensus │ ├── Cargo.toml │ └── src │ │ ├── aggregator.rs │ │ ├── config.rs │ │ ├── consensus.rs │ │ ├── core.rs │ │ ├── error.rs │ │ ├── helper.rs │ │ ├── leader.rs │ │ ├── lib.rs │ │ ├── mempool.rs │ │ ├── messages.rs │ │ ├── proposer.rs │ │ ├── synchronizer.rs │ │ ├── tests │ │ ├── aggregator_tests.rs │ │ ├── common.rs │ │ ├── consensus_tests.rs │ │ ├── core_tests.rs │ │ ├── helper_tests.rs │ │ ├── messages_tests.rs │ │ ├── synchronizer_tests.rs │ │ └── timer_tests.rs │ │ └── timer.rs ├── crypto │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── tests │ │ └── crypto_tests.rs ├── mempool │ ├── Cargo.toml │ └── src │ │ ├── batch_maker.rs │ │ ├── config.rs │ │ ├── helper.rs │ │ ├── lib.rs │ │ ├── mempool.rs │ │ ├── processor.rs │ │ ├── quorum_waiter.rs │ │ ├── synchronizer.rs │ │ └── tests │ │ ├── batch_maker_tests.rs │ │ ├── common.rs │ │ ├── helper_tests.rs │ │ ├── mempool_tests.rs │ │ ├── processor_tests.rs │ │ ├── quorum_waiter_tests.rs │ │ └── synchronizer_tests.rs ├── network │ ├── Cargo.toml │ └── src │ │ ├── dvf_message.rs │ │ ├── error.rs │ │ ├── lib.rs │ │ ├── receiver.rs │ │ ├── reliable_sender.rs │ │ ├── simple_sender.rs │ │ └── tests │ │ ├── common.rs │ │ ├── receiver_tests.rs │ │ ├── reliable_sender_tests.rs │ │ └── simple_sender_tests.rs ├── run.sh ├── store │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── tests │ │ └── store_tests.rs └── utils │ ├── Cargo.toml │ └── src │ ├── lib.rs │ ├── monitored_channel.rs │ └── size_monitor.rs ├── imgs ├── architecture.png ├── operatpr-setup1.png ├── operatpr-setup2.png ├── operatpr-setup3.png ├── operatpr-setup4.png ├── operatpr-setup5.png └── operatpr-setup6.png ├── scripts └── clean_container_log.sh ├── src ├── boot_node │ ├── Cargo.lock │ ├── Cargo.toml │ ├── bootnode.proto │ ├── build.rs │ └── src │ │ ├── boot_service.rs │ │ ├── config.rs │ │ ├── lib.rs │ │ └── proto.rs ├── cli.rs ├── crypto │ ├── define.rs │ ├── dkg.rs │ ├── elgamal.rs │ ├── generic_threshold.rs │ ├── impls │ │ ├── blst.rs │ │ └── mod.rs │ └── mod.rs ├── deposit │ └── mod.rs ├── dvf_key_tool │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── exit │ └── mod.rs ├── lib.rs ├── main.rs ├── math │ ├── bigint_ext.rs │ ├── mod.rs │ └── polynomial.rs ├── metrics.rs ├── network │ ├── io_committee.rs │ └── mod.rs ├── node │ ├── config.rs │ ├── contract.rs │ ├── db.rs │ ├── discovery.rs │ ├── dvfcore.rs │ ├── mod.rs │ ├── node.rs │ ├── status_report.rs │ └── utils.rs ├── test_utils │ └── mod.rs ├── utils │ ├── blst_utils.rs │ ├── error.rs │ ├── ip_util.rs │ ├── mod.rs │ └── rand_utils.rs └── validation │ ├── account_utils │ ├── mod.rs │ └── validator_definitions.rs │ ├── attestation_service.rs │ ├── beacon_node_fallback.rs │ ├── block_service.rs │ ├── check_synced.rs │ ├── cli.rs │ ├── config.rs │ ├── doppelganger_service.rs │ ├── duties_service.rs │ ├── duties_service │ └── sync.rs │ ├── eth2_keystore_share │ ├── keystore_share.rs │ └── mod.rs │ ├── generic_operator_committee.rs │ ├── graffiti_file.rs │ ├── http_api │ ├── api_secret.rs │ ├── create_validator.rs │ ├── graffiti.rs │ ├── keystores.rs │ ├── mod.rs │ ├── remotekeys.rs │ ├── tests.rs │ └── tests │ │ └── keystores.rs │ ├── http_metrics │ ├── metrics.rs │ └── mod.rs │ ├── impls │ ├── fake.rs │ ├── hotstuff.rs │ └── mod.rs │ ├── initialized_validators.rs │ ├── key_cache.rs │ ├── latency.rs │ ├── mod.rs │ ├── notifier.rs │ ├── operator.rs │ ├── operator_committee_definitions.rs │ ├── operator_committees.rs │ ├── preparation_service.rs │ ├── signing_method.rs │ ├── signing_method │ └── web3signer.rs │ ├── sync_committee_service.rs │ ├── validator_dir │ ├── mod.rs │ └── share_builder.rs │ └── validator_store.rs └── tests ├── test_generic_threshold.rs └── test_operator_committee.rs /.env.example: -------------------------------------------------------------------------------- 1 | GETH_NETWORK=mainnet 2 | NETHERMIND_NETWORK=mainnet 3 | BESU_NETWORK=mainnet 4 | ERIGON_NETWORK=mainnet 5 | LIGHTHOUSE_NETWORK=mainnet 6 | OPERATOR_NETWORK=mainnet 7 | IMAGE_TAG=v4.1.0-mainnet 8 | REGISTRY_CONTRACT_ADDRESS=1a1f82f0365571A0b06df0992FC4D1BCc5Fdc6aD 9 | NETWORK_CONTRACT_ADDRESS=829f3c089fE315FCB2BC9506B237BB56b7c3335B 10 | CONFIG_CONTRACT_ADDRESS=07FA0F7f3C67e4cdE0FC23A072dcD712CF9a06C1 11 | CLUSTER_CONTRACT_ADDRESS=f0455Aca6B61109098562610e89C7ca22c12Bb43 12 | API_SERVER=https://api-node.safestake.xyz/api/op/ 13 | # different chain has different ttd 14 | TTD=10790000 15 | # separated by ',' for multiple relays, such as MEV_BOOST_RELAYS=xxx,xxx,xxx 16 | MEV_BOOST_RELAYS=https://0xa15b52576bcbf1072f4a011c0f99f9fb6c66f3e1ff321f11f461d15e31b1cb359caa092c71bbded0bae5b5ea401aab7e@aestus.live,https://0xa7ab7a996c8584251c8f925da3170bdfd6ebc75d50f5ddc4050a6fdc77f2a3b5fce2cc750d0865e05d7228af97d69561@agnostic-relay.net,https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com,https://0xb0b07cd0abef743db4260b0ed50619cf6ad4d82064cb4fbec9d3ec530f7c5e6793d9f286c4e082c0244ffb9f2658fe88@bloxroute.regulated.blxrbdn.com,https://0xb3ee7afcf27f1f1259ac1787876318c6584ee353097a50ed84f51a1f21a323b3736f271a895c7ce918c038e4265918be@relay.edennetwork.io,https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net,https://0x98650451ba02064f7b000f5768cf0cf4d4e492317d82871bdc87ef841a0743f69f0f1eea11168503240ac35d101c9135@mainnet-relay.securerpc.com,https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money 17 | #gas limit. [default: 30,000,000] 18 | GAS_LIMIT_INTEGER=30000000 19 | RPC_URL= 20 | OPERATOR_ID= 21 | # The beacon node endpoint, e.g., http://127.0.0.1:5052 for a local node 22 | BEACON_NODE_ENDPOINT= 23 | # public ipv4 ip of the server running your operator 24 | NODE_IP= 25 | # run a MEV(Maximal Extractable Value) boost for lighthouse when you want to open mev 26 | MEV_ENDPOINT= -------------------------------------------------------------------------------- /.gitbook/assets/coalition game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/coalition game.png -------------------------------------------------------------------------------- /.gitbook/assets/image (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (10) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10) (1) (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (10) (1) (2).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (10) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10) (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (10) (2).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (10).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (11) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11) (1) (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (11) (1) (2).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (11) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11) (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (11) (2).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (11).png -------------------------------------------------------------------------------- /.gitbook/assets/image (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (2).png -------------------------------------------------------------------------------- /.gitbook/assets/image (3).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (3).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (4).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (5).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (6).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (7).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (8).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image (9).png -------------------------------------------------------------------------------- /.gitbook/assets/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/.gitbook/assets/image.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/macos,vim,rust,linux,windows 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=macos,vim,rust,linux,windows 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### macOS ### 20 | # General 21 | .DS_Store 22 | .AppleDouble 23 | .LSOverride 24 | 25 | # Icon must end with two \r 26 | Icon 27 | 28 | 29 | # Thumbnails 30 | ._* 31 | 32 | # Files that might appear in the root of a volume 33 | .DocumentRevisions-V100 34 | .fseventsd 35 | .Spotlight-V100 36 | .TemporaryItems 37 | .Trashes 38 | .VolumeIcon.icns 39 | .com.apple.timemachine.donotpresent 40 | 41 | # Directories potentially created on remote AFP share 42 | .AppleDB 43 | .AppleDesktop 44 | Network Trash Folder 45 | Temporary Items 46 | .apdisk 47 | 48 | ### Rust ### 49 | # Generated by Cargo 50 | # will have compiled files and executables 51 | debug/ 52 | target/ 53 | 54 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 55 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 56 | #Cargo.lock 57 | 58 | # These are backup files generated by rustfmt 59 | **/*.rs.bk 60 | 61 | # MSVC Windows builds of rustc generate these, which store debugging information 62 | *.pdb 63 | 64 | ### Vim ### 65 | # Swap 66 | [._]*.s[a-v][a-z] 67 | !*.svg # comment out if you don't need vector files 68 | [._]*.sw[a-p] 69 | [._]s[a-rt-v][a-z] 70 | [._]ss[a-gi-z] 71 | [._]sw[a-p] 72 | 73 | # Session 74 | Session.vim 75 | Sessionx.vim 76 | 77 | # Temporary 78 | .netrwhist 79 | # Auto-generated tag files 80 | tags 81 | # Persistent undo 82 | [._]*.un~ 83 | 84 | ### Windows ### 85 | # Windows thumbnail cache files 86 | Thumbs.db 87 | Thumbs.db:encryptable 88 | ehthumbs.db 89 | ehthumbs_vista.db 90 | 91 | # Dump file 92 | *.stackdump 93 | 94 | # Folder config file 95 | [Dd]esktop.ini 96 | 97 | # Recycle Bin used on file shares 98 | $RECYCLE.BIN/ 99 | 100 | # Windows Installer files 101 | *.cab 102 | *.msi 103 | *.msix 104 | *.msm 105 | *.msp 106 | 107 | # Windows shortcuts 108 | *.lnk 109 | 110 | # End of https://www.toptal.com/developers/gitignore/api/macos,vim,rust,linux,windows 111 | 112 | 113 | # protobuf 114 | network_msgs.rs 115 | 116 | committee.json 117 | node_*.json 118 | db_* 119 | node_copy 120 | .env -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lighthouse"] 2 | path = lighthouse 3 | url = https://github.com/ParaState/lighthouse 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.inlayHints.typeHints.enable": false 3 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dvf" 3 | version = "1.4.0" 4 | authors = ["Zico "] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | [features] 9 | default = ["slasher-lmdb"] 10 | # Compiles the BLS crypto code so that the binary is portable across machines. 11 | portable = ["bls/supranational-portable"] 12 | # Compiles BLST so that it always uses ADX instructions. 13 | modern = ["bls/supranational-force-adx"] 14 | # Support minimal spec (used for testing only). 15 | spec-minimal = [] 16 | # Support Gnosis spec and Gnosis Beacon Chain. 17 | gnosis = [] 18 | # Support slasher MDBX backend. 19 | slasher-mdbx = ["slasher/mdbx"] 20 | # Support slasher LMDB backend. 21 | slasher-lmdb = ["slasher/lmdb"] 22 | # Support slasher redb backend. 23 | slasher-redb = ["slasher/redb"] 24 | # Deprecated. This is now enabled by default on non windows targets. 25 | jemalloc = [] 26 | 27 | [target.'cfg(not(target_os = "windows"))'.dependencies] 28 | malloc_utils = { path = "lighthouse/common/malloc_utils", features = ["jemalloc"] } 29 | 30 | [target.'cfg(target_os = "windows")'.dependencies] 31 | malloc_utils = { path = "lighthouse/common/malloc_utils" } 32 | 33 | [dependencies] 34 | slog = { version = "2", features = ["max_level_debug", "release_max_level_debug", "nested-values"] } 35 | types = { path = "lighthouse/consensus/types" } 36 | bls = { path = "lighthouse/crypto/bls" } 37 | ethereum_hashing = "0.7.0" 38 | clap = { version = "4.5.4", features = ["derive", "cargo", "wrap_help"] } 39 | environment = { path = "lighthouse/lighthouse/environment" } 40 | futures = "0.3" 41 | validator_client = { path = "lighthouse/validator_client" } 42 | clap_utils = { path = "lighthouse/common/clap_utils" } 43 | eth2_network_config = { path = "lighthouse/common/eth2_network_config" } 44 | lighthouse_version = { path = "lighthouse/common/lighthouse_version" } 45 | account_utils = { path = "lighthouse/common/account_utils" } 46 | metrics = { path = "lighthouse/common/metrics" } 47 | serde = { version = "1", features = ["derive"] } 48 | serde_json = "1" 49 | serde_yaml = "0.9" 50 | task_executor = { path = "lighthouse/common/task_executor" } 51 | malloc_utils = { path = "lighthouse/common/malloc_utils" } 52 | directory = { path = "lighthouse/common/directory" } 53 | unused_port = { path = "lighthouse/common/unused_port" } 54 | slasher = { path = "lighthouse/slasher", default-features = false } 55 | logging = { path = "lighthouse/common/logging" } 56 | boot_node = { path = "src/boot_node" } 57 | tokio = { version = "1", features = ["rt-multi-thread", "sync", "signal", "macros"] } 58 | dvf_utils = { path = "lighthouse/common/dvf_utils" } 59 | [dev-dependencies] 60 | tempfile = "3" 61 | validator_dir = { path = "lighthouse/common/validator_dir" } 62 | slashing_protection = { path = "lighthouse/validator_client/slashing_protection" } 63 | lighthouse_network = { path = "lighthouse/beacon_node/lighthouse_network" } 64 | sensitive_url = { path = "lighthouse/common/sensitive_url" } 65 | eth1 = { path = "lighthouse/beacon_node/eth1" } 66 | eth2 = { path = "lighthouse/common/eth2" } 67 | beacon_processor = { path = "lighthouse/beacon_node/beacon_processor" } 68 | beacon_node_fallback = { path = "lighthouse/validator_client/beacon_node_fallback" } 69 | initialized_validators = { path = "lighthouse/validator_client/initialized_validators" } 70 | 71 | 72 | [[test]] 73 | name = "lighthouse_tests" 74 | path = "tests/main.rs" 75 | 76 | # Prevent cargo-udeps from flagging the dummy package `target_check`, which exists only 77 | # to assert properties of the compilation target. 78 | [package.metadata.cargo-udeps.ignore] 79 | normal = ["target_check"] 80 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.86.0 AS builder 2 | 3 | RUN apt-get update && apt-get -y upgrade \ 4 | && apt-get install -y cmake libclang-dev protobuf-compiler 5 | 6 | RUN USER=root cargo new --bin app 7 | WORKDIR /app 8 | 9 | COPY ./Cargo.lock ./Cargo.lock 10 | COPY ./Cargo.toml ./Cargo.toml 11 | COPY ./lighthouse ./lighthouse 12 | COPY ./boot_config ./boot_config 13 | # copy your source tree 14 | COPY ./build.rs ./build.rs 15 | COPY ./src ./src 16 | 17 | # build for release 18 | ARG CPU_NUM=16 19 | RUN cargo build -j $CPU_NUM --release 20 | RUN cd src/dvf_key_tool && cargo build -j $CPU_NUM --release 21 | FROM ubuntu:22.04 22 | RUN apt-get update && apt-get -y upgrade && apt-get install -y --no-install-recommends \ 23 | libssl-dev \ 24 | curl \ 25 | ca-certificates \ 26 | && apt-get clean \ 27 | && rm -rf /var/lib/apt/lists/* 28 | WORKDIR /app 29 | COPY --from=builder /app/boot_config /app/boot_config 30 | COPY --from=builder /app/target/release/dvf /usr/local/bin/dvf 31 | COPY --from=builder /app/src/dvf_key_tool/target/release/dvf_key_tool /usr/local/bin/dvf_key_tool -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SafeStake: A trust-minimized middle layer for secure, decentralized ETH staking 2 | 3 | [![Publish Image & UnitTest](https://github.com/ParaState/SafeStakeOperator/actions/workflows/ci_dev.yml/badge.svg?branch=dev)](https://github.com/ParaState/SafeStakeOperator/actions/workflows/ci_dev.yml) 4 | 5 | ## What is SafeStake? 6 | 7 | `SafeStake` is a decentralized staking framework and protocol that maximizes staker rewards by keeping validators secure and online to perform Ethereum Proof-of-Stake consensus (ETH2) duties. It splits a validator key into shares and distributes them over several nodes run by independent operators to achieve high levels of security and fault tolerance. Written in Rust, SafeStake runs on top of the ETH2/consensus client [Lighthouse](https://github.com/sigp/lighthouse) and uses [Hotstuff](https://github.com/asonnino/hotstuff) (a BFT consensus library) for consensus. The referenced [thesis](https://eprint.iacr.org/2019/985). 8 | 9 |

SafeStake Network Architecture

10 | 11 | ### SafeStake makes earning staking rewards safe and easy for all ETH holders. 12 | 13 | * `Stage 1 - Deposit 32 ETH` and choose a group of four operators to manage your validator. 14 | * `Stage 2` - Partnering with LST protocols to run 'Pooled Validator', empowring LST/LRT protocols to deploy validators on SafeStake platform to enhance security and improve performance resilience. 15 | 16 | **SafeStake is the first ETH staking pool to implement distributed validator technology (DVT) written in Rust for increased decentralization, security, and reliability.** 17 | 18 | ### Test Drive SafeStake 19 | 20 | You can join the SafeStake testnet by running a **Validator** or an **Operator Node**. 21 | 22 |
Test SafeStake

Join the SafeStake Network

23 | 24 | ### Run a SafeStake Validator 25 | 26 | In the SafeStake ecosystem, there is no need for stakers to deploy validators as they delegate those duties to operators. A deposit of as little as .01 ETH up to 32 ETH is all a user needs to join the network as a validator. Just connect your wallet and follow the instructions to get started. 27 | 28 | ### Run a SafeStake Operator Node 29 | 30 | Please refer to the step-by-step instructions [here](docs/safestake-running-an-operator-node.md). 31 | 32 | ## SafeStake White Paper 33 | 34 | Read the SafeStake [white paper](https://docsend.com/view/22tth6krr9mnfhre?lt\_utm\_source=lt\_share\_link). 35 | 36 | ## Additional Information 37 | 38 | Check out [our website](https://www.safestake.xyz/) for more about SafeStake. 39 | 40 | [Help test](https://testnet.safestake.xyz/) the SafeStake network! 41 | 42 | Twitter: [https://twitter.com/safestakeDVT](https://twitter.com/safestakeDVT) 43 | 44 | Join our [Discord](http://discord.gg/zFS3Mnfpwj) chat channel! 45 | 46 | ## Beta Advisory 47 | 48 | Currently, the SafeStake project is in public testnet stage. In addition, the smart contracts have been reviewed by the Nethermind Team and fulfilled audit by PeckShield. Please check the detailed [audit report](https://github.com/peckshield/publications/tree/master/audit_reports/PeckShield-Audit-Report-SafeStake-v1.0.pdf) and the Operator Networking Security Assessment Report by SigmaPrime. [Sigma_Prime_SafeStake_Operator_Security_Assessment_Report_v2_1.pdf](https://github.com/user-attachments/files/17098313/Sigma_Prime_SafeStake_Operator_Security_Assessment_Report_v2_1.pdf). 49 | Stay tuned for the Stage1 mainnet launch! 50 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Please see [Releases](https://github.com/ParaState/SafeStakeOperator/releases). We recommend using the most recently released version. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | Please send vulnerability reports to team@safestake.xyz 10 | 11 | Please do not file a public ticket mentioning the vulnerability, as doing so could increase the likelihood of the vulnerability being used before a fix has been created, released and installed on the network. 12 | -------------------------------------------------------------------------------- /boot_config/boot_enrs.yaml: -------------------------------------------------------------------------------- 1 | - enr:-IS4QCQaienDvEyWvFY9-wkj55spRowzzp-so55JRefrrTAeAbQ3Lr7fl9_k5ScRQBxeozZ1qZRLJkQpZGOLLNd3q6QBgmlkgnY0gmlwhBKNvWmJc2VjcDI1NmsxoQL4ns4R7bHwiMB7LId7Kc7KCbScmVhDxcROOxpUHVnz8oN1ZHCCIy0 2 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | // This is a stub for determining the build profile, see `build_profile_name`. 2 | fn main() {} 3 | -------------------------------------------------------------------------------- /common/dvf_directory/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dvf_directory" 3 | version = "0.1.0" 4 | authors = ["Zhicong Huang "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | dirs = "3.0.1" 9 | lighthouse_directory = { path = "../../lighthouse/common/directory", package = "directory" } 10 | dvf_version = { path = "../dvf_version" } 11 | clap = "4.5.4" 12 | 13 | 14 | [dev-dependencies] 15 | -------------------------------------------------------------------------------- /common/dvf_directory/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | use lighthouse_directory::{ 3 | get_network_dir, DEFAULT_ROOT_DIR 4 | }; 5 | use dvf_version::ROOT_VERSION; 6 | use clap::ArgMatches; 7 | 8 | pub fn get_default_base_dir(cli_args: &ArgMatches) -> PathBuf { 9 | dirs::home_dir() 10 | .unwrap_or_else(|| PathBuf::from(".")) 11 | .join(DEFAULT_ROOT_DIR) 12 | .join(format!("v{}", ROOT_VERSION)) 13 | .join(get_network_dir(cli_args)) 14 | } -------------------------------------------------------------------------------- /common/dvf_version/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dvf_version" 3 | version = "0.1.0" 4 | authors = ["Zhicong Huang "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | 9 | 10 | [dev-dependencies] 11 | -------------------------------------------------------------------------------- /common/dvf_version/src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | /// Up to 1 million 3 | /// !NOTE: Don't change this unless you know want you are doing. We relate this to the database storage path of dvf. 4 | /// Changing this might essentially have the effect of cleaning all data. 5 | pub const ROOT_VERSION: u64 = 1; 6 | /// Up to 1 million 7 | pub const MAJOR_VERSION: u64 = 3; 8 | /// Up to 1 million 9 | pub const MINOR_VERSION: u64 = 4; 10 | 11 | pub static VERSION: u64 = ROOT_VERSION * 1_000_000_000_000 + MAJOR_VERSION * 1_000_000 + MINOR_VERSION; 12 | 13 | 14 | pub const SOFTWARE_MINOR_VERSION: u64 = 5; 15 | pub static SOFTWARE_VERSION: u64 = ROOT_VERSION * 1_000_000_000_000 + MAJOR_VERSION * 1_000_000 + SOFTWARE_MINOR_VERSION; -------------------------------------------------------------------------------- /docker-compose-boot.yml: -------------------------------------------------------------------------------- 1 | services: 2 | dvf_root_node: 3 | network_mode: "host" 4 | image: parastate/dvf-operator:${IMAGE_TAG} 5 | pull_policy: always 6 | command: 7 | - /bin/sh 8 | - -c 9 | - | 10 | dvf boot_node --ip ${NODE_IP} --port 9005 2>&1 11 | expose: 12 | - "9005" 13 | volumes: 14 | - boot-data:/root/.lighthouse 15 | volumes: 16 | boot-data: 17 | driver: local 18 | driver_opts: 19 | o: bind 20 | type: none 21 | device: /data/boot 22 | -------------------------------------------------------------------------------- /docker-log-configure/daemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "position-comment": "put this file to /etc/docker/daemon.json, and reload all container", 3 | "log-driver": "json-file", 4 | "log-opts": { 5 | "max-size": "100m", 6 | "max-file": "5" 7 | } 8 | } -------------------------------------------------------------------------------- /docs/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | * [SafeStake: A trust-minimized middle layer for secure, decentralized ETH staking](README.md) 4 | * [SafeStake: Ecosystem](safestake-ecosystem.md) 5 | * [SafeStake: Tech Stack](safestake-tech-stack.md) 6 | * [SafeStake: Tokenomics (ongoing)](safestake-tokenomics-ongoing.md) 7 | * [SafeStake: Running an Operator Node (on going)](safestake-running-an-operator-node.md) 8 | * [Distributed Key Generation](safestake-tech-dkg.md) 9 | -------------------------------------------------------------------------------- /docs/imgs/committe-size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/committe-size.png -------------------------------------------------------------------------------- /docs/imgs/infura-step1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/infura-step1.png -------------------------------------------------------------------------------- /docs/imgs/infura-step2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/infura-step2.png -------------------------------------------------------------------------------- /docs/imgs/infura-step3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/infura-step3.png -------------------------------------------------------------------------------- /docs/imgs/infura-step4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/infura-step4.png -------------------------------------------------------------------------------- /docs/imgs/operatpr-setup1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/operatpr-setup1.png -------------------------------------------------------------------------------- /docs/imgs/operatpr-setup2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/operatpr-setup2.png -------------------------------------------------------------------------------- /docs/imgs/operatpr-setup3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/operatpr-setup3.png -------------------------------------------------------------------------------- /docs/imgs/operatpr-setup4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/operatpr-setup4.png -------------------------------------------------------------------------------- /docs/imgs/operatpr-setup5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/operatpr-setup5.png -------------------------------------------------------------------------------- /docs/imgs/operatpr-setup6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/operatpr-setup6.png -------------------------------------------------------------------------------- /docs/imgs/validator-exit-upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/validator-exit-upload.png -------------------------------------------------------------------------------- /docs/imgs/validator-exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/docs/imgs/validator-exit.png -------------------------------------------------------------------------------- /docs/safestake-license-attribution.md: -------------------------------------------------------------------------------- 1 | # Attribution Notice 2 | 3 | Safestake implements its operator software based on [Hotstuff](https://github.com/asonnino/hotstuff) and [Lighthouse validator client](https://github.com/sigp/lighthouse/tree/stable/validator_client). 4 | 5 | ## Hotstuff 6 | Our code under the `hotstuff` directory is mostly taken from the [Hotstuff](https://github.com/asonnino/hotstuff) repository, with the following modification: 7 | - Upgrade to support port reuse for multiple committees (VAs) 8 | - Optimize recovery and syncrhonization mechanisms after node crash and reboot 9 | 10 | 11 | ## Lighthouse 12 | Our operator is a modified decentralized version of Lighhouse's validator client. It reuses most of Lighthouse's VA logics, including: 13 | - Duty retrieval and execution 14 | - Slashing protection 15 | 16 | The most important updates we make are: 17 | - Update the signing method to include an option to sign distributely among a committee of operators 18 | - Update the VA load and save logics to handle operators instead of complete validators. -------------------------------------------------------------------------------- /docs/safestake-running-a-boot-node.md: -------------------------------------------------------------------------------- 1 | # SafeStake: Running a Boot Node 2 | 3 | **Updates happen frequently! Our** [**Github**](https://github.com/ParaState/SafeStakeOperator) **always has the latest operator node resources and setup instructions.** 4 | 5 | 6 | ***NOTE: This tutorial is meant for SafeStake admininistrator. You DON'T need to read this if you are a user who wants to setup an operator node. Instead, you should read the [tutorial for operator node](./safestake-running-an-operator-node.md).*** 7 | 8 | 9 | ## **Boot Node Service** 10 | 11 | The duty agreement among operators uses Hotstuff consensus and runs on a p2p network. This requires operators to know each other's IP addresses. For this purpose, SafeStake runs and maintains a root node that operators can consult and use to join the p2p network. 12 | 13 | **Dependencies** 14 | 15 | **Server** 16 | 17 | * Public Static Network IP 18 | * Hardware(Recommend) 19 | * CPU: 2 20 | * Memory: 2G 21 | * Disk: 30GB 22 | * OS 23 | * Unix 24 | * Software 25 | * Docker 26 | * Docker Compose 27 | 28 | **Set firewall rule** 29 | 30 | | Port range | Protocol | Source | 31 | | ---------- | -------- | --------- | 32 | | 9005 | TCP & UDP | 0.0.0.0/0 | 33 | 34 | **Installation** 35 | 36 | Clone this repository: 37 | 38 | ``` 39 | sudo mkdir -p /data/boot 40 | git clone --recurse-submodules https://github.com/ParaState/SafeStakeOperator dvf 41 | cd dvf 42 | mv .env.example .env 43 | ``` 44 | 45 | Install Docker and Docker Compose 46 | 47 | * [install docker engine](https://docs.docker.com/engine/install/) 48 | * [install docker compose](https://docs.docker.com/compose/install/) 49 | 50 | 51 | 52 | **Start Service** 53 | 54 | Run the following to start the root node service: 55 | 56 | ``` 57 | sudo docker compose -f docker-compose-boot.yml up -d 58 | ``` 59 | 60 | Get root node enr 61 | 62 | ``` 63 | docker compose -f docker-compose-boot.yml logs -f dvf_root_node | grep enr 64 | ``` 65 | 66 | output 67 | 68 | > dvf-dvf\_root\_node-1 | Base64 ENR: _enr:-IS4QNa-kpJM1eWfueeEnY2iXlLAL0QY2gAWAhmsb4c8VmrSK9J7N5dfXS\_DgSASCDrUTHMqMUlP4OXSYEVh-Z7zFHkBgmlkgnY0gmlwhAMBnbWJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2\_oxVtw0RW\_QAdpzBQA8yWM0xOIN1ZHCCIy0_ 69 | 70 | _**NOTE:**_ SafeStake will maintain the ENR(s) of the boot node(s) on its website so that users registering as operators can utilize them to start operator nodes. 71 | 72 | 73 | **`The boot node is now ready to be used.`** 74 | -------------------------------------------------------------------------------- /docs/safestake-tech-dkg.md: -------------------------------------------------------------------------------- 1 | # Distributed Key Generation 2 | 3 | Safestake implements the distributed key generation algorithm for BLS threshold signature introduced in [this paper](https://eprint.iacr.org/2019/985.pdf). 4 | 5 | ## Algorithm features 6 | The algorithm generates a BLS secret key that is secret-shared among $n$ parties, with a security threshold of $t$, supporting $(t, n)$- BLS threshold signature. More details: 7 | * The algorithm is completely distributed, hence no single party obtains the plain secret key. 8 | * Our implementation supports different security options, against either passive adversary or active adversary (Default: active security). 9 | * A $(3, 4)$-threshold instantiation means as long as there are 3 honest parties among 4 participants, then the security is guaranteed (i.e., tolerating at most $n-t$ malicious parties). 10 | 11 | ## Usage 12 | Usage examples can be found in the rich tests of the code repository. A standard use case is shown [here](https://github.com/ParaState/SafeStakeOperator/blob/33df5533533436994b788d0cede34797c48e9e84/src/crypto/dkg.rs#L959). 13 | 14 | ## Unit / integration tests 15 | You can run the DKG test with (active security): 16 | ```bash 17 | cargo test test_dkg_secure_net -- --show-output 18 | ``` -------------------------------------------------------------------------------- /hotstuff/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["store", "crypto", "network", "mempool", "consensus", "config", "utils"] -------------------------------------------------------------------------------- /hotstuff/benchmark/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 98 | __pypackages__/ 99 | 100 | # Celery stuff 101 | celerybeat-schedule 102 | celerybeat.pid 103 | 104 | # SageMath parsed files 105 | *.sage.py 106 | 107 | # Environments 108 | .env 109 | .venv 110 | env/ 111 | venv/ 112 | ENV/ 113 | env.bak/ 114 | venv.bak/ 115 | 116 | # Spyder project settings 117 | .spyderproject 118 | .spyproject 119 | 120 | # Rope project settings 121 | .ropeproject 122 | 123 | # mkdocs documentation 124 | /site 125 | 126 | # mypy 127 | .mypy_cache/ 128 | .dmypy.json 129 | dmypy.json 130 | 131 | # Pyre type checker 132 | .pyre/ 133 | 134 | # pytype static type analyzer 135 | .pytype/ 136 | 137 | # Cython debug symbols 138 | cython_debug/ 139 | -------------------------------------------------------------------------------- /hotstuff/benchmark/benchmark/__init__: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/benchmark/__init__ -------------------------------------------------------------------------------- /hotstuff/benchmark/benchmark/commands.py: -------------------------------------------------------------------------------- 1 | from os.path import join 2 | 3 | from benchmark.utils import PathMaker 4 | 5 | 6 | class CommandMaker: 7 | 8 | @staticmethod 9 | def cleanup(): 10 | return ( 11 | f'rm -r .db-* ; rm .*.json ; mkdir -p {PathMaker.results_path()}' 12 | ) 13 | 14 | @staticmethod 15 | def clean_logs(): 16 | return f'rm -r {PathMaker.logs_path()} ; mkdir -p {PathMaker.logs_path()}' 17 | 18 | @staticmethod 19 | def compile(): 20 | return 'cargo build --quiet --release --features benchmark' 21 | 22 | @staticmethod 23 | def generate_key(filename): 24 | assert isinstance(filename, str) 25 | return f'./node keys --filename {filename}' 26 | 27 | @staticmethod 28 | def run_node(keys, committee, store, parameters, debug=False): 29 | assert isinstance(keys, str) 30 | assert isinstance(committee, str) 31 | assert isinstance(parameters, str) 32 | assert isinstance(debug, bool) 33 | v = '-vvv' if debug else '-vv' 34 | return (f'./node {v} run --keys {keys} --committee {committee} ' 35 | f'--store {store} --parameters {parameters}') 36 | 37 | @staticmethod 38 | def run_client(address, size, rate, timeout, nodes=[]): 39 | assert isinstance(address, str) 40 | assert isinstance(size, int) and size > 0 41 | assert isinstance(rate, int) and rate >= 0 42 | assert isinstance(nodes, list) 43 | assert all(isinstance(x, str) for x in nodes) 44 | nodes = f'--nodes {" ".join(nodes)}' if nodes else '' 45 | return (f'./client {address} --size {size} ' 46 | f'--rate {rate} --timeout {timeout} {nodes}') 47 | 48 | @staticmethod 49 | def kill(): 50 | return 'tmux kill-server' 51 | 52 | @staticmethod 53 | def alias_binaries(origin): 54 | assert isinstance(origin, str) 55 | node, client = join(origin, 'node'), join(origin, 'client') 56 | return f'rm node ; rm client ; ln -s {node} . ; ln -s {client} .' 57 | -------------------------------------------------------------------------------- /hotstuff/benchmark/benchmark/settings.py: -------------------------------------------------------------------------------- 1 | from json import load, JSONDecodeError 2 | 3 | 4 | class SettingsError(Exception): 5 | pass 6 | 7 | 8 | class Settings: 9 | def __init__(self, testbed, key_name, key_path, consensus_port, mempool_port, 10 | front_port, repo_name, repo_url, branch, instance_type, aws_regions): 11 | if isinstance(aws_regions, list): 12 | regions = aws_regions 13 | else: 14 | [aws_regions] 15 | 16 | inputs_str = [ 17 | testbed, key_name, key_path, repo_name, repo_url, branch, instance_type 18 | ] 19 | inputs_str += regions 20 | inputs_int = [consensus_port, mempool_port, front_port] 21 | ok = all(isinstance(x, str) for x in inputs_str) 22 | ok &= all(isinstance(x, int) for x in inputs_int) 23 | ok &= len(regions) > 0 24 | if not ok: 25 | raise SettingsError('Invalid settings types') 26 | 27 | self.testbed = testbed 28 | 29 | self.key_name = key_name 30 | self.key_path = key_path 31 | 32 | self.consensus_port = consensus_port 33 | self.mempool_port = mempool_port 34 | self.front_port = front_port 35 | 36 | self.repo_name = repo_name 37 | self.repo_url = repo_url 38 | self.branch = branch 39 | 40 | self.instance_type = instance_type 41 | self.aws_regions = regions 42 | 43 | @classmethod 44 | def load(cls, filename): 45 | try: 46 | with open(filename, 'r') as f: 47 | data = load(f) 48 | 49 | return cls( 50 | data['testbed'], 51 | data['key']['name'], 52 | data['key']['path'], 53 | data['ports']['consensus'], 54 | data['ports']['mempool'], 55 | data['ports']['front'], 56 | data['repo']['name'], 57 | data['repo']['url'], 58 | data['repo']['branch'], 59 | data['instances']['type'], 60 | data['instances']['regions'], 61 | ) 62 | except (OSError, JSONDecodeError) as e: 63 | raise SettingsError(str(e)) 64 | 65 | except KeyError as e: 66 | raise SettingsError(f'Malformed settings: missing key {e}') 67 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/2-chain/plots/faults-latency.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/2-chain/plots/faults-latency.pdf -------------------------------------------------------------------------------- /hotstuff/benchmark/data/2-chain/plots/faults-latency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/2-chain/plots/faults-latency.png -------------------------------------------------------------------------------- /hotstuff/benchmark/data/2-chain/plots/faults-robustness.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/2-chain/plots/faults-robustness.pdf -------------------------------------------------------------------------------- /hotstuff/benchmark/data/2-chain/plots/faults-robustness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/2-chain/plots/faults-robustness.png -------------------------------------------------------------------------------- /hotstuff/benchmark/data/2-chain/plots/latency.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/2-chain/plots/latency.pdf -------------------------------------------------------------------------------- /hotstuff/benchmark/data/2-chain/plots/latency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/2-chain/plots/latency.png -------------------------------------------------------------------------------- /hotstuff/benchmark/data/2-chain/plots/robustness.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/2-chain/plots/robustness.pdf -------------------------------------------------------------------------------- /hotstuff/benchmark/data/2-chain/plots/robustness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/2-chain/plots/robustness.png -------------------------------------------------------------------------------- /hotstuff/benchmark/data/2-chain/plots/tps.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/2-chain/plots/tps.pdf -------------------------------------------------------------------------------- /hotstuff/benchmark/data/2-chain/plots/tps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/2-chain/plots/tps.png -------------------------------------------------------------------------------- /hotstuff/benchmark/data/2-chain/results/bench-0-50-100000-512.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Faults: 0 nodes 7 | Committee size: 50 nodes 8 | Input rate: 100,000 tx/s 9 | Transaction size: 512 B 10 | Execution time: 297 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 5,000 ms 14 | Mempool GC depth: 50 rounds 15 | Mempool sync retry delay: 5,000 ms 16 | Mempool sync retry nodes: 3 nodes 17 | Mempool batch size: 500,000 B 18 | Mempool max batch delay: 100 ms 19 | 20 | + RESULTS: 21 | Consensus TPS: 89,443 tx/s 22 | Consensus BPS: 45,794,634 B/s 23 | Consensus latency: 2,605 ms 24 | 25 | End-to-end TPS: 89,379 tx/s 26 | End-to-end BPS: 45,761,950 B/s 27 | End-to-end latency: 5,812 ms 28 | ----------------------------------------- 29 | 30 | ----------------------------------------- 31 | SUMMARY: 32 | ----------------------------------------- 33 | + CONFIG: 34 | Faults: 0 nodes 35 | Committee size: 50 nodes 36 | Input rate: 100,000 tx/s 37 | Transaction size: 512 B 38 | Execution time: 288 s 39 | 40 | Consensus timeout delay: 5,000 ms 41 | Consensus sync retry delay: 5,000 ms 42 | Mempool GC depth: 50 rounds 43 | Mempool sync retry delay: 5,000 ms 44 | Mempool sync retry nodes: 3 nodes 45 | Mempool batch size: 500,000 B 46 | Mempool max batch delay: 100 ms 47 | 48 | + RESULTS: 49 | Consensus TPS: 83,160 tx/s 50 | Consensus BPS: 42,578,107 B/s 51 | Consensus latency: 19,937 ms 52 | 53 | End-to-end TPS: 83,102 tx/s 54 | End-to-end BPS: 42,548,416 B/s 55 | End-to-end latency: 24,608 ms 56 | ----------------------------------------- 57 | 58 | ----------------------------------------- 59 | SUMMARY: 60 | ----------------------------------------- 61 | + CONFIG: 62 | Faults: 0 nodes 63 | Committee size: 50 nodes 64 | Input rate: 100,000 tx/s 65 | Transaction size: 512 B 66 | Execution time: 293 s 67 | 68 | Consensus timeout delay: 5,000 ms 69 | Consensus sync retry delay: 5,000 ms 70 | Mempool GC depth: 50 rounds 71 | Mempool sync retry delay: 5,000 ms 72 | Mempool sync retry nodes: 3 nodes 73 | Mempool batch size: 500,000 B 74 | Mempool max batch delay: 100 ms 75 | 76 | + RESULTS: 77 | Consensus TPS: 93,620 tx/s 78 | Consensus BPS: 47,933,543 B/s 79 | Consensus latency: 4,051 ms 80 | 81 | End-to-end TPS: 93,604 tx/s 82 | End-to-end BPS: 47,925,034 B/s 83 | End-to-end latency: 7,349 ms 84 | ----------------------------------------- 85 | 86 | ----------------------------------------- 87 | SUMMARY: 88 | ----------------------------------------- 89 | + CONFIG: 90 | Faults: 0 nodes 91 | Committee size: 50 nodes 92 | Input rate: 100,000 tx/s 93 | Transaction size: 512 B 94 | Execution time: 301 s 95 | 96 | Consensus timeout delay: 5,000 ms 97 | Consensus sync retry delay: 5,000 ms 98 | Mempool GC depth: 50 rounds 99 | Mempool sync retry delay: 5,000 ms 100 | Mempool sync retry nodes: 3 nodes 101 | Mempool batch size: 500,000 B 102 | Mempool max batch delay: 100 ms 103 | 104 | + RESULTS: 105 | Consensus TPS: 97,861 tx/s 106 | Consensus BPS: 50,104,628 B/s 107 | Consensus latency: 1,223 ms 108 | 109 | End-to-end TPS: 97,772 tx/s 110 | End-to-end BPS: 50,059,042 B/s 111 | End-to-end latency: 1,692 ms 112 | ----------------------------------------- 113 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/plots/faults-latency.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/3-chain/plots/faults-latency.pdf -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/plots/faults-latency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/3-chain/plots/faults-latency.png -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/plots/faults-robustness.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/3-chain/plots/faults-robustness.pdf -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/plots/faults-robustness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/3-chain/plots/faults-robustness.png -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/plots/latency.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/3-chain/plots/latency.pdf -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/plots/latency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/3-chain/plots/latency.png -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/plots/robustness.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/3-chain/plots/robustness.pdf -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/plots/robustness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/3-chain/plots/robustness.png -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/plots/tps.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/3-chain/plots/tps.pdf -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/plots/tps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/hotstuff/benchmark/data/3-chain/plots/tps.png -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-10-50000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 10 nodes 7 | Input rate: 50,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 301 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 49,854 tx/s 23 | Consensus BPS: 25,525,105 B/s 24 | Consensus latency: 886 ms 25 | 26 | End-to-end TPS: 49,829 tx/s 27 | End-to-end BPS: 25,512,316 B/s 28 | End-to-end latency: 1,666 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 10 nodes 36 | Input rate: 50,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 291 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 40,854 tx/s 52 | Consensus BPS: 20,917,339 B/s 53 | Consensus latency: 1,359 ms 54 | 55 | End-to-end TPS: 40,836 tx/s 56 | End-to-end BPS: 20,908,061 B/s 57 | End-to-end latency: 3,040 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 10 nodes 65 | Input rate: 50,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 301 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 49,896 tx/s 81 | Consensus BPS: 25,546,542 B/s 82 | Consensus latency: 708 ms 83 | 84 | End-to-end TPS: 49,866 tx/s 85 | End-to-end BPS: 25,531,446 B/s 86 | End-to-end latency: 1,378 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-10-60000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 10 nodes 7 | Input rate: 60,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 302 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 59,792 tx/s 23 | Consensus BPS: 30,613,524 B/s 24 | Consensus latency: 697 ms 25 | 26 | End-to-end TPS: 59,786 tx/s 27 | End-to-end BPS: 30,610,275 B/s 28 | End-to-end latency: 1,360 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 10 nodes 36 | Input rate: 60,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 302 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 59,891 tx/s 52 | Consensus BPS: 30,664,375 B/s 53 | Consensus latency: 692 ms 54 | 55 | End-to-end TPS: 59,833 tx/s 56 | End-to-end BPS: 30,634,510 B/s 57 | End-to-end latency: 1,433 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 10 nodes 65 | Input rate: 60,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 301 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 59,845 tx/s 81 | Consensus BPS: 30,640,695 B/s 82 | Consensus latency: 724 ms 83 | 84 | End-to-end TPS: 59,800 tx/s 85 | End-to-end BPS: 30,617,382 B/s 86 | End-to-end latency: 1,776 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-10-70000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 10 nodes 7 | Input rate: 70,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 301 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 69,803 tx/s 23 | Consensus BPS: 35,738,992 B/s 24 | Consensus latency: 715 ms 25 | 26 | End-to-end TPS: 69,769 tx/s 27 | End-to-end BPS: 35,721,793 B/s 28 | End-to-end latency: 1,487 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 10 nodes 36 | Input rate: 70,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 301 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 69,827 tx/s 52 | Consensus BPS: 35,751,540 B/s 53 | Consensus latency: 729 ms 54 | 55 | End-to-end TPS: 69,796 tx/s 56 | End-to-end BPS: 35,735,406 B/s 57 | End-to-end latency: 2,839 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 10 nodes 65 | Input rate: 70,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 301 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 69,877 tx/s 81 | Consensus BPS: 35,776,957 B/s 82 | Consensus latency: 719 ms 83 | 84 | End-to-end TPS: 69,776 tx/s 85 | End-to-end BPS: 35,725,211 B/s 86 | End-to-end latency: 1,736 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-10-80000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 10 nodes 7 | Input rate: 80,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 301 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 79,841 tx/s 23 | Consensus BPS: 40,878,623 B/s 24 | Consensus latency: 1,429 ms 25 | 26 | End-to-end TPS: 79,756 tx/s 27 | End-to-end BPS: 40,834,895 B/s 28 | End-to-end latency: 3,589 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 10 nodes 36 | Input rate: 80,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 301 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 77,742 tx/s 52 | Consensus BPS: 39,803,831 B/s 53 | Consensus latency: 1,494 ms 54 | 55 | End-to-end TPS: 77,670 tx/s 56 | End-to-end BPS: 39,767,247 B/s 57 | End-to-end latency: 5,197 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 10 nodes 65 | Input rate: 80,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 301 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 79,810 tx/s 81 | Consensus BPS: 40,862,737 B/s 82 | Consensus latency: 721 ms 83 | 84 | End-to-end TPS: 79,764 tx/s 85 | End-to-end BPS: 40,839,279 B/s 86 | End-to-end latency: 2,648 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-10-85000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 10 nodes 7 | Input rate: 85,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 204 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 65,916 tx/s 23 | Consensus BPS: 33,748,794 B/s 24 | Consensus latency: 2,490 ms 25 | 26 | End-to-end TPS: 65,805 tx/s 27 | End-to-end BPS: 33,692,003 B/s 28 | End-to-end latency: 12,509 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 10 nodes 36 | Input rate: 85,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 299 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 81,006 tx/s 52 | Consensus BPS: 41,475,150 B/s 53 | Consensus latency: 974 ms 54 | 55 | End-to-end TPS: 80,954 tx/s 56 | End-to-end BPS: 41,448,234 B/s 57 | End-to-end latency: 9,417 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 10 nodes 65 | Input rate: 85,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 223 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 54,393 tx/s 81 | Consensus BPS: 27,849,440 B/s 82 | Consensus latency: 2,640 ms 83 | 84 | End-to-end TPS: 54,344 tx/s 85 | End-to-end BPS: 27,824,308 B/s 86 | End-to-end latency: 17,910 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-10000-512-1.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 9,500 tx/s 8 | Transaction size: 512 B 9 | Faults: 1 nodes 10 | Execution time: 301 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 6,434 tx/s 23 | Consensus BPS: 3,294,111 B/s 24 | Consensus latency: 2,449 ms 25 | 26 | End-to-end TPS: 6,227 tx/s 27 | End-to-end BPS: 3,188,173 B/s 28 | End-to-end latency: 6,562 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 9,500 tx/s 37 | Transaction size: 512 B 38 | Faults: 1 nodes 39 | Execution time: 294 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 7,356 tx/s 52 | Consensus BPS: 3,766,137 B/s 53 | Consensus latency: 3,090 ms 54 | 55 | End-to-end TPS: 7,118 tx/s 56 | End-to-end BPS: 3,644,600 B/s 57 | End-to-end latency: 7,109 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 9,500 tx/s 66 | Transaction size: 512 B 67 | Faults: 1 nodes 68 | Execution time: 296 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 6,349 tx/s 81 | Consensus BPS: 3,250,458 B/s 82 | Consensus latency: 2,325 ms 83 | 84 | End-to-end TPS: 6,147 tx/s 85 | End-to-end BPS: 3,147,383 B/s 86 | End-to-end latency: 6,158 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-10000-512-3.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 8,500 tx/s 8 | Transaction size: 512 B 9 | Faults: 3 nodes 10 | Execution time: 278 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 4,760 tx/s 23 | Consensus BPS: 2,437,117 B/s 24 | Consensus latency: 8,703 ms 25 | 26 | End-to-end TPS: 4,733 tx/s 27 | End-to-end BPS: 2,423,146 B/s 28 | End-to-end latency: 13,094 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 8,500 tx/s 37 | Transaction size: 512 B 38 | Faults: 3 nodes 39 | Execution time: 297 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 4,997 tx/s 52 | Consensus BPS: 2,558,349 B/s 53 | Consensus latency: 6,810 ms 54 | 55 | End-to-end TPS: 4,968 tx/s 56 | End-to-end BPS: 2,543,526 B/s 57 | End-to-end latency: 11,737 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 8,500 tx/s 66 | Transaction size: 512 B 67 | Faults: 3 nodes 68 | Execution time: 280 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 5,591 tx/s 81 | Consensus BPS: 2,862,765 B/s 82 | Consensus latency: 4,788 ms 83 | 84 | End-to-end TPS: 5,563 tx/s 85 | End-to-end BPS: 2,848,222 B/s 86 | End-to-end latency: 9,845 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-100000-512-1.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 95,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 1 nodes 10 | Execution time: 253 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 25,098 tx/s 23 | Consensus BPS: 12,850,176 B/s 24 | Consensus latency: 3,227 ms 25 | 26 | End-to-end TPS: 25,084 tx/s 27 | End-to-end BPS: 12,843,156 B/s 28 | End-to-end latency: 13,435 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 95,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 1 nodes 39 | Execution time: 300 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 37,012 tx/s 52 | Consensus BPS: 18,950,278 B/s 53 | Consensus latency: 1,988 ms 54 | 55 | End-to-end TPS: 36,995 tx/s 56 | End-to-end BPS: 18,941,233 B/s 57 | End-to-end latency: 13,948 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 95,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 1 nodes 68 | Execution time: 292 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 35,901 tx/s 81 | Consensus BPS: 18,381,288 B/s 82 | Consensus latency: 2,031 ms 83 | 84 | End-to-end TPS: 35,868 tx/s 85 | End-to-end BPS: 18,364,329 B/s 86 | End-to-end latency: 13,469 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-100000-512-3.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 85,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 3 nodes 10 | Execution time: 290 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 11,963 tx/s 23 | Consensus BPS: 6,125,022 B/s 24 | Consensus latency: 5,482 ms 25 | 26 | End-to-end TPS: 11,899 tx/s 27 | End-to-end BPS: 6,092,261 B/s 28 | End-to-end latency: 21,948 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 85,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 3 nodes 39 | Execution time: 299 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 11,473 tx/s 52 | Consensus BPS: 5,873,997 B/s 53 | Consensus latency: 5,803 ms 54 | 55 | End-to-end TPS: 11,405 tx/s 56 | End-to-end BPS: 5,839,500 B/s 57 | End-to-end latency: 23,763 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 85,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 3 nodes 68 | Execution time: 292 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 11,889 tx/s 81 | Consensus BPS: 6,087,151 B/s 82 | Consensus latency: 5,476 ms 83 | 84 | End-to-end TPS: 11,816 tx/s 85 | End-to-end BPS: 6,049,865 B/s 86 | End-to-end latency: 20,961 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-20000-512-3.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 17,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 3 nodes 10 | Execution time: 298 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 7,475 tx/s 23 | Consensus BPS: 3,827,281 B/s 24 | Consensus latency: 7,684 ms 25 | 26 | End-to-end TPS: 7,458 tx/s 27 | End-to-end BPS: 3,818,268 B/s 28 | End-to-end latency: 12,758 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 17,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 3 nodes 39 | Execution time: 294 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 6,952 tx/s 52 | Consensus BPS: 3,559,482 B/s 53 | Consensus latency: 8,274 ms 54 | 55 | End-to-end TPS: 6,935 tx/s 56 | End-to-end BPS: 3,550,891 B/s 57 | End-to-end latency: 12,802 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 17,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 3 nodes 68 | Execution time: 299 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 7,331 tx/s 81 | Consensus BPS: 3,753,631 B/s 82 | Consensus latency: 10,361 ms 83 | 84 | End-to-end TPS: 7,321 tx/s 85 | End-to-end BPS: 3,748,461 B/s 86 | End-to-end latency: 14,917 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-30000-512-1.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 28,500 tx/s 8 | Transaction size: 512 B 9 | Faults: 1 nodes 10 | Execution time: 297 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 16,779 tx/s 23 | Consensus BPS: 8,591,049 B/s 24 | Consensus latency: 3,567 ms 25 | 26 | End-to-end TPS: 16,638 tx/s 27 | End-to-end BPS: 8,518,574 B/s 28 | End-to-end latency: 7,216 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 28,500 tx/s 37 | Transaction size: 512 B 38 | Faults: 1 nodes 39 | Execution time: 295 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 16,983 tx/s 52 | Consensus BPS: 8,695,329 B/s 53 | Consensus latency: 2,882 ms 54 | 55 | End-to-end TPS: 16,826 tx/s 56 | End-to-end BPS: 8,614,968 B/s 57 | End-to-end latency: 6,547 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 28,500 tx/s 66 | Transaction size: 512 B 67 | Faults: 1 nodes 68 | Execution time: 291 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 15,798 tx/s 81 | Consensus BPS: 8,088,341 B/s 82 | Consensus latency: 2,114 ms 83 | 84 | End-to-end TPS: 15,641 tx/s 85 | End-to-end BPS: 8,008,105 B/s 86 | End-to-end latency: 5,614 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-40000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 40,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 301 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 39,908 tx/s 23 | Consensus BPS: 20,432,709 B/s 24 | Consensus latency: 571 ms 25 | 26 | End-to-end TPS: 39,886 tx/s 27 | End-to-end BPS: 20,421,593 B/s 28 | End-to-end latency: 1,156 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 40,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 301 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 39,904 tx/s 52 | Consensus BPS: 20,430,831 B/s 53 | Consensus latency: 574 ms 54 | 55 | End-to-end TPS: 39,865 tx/s 56 | End-to-end BPS: 20,410,755 B/s 57 | End-to-end latency: 1,256 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 40,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 302 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 39,882 tx/s 81 | Consensus BPS: 20,419,439 B/s 82 | Consensus latency: 577 ms 83 | 84 | End-to-end TPS: 39,878 tx/s 85 | End-to-end BPS: 20,417,475 B/s 86 | End-to-end latency: 1,225 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-50000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 50,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 301 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 49,915 tx/s 23 | Consensus BPS: 25,556,597 B/s 24 | Consensus latency: 546 ms 25 | 26 | End-to-end TPS: 49,845 tx/s 27 | End-to-end BPS: 25,520,784 B/s 28 | End-to-end latency: 1,175 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 50,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 302 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 49,921 tx/s 52 | Consensus BPS: 25,559,351 B/s 53 | Consensus latency: 547 ms 54 | 55 | End-to-end TPS: 49,875 tx/s 56 | End-to-end BPS: 25,536,209 B/s 57 | End-to-end latency: 1,173 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 50,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 302 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 49,923 tx/s 81 | Consensus BPS: 25,560,746 B/s 82 | Consensus latency: 550 ms 83 | 84 | End-to-end TPS: 49,864 tx/s 85 | End-to-end BPS: 25,530,311 B/s 86 | End-to-end latency: 1,262 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-50000-512-1.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 47,500 tx/s 8 | Transaction size: 512 B 9 | Faults: 1 nodes 10 | Execution time: 301 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 25,738 tx/s 23 | Consensus BPS: 13,177,603 B/s 24 | Consensus latency: 3,406 ms 25 | 26 | End-to-end TPS: 25,377 tx/s 27 | End-to-end BPS: 12,992,889 B/s 28 | End-to-end latency: 7,398 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 47,500 tx/s 37 | Transaction size: 512 B 38 | Faults: 1 nodes 39 | Execution time: 296 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 26,379 tx/s 52 | Consensus BPS: 13,505,997 B/s 53 | Consensus latency: 6,163 ms 54 | 55 | End-to-end TPS: 25,997 tx/s 56 | End-to-end BPS: 13,310,467 B/s 57 | End-to-end latency: 10,115 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 47,500 tx/s 66 | Transaction size: 512 B 67 | Faults: 1 nodes 68 | Execution time: 294 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 26,337 tx/s 81 | Consensus BPS: 13,484,571 B/s 82 | Consensus latency: 4,932 ms 83 | 84 | End-to-end TPS: 25,954 tx/s 85 | End-to-end BPS: 13,288,315 B/s 86 | End-to-end latency: 8,724 ms 87 | ----------------------------------------- 88 | 89 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-50000-512-3.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 42,500 tx/s 8 | Transaction size: 512 B 9 | Faults: 3 nodes 10 | Execution time: 294 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 15,308 tx/s 23 | Consensus BPS: 7,837,884 B/s 24 | Consensus latency: 4,694 ms 25 | 26 | End-to-end TPS: 15,107 tx/s 27 | End-to-end BPS: 7,734,686 B/s 28 | End-to-end latency: 16,394 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 42,500 tx/s 37 | Transaction size: 512 B 38 | Faults: 3 nodes 39 | Execution time: 300 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 15,043 tx/s 52 | Consensus BPS: 7,702,137 B/s 53 | Consensus latency: 4,792 ms 54 | 55 | End-to-end TPS: 14,720 tx/s 56 | End-to-end BPS: 7,536,554 B/s 57 | End-to-end latency: 17,078 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 42,500 tx/s 66 | Transaction size: 512 B 67 | Faults: 3 nodes 68 | Execution time: 298 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 15,297 tx/s 81 | Consensus BPS: 7,832,034 B/s 82 | Consensus latency: 5,451 ms 83 | 84 | End-to-end TPS: 14,914 tx/s 85 | End-to-end BPS: 7,636,203 B/s 86 | End-to-end latency: 16,924 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-60000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 60,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 301 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 59,892 tx/s 23 | Consensus BPS: 30,664,497 B/s 24 | Consensus latency: 572 ms 25 | 26 | End-to-end TPS: 59,829 tx/s 27 | End-to-end BPS: 30,632,247 B/s 28 | End-to-end latency: 1,268 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 60,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 202 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 45,697 tx/s 52 | Consensus BPS: 23,396,901 B/s 53 | Consensus latency: 1,104 ms 54 | 55 | End-to-end TPS: 45,677 tx/s 56 | End-to-end BPS: 23,386,599 B/s 57 | End-to-end latency: 4,970 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 60,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 223 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 42,644 tx/s 81 | Consensus BPS: 21,833,927 B/s 82 | Consensus latency: 1,133 ms 83 | 84 | End-to-end TPS: 42,600 tx/s 85 | End-to-end BPS: 21,811,042 B/s 86 | End-to-end latency: 5,203 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-70000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 70,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 190 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 63,415 tx/s 23 | Consensus BPS: 32,468,433 B/s 24 | Consensus latency: 904 ms 25 | 26 | End-to-end TPS: 63,350 tx/s 27 | End-to-end BPS: 32,435,424 B/s 28 | End-to-end latency: 2,952 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 70,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 216 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 44,016 tx/s 52 | Consensus BPS: 22,536,122 B/s 53 | Consensus latency: 2,086 ms 54 | 55 | End-to-end TPS: 43,941 tx/s 56 | End-to-end BPS: 22,497,972 B/s 57 | End-to-end latency: 7,815 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 70,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 187 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 52,216 tx/s 81 | Consensus BPS: 26,734,829 B/s 82 | Consensus latency: 1,558 ms 83 | 84 | End-to-end TPS: 52,144 tx/s 85 | End-to-end BPS: 26,697,707 B/s 86 | End-to-end latency: 5,676 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-70000-512-1.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 66,500 tx/s 8 | Transaction size: 512 B 9 | Faults: 1 nodes 10 | Execution time: 236 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 28,753 tx/s 23 | Consensus BPS: 14,721,692 B/s 24 | Consensus latency: 2,945 ms 25 | 26 | End-to-end TPS: 28,295 tx/s 27 | End-to-end BPS: 14,487,049 B/s 28 | End-to-end latency: 11,528 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 66,500 tx/s 37 | Transaction size: 512 B 38 | Faults: 1 nodes 39 | Execution time: 295 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 38,697 tx/s 52 | Consensus BPS: 19,812,695 B/s 53 | Consensus latency: 2,492 ms 54 | 55 | End-to-end TPS: 38,232 tx/s 56 | End-to-end BPS: 19,574,908 B/s 57 | End-to-end latency: 10,943 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 66,500 tx/s 66 | Transaction size: 512 B 67 | Faults: 1 nodes 68 | Execution time: 298 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 38,358 tx/s 81 | Consensus BPS: 19,639,255 B/s 82 | Consensus latency: 2,742 ms 83 | 84 | End-to-end TPS: 37,899 tx/s 85 | End-to-end BPS: 19,404,436 B/s 86 | End-to-end latency: 12,850 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-70000-512-3.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 59,500 tx/s 8 | Transaction size: 512 B 9 | Faults: 3 nodes 10 | Execution time: 291 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 12,133 tx/s 23 | Consensus BPS: 6,211,870 B/s 24 | Consensus latency: 7,469 ms 25 | 26 | End-to-end TPS: 12,046 tx/s 27 | End-to-end BPS: 6,167,693 B/s 28 | End-to-end latency: 21,965 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 59,500 tx/s 37 | Transaction size: 512 B 38 | Faults: 3 nodes 39 | Execution time: 295 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 11,871 tx/s 52 | Consensus BPS: 6,077,867 B/s 53 | Consensus latency: 7,616 ms 54 | 55 | End-to-end TPS: 11,785 tx/s 56 | End-to-end BPS: 6,033,863 B/s 57 | End-to-end latency: 22,587 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 59,500 tx/s 66 | Transaction size: 512 B 67 | Faults: 3 nodes 68 | Execution time: 292 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 12,112 tx/s 81 | Consensus BPS: 6,201,185 B/s 82 | Consensus latency: 7,410 ms 83 | 84 | End-to-end TPS: 12,028 tx/s 85 | End-to-end BPS: 6,158,477 B/s 86 | End-to-end latency: 22,637 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-80000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 80,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 193 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 51,990 tx/s 23 | Consensus BPS: 26,618,635 B/s 24 | Consensus latency: 1,505 ms 25 | 26 | End-to-end TPS: 51,940 tx/s 27 | End-to-end BPS: 26,593,389 B/s 28 | End-to-end latency: 7,654 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 80,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 228 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 38,722 tx/s 52 | Consensus BPS: 19,825,688 B/s 53 | Consensus latency: 2,059 ms 54 | 55 | End-to-end TPS: 38,693 tx/s 56 | End-to-end BPS: 19,810,827 B/s 57 | End-to-end latency: 10,223 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 80,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 223 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 34,480 tx/s 81 | Consensus BPS: 17,653,548 B/s 82 | Consensus latency: 2,260 ms 83 | 84 | End-to-end TPS: 34,429 tx/s 85 | End-to-end BPS: 17,627,639 B/s 86 | End-to-end latency: 10,586 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-20-80000-512-1.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 20 nodes 7 | Input rate: 76,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 1 nodes 10 | Execution time: 262 s 11 | 12 | Consensus timeout delay: 5,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 26,927 tx/s 23 | Consensus BPS: 13,786,487 B/s 24 | Consensus latency: 2,939 ms 25 | 26 | End-to-end TPS: 26,612 tx/s 27 | End-to-end BPS: 13,625,428 B/s 28 | End-to-end latency: 12,114 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 20 nodes 36 | Input rate: 76,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 1 nodes 39 | Execution time: 301 s 40 | 41 | Consensus timeout delay: 5,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 37,917 tx/s 52 | Consensus BPS: 19,413,554 B/s 53 | Consensus latency: 2,967 ms 54 | 55 | End-to-end TPS: 37,544 tx/s 56 | End-to-end BPS: 19,222,375 B/s 57 | End-to-end latency: 12,329 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 20 nodes 65 | Input rate: 76,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 1 nodes 68 | Execution time: 301 s 69 | 70 | Consensus timeout delay: 5,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 37,141 tx/s 81 | Consensus BPS: 19,016,195 B/s 82 | Consensus latency: 3,743 ms 83 | 84 | End-to-end TPS: 36,762 tx/s 85 | End-to-end BPS: 18,822,147 B/s 86 | End-to-end latency: 13,827 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-50-20000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 50 nodes 7 | Input rate: 20,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 302 s 11 | 12 | Consensus timeout delay: 10,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 19,792 tx/s 23 | Consensus BPS: 10,133,552 B/s 24 | Consensus latency: 1,163 ms 25 | 26 | End-to-end TPS: 19,781 tx/s 27 | End-to-end BPS: 10,127,640 B/s 28 | End-to-end latency: 3,212 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 50 nodes 36 | Input rate: 20,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 302 s 40 | 41 | Consensus timeout delay: 10,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 19,815 tx/s 52 | Consensus BPS: 10,145,197 B/s 53 | Consensus latency: 1,072 ms 54 | 55 | End-to-end TPS: 19,813 tx/s 56 | End-to-end BPS: 10,144,457 B/s 57 | End-to-end latency: 3,106 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 50 nodes 65 | Input rate: 20,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 301 s 69 | 70 | Consensus timeout delay: 10,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 19,767 tx/s 81 | Consensus BPS: 10,120,867 B/s 82 | Consensus latency: 1,192 ms 83 | 84 | End-to-end TPS: 19,759 tx/s 85 | End-to-end BPS: 10,116,736 B/s 86 | End-to-end latency: 3,274 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-50-30000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 50 nodes 7 | Input rate: 30,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 301 s 11 | 12 | Consensus timeout delay: 10,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 29,837 tx/s 23 | Consensus BPS: 15,276,443 B/s 24 | Consensus latency: 889 ms 25 | 26 | End-to-end TPS: 29,810 tx/s 27 | End-to-end BPS: 15,262,743 B/s 28 | End-to-end latency: 2,337 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 50 nodes 36 | Input rate: 30,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 301 s 40 | 41 | Consensus timeout delay: 10,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 29,806 tx/s 52 | Consensus BPS: 15,260,695 B/s 53 | Consensus latency: 876 ms 54 | 55 | End-to-end TPS: 29,787 tx/s 56 | End-to-end BPS: 15,251,069 B/s 57 | End-to-end latency: 2,335 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 50 nodes 65 | Input rate: 30,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 301 s 69 | 70 | Consensus timeout delay: 10,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 29,785 tx/s 81 | Consensus BPS: 15,250,023 B/s 82 | Consensus latency: 942 ms 83 | 84 | End-to-end TPS: 29,770 tx/s 85 | End-to-end BPS: 15,242,183 B/s 86 | End-to-end latency: 2,405 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-50-40000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 50 nodes 7 | Input rate: 40,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 302 s 11 | 12 | Consensus timeout delay: 10,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 21,677 tx/s 23 | Consensus BPS: 11,098,700 B/s 24 | Consensus latency: 1,778 ms 25 | 26 | End-to-end TPS: 21,673 tx/s 27 | End-to-end BPS: 11,096,348 B/s 28 | End-to-end latency: 7,045 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 50 nodes 36 | Input rate: 40,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 201 s 40 | 41 | Consensus timeout delay: 10,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 34,978 tx/s 52 | Consensus BPS: 17,908,542 B/s 53 | Consensus latency: 1,042 ms 54 | 55 | End-to-end TPS: 34,960 tx/s 56 | End-to-end BPS: 17,899,533 B/s 57 | End-to-end latency: 5,961 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 50 nodes 65 | Input rate: 40,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 200 s 69 | 70 | Consensus timeout delay: 10,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 25,851 tx/s 81 | Consensus BPS: 13,235,833 B/s 82 | Consensus latency: 2,858 ms 83 | 84 | End-to-end TPS: 25,825 tx/s 85 | End-to-end BPS: 13,222,263 B/s 86 | End-to-end latency: 9,994 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/data/3-chain/results/bench-50-50000-512-0.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------- 3 | SUMMARY: 4 | ----------------------------------------- 5 | + CONFIG: 6 | Committee size: 50 nodes 7 | Input rate: 50,000 tx/s 8 | Transaction size: 512 B 9 | Faults: 0 nodes 10 | Execution time: 201 s 11 | 12 | Consensus timeout delay: 10,000 ms 13 | Consensus sync retry delay: 100,000 ms 14 | Consensus max payloads size: 1,000 B 15 | Consensus min block delay: 100 ms 16 | Mempool queue capacity: 100,000 B 17 | Mempool sync retry delay: 100,000 ms 18 | Mempool max payloads size: 500,000 B 19 | Mempool min block delay: 100 ms 20 | 21 | + RESULTS: 22 | Consensus TPS: 33,554 tx/s 23 | Consensus BPS: 17,179,757 B/s 24 | Consensus latency: 3,348 ms 25 | 26 | End-to-end TPS: 33,519 tx/s 27 | End-to-end BPS: 17,161,558 B/s 28 | End-to-end latency: 13,239 ms 29 | ----------------------------------------- 30 | 31 | ----------------------------------------- 32 | SUMMARY: 33 | ----------------------------------------- 34 | + CONFIG: 35 | Committee size: 50 nodes 36 | Input rate: 50,000 tx/s 37 | Transaction size: 512 B 38 | Faults: 0 nodes 39 | Execution time: 243 s 40 | 41 | Consensus timeout delay: 10,000 ms 42 | Consensus sync retry delay: 100,000 ms 43 | Consensus max payloads size: 1,000 B 44 | Consensus min block delay: 100 ms 45 | Mempool queue capacity: 100,000 B 46 | Mempool sync retry delay: 100,000 ms 47 | Mempool max payloads size: 500,000 B 48 | Mempool min block delay: 100 ms 49 | 50 | + RESULTS: 51 | Consensus TPS: 27,533 tx/s 52 | Consensus BPS: 14,096,898 B/s 53 | Consensus latency: 3,099 ms 54 | 55 | End-to-end TPS: 27,507 tx/s 56 | End-to-end BPS: 14,083,384 B/s 57 | End-to-end latency: 8,520 ms 58 | ----------------------------------------- 59 | 60 | ----------------------------------------- 61 | SUMMARY: 62 | ----------------------------------------- 63 | + CONFIG: 64 | Committee size: 50 nodes 65 | Input rate: 50,000 tx/s 66 | Transaction size: 512 B 67 | Faults: 0 nodes 68 | Execution time: 221 s 69 | 70 | Consensus timeout delay: 10,000 ms 71 | Consensus sync retry delay: 100,000 ms 72 | Consensus max payloads size: 1,000 B 73 | Consensus min block delay: 100 ms 74 | Mempool queue capacity: 100,000 B 75 | Mempool sync retry delay: 100,000 ms 76 | Mempool max payloads size: 500,000 B 77 | Mempool min block delay: 100 ms 78 | 79 | + RESULTS: 80 | Consensus TPS: 27,029 tx/s 81 | Consensus BPS: 13,838,722 B/s 82 | Consensus latency: 3,874 ms 83 | 84 | End-to-end TPS: 26,989 tx/s 85 | End-to-end BPS: 13,818,402 B/s 86 | End-to-end latency: 13,659 ms 87 | ----------------------------------------- 88 | -------------------------------------------------------------------------------- /hotstuff/benchmark/requirements.txt: -------------------------------------------------------------------------------- 1 | boto3==1.16.0 2 | fabric==2.6.0 3 | matplotlib==3.3.4 -------------------------------------------------------------------------------- /hotstuff/benchmark/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "testbed": "hotstuff", 3 | "key": { 4 | "name": "aws", 5 | "path": "/absolute/ssh/key/path" 6 | }, 7 | "ports": { 8 | "consensus": 8000, 9 | "mempool": 7000, 10 | "front": 6000 11 | }, 12 | "repo": { 13 | "name": "hotstuff", 14 | "url": "https://github.com/asonnino/hotstuff.git", 15 | "branch": "main" 16 | }, 17 | "instances": { 18 | "type": "m5d.8xlarge", 19 | "regions": [ 20 | "us-east-1", 21 | "eu-north-1", 22 | "ap-southeast-2", 23 | "us-west-1", 24 | "ap-northeast-1" 25 | ] 26 | } 27 | } -------------------------------------------------------------------------------- /hotstuff/config/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hotstuff_config" 3 | version = "0.1.0" 4 | authors = ["Alberto Sonnino "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | bincode = "1.3.1" 10 | serde = { version = "1.0", features = ["derive"] } 11 | serde_json = "1.0.61" 12 | rand = "0.7.3" 13 | thiserror = "1.0.21" 14 | crypto = { path = "../crypto" } 15 | consensus = { path = "../consensus" } 16 | mempool = { path = "../mempool" } 17 | hex = "0.4" 18 | zeroize = { version = "1.4.2", features = ["zeroize_derive"] } -------------------------------------------------------------------------------- /hotstuff/consensus/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "consensus" 3 | version = "0.1.0" 4 | authors = ["Alberto Sonnino "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | thiserror = "1.0.21" 10 | tokio = { version = "1.3.0", features = ["rt", "time", "macros", "sync"] } 11 | ed25519-dalek = "2.1.1" 12 | log = "0.4.0" 13 | serde = { version = "1.0", features = ["derive"] } 14 | bytes = "1.0.1" 15 | bincode = "1.3.1" 16 | futures = "0.3.8" 17 | async-recursion = "0.3.1" 18 | base64 = "0.13.0" 19 | async-trait = "0.1.50" 20 | exit-future = "0.2.0" 21 | store = { path = "../store" } 22 | crypto = { path = "../crypto" } 23 | network = { path = "../network" } 24 | mempool = { path = "../mempool" } 25 | utils = { path = "../utils" } 26 | 27 | [dev-dependencies] 28 | tokio-util = { version = "0.6.2", features= ["codec"] } 29 | rand = "0.7.3" 30 | 31 | [features] 32 | benchmark = [] 33 | -------------------------------------------------------------------------------- /hotstuff/consensus/src/config.rs: -------------------------------------------------------------------------------- 1 | use crypto::PublicKey; 2 | use log::info; 3 | use serde::{Deserialize, Serialize}; 4 | use std::collections::HashMap; 5 | use std::net::SocketAddr; 6 | 7 | pub type Stake = u32; 8 | pub type EpochNumber = u128; 9 | 10 | #[derive(Serialize, Deserialize)] 11 | pub struct Parameters { 12 | pub timeout_delay: u64, 13 | pub sync_retry_delay: u64, 14 | } 15 | 16 | impl Default for Parameters { 17 | fn default() -> Self { 18 | Self { 19 | // timeout_delay: 5_000, 20 | timeout_delay: 2_000, 21 | // timeout_delay: 500, 22 | sync_retry_delay: 10_000, 23 | } 24 | } 25 | } 26 | 27 | impl Parameters { 28 | pub fn log(&self) { 29 | // NOTE: These log entries are used to compute performance. 30 | info!("Timeout delay set to {} rounds", self.timeout_delay); 31 | info!("Sync retry delay set to {} ms", self.sync_retry_delay); 32 | } 33 | } 34 | 35 | #[derive(Clone, Serialize, Deserialize)] 36 | pub struct Authority { 37 | pub stake: Stake, 38 | pub address: SocketAddr, 39 | } 40 | 41 | #[derive(Clone, Serialize, Deserialize)] 42 | pub struct Committee { 43 | pub authorities: HashMap, 44 | pub epoch: EpochNumber, 45 | } 46 | 47 | impl Committee { 48 | pub fn new(info: Vec<(PublicKey, Stake, SocketAddr)>, epoch: EpochNumber) -> Self { 49 | Self { 50 | authorities: info 51 | .into_iter() 52 | .map(|(name, stake, address)| { 53 | let authority = Authority { stake, address }; 54 | (name, authority) 55 | }) 56 | .collect(), 57 | epoch, 58 | } 59 | } 60 | 61 | pub fn size(&self) -> usize { 62 | self.authorities.len() 63 | } 64 | 65 | pub fn stake(&self, name: &PublicKey) -> Stake { 66 | self.authorities.get(name).map_or_else(|| 0, |x| x.stake) 67 | } 68 | 69 | pub fn quorum_threshold(&self) -> Stake { 70 | // If N = 3f + 1 + k (0 <= k < 3) 71 | // then (2 N + 3) / 3 = 2f + 1 + (2k + 2)/3 = 2f + 1 + k = N - f 72 | let total_votes: Stake = self.authorities.values().map(|x| x.stake).sum(); 73 | 2 * total_votes / 3 + 1 74 | } 75 | 76 | pub fn address(&self, name: &PublicKey) -> Option { 77 | self.authorities.get(name).map(|x| x.address) 78 | } 79 | 80 | pub fn broadcast_addresses(&self, myself: &PublicKey) -> Vec<(PublicKey, SocketAddr)> { 81 | self.authorities 82 | .iter() 83 | .filter(|(name, _)| name != &myself) 84 | .map(|(name, x)| (*name, x.address)) 85 | .collect() 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /hotstuff/consensus/src/error.rs: -------------------------------------------------------------------------------- 1 | use crate::consensus::Round; 2 | use crypto::{CryptoError, Digest, PublicKey}; 3 | use store::StoreError; 4 | use thiserror::Error; 5 | use crate::messages::{Block}; 6 | 7 | #[macro_export] 8 | macro_rules! bail { 9 | ($e:expr) => { 10 | return Err($e); 11 | }; 12 | } 13 | 14 | #[macro_export(local_inner_macros)] 15 | macro_rules! ensure { 16 | ($cond:expr, $e:expr) => { 17 | if !($cond) { 18 | bail!($e); 19 | } 20 | }; 21 | } 22 | 23 | pub type ConsensusResult = Result; 24 | 25 | #[derive(Error, Debug)] 26 | pub enum ConsensusError { 27 | #[error("Network error: {0}")] 28 | NetworkError(#[from] std::io::Error), 29 | 30 | #[error("Serialization error: {0}")] 31 | SerializationError(#[from] Box), 32 | 33 | #[error("Store error: {0}")] 34 | StoreError(#[from] StoreError), 35 | 36 | #[error("Node {0} is not in the committee")] 37 | NotInCommittee(PublicKey), 38 | 39 | #[error("Invalid signature")] 40 | InvalidSignature(#[from] CryptoError), 41 | 42 | #[error("[{digest}, {t}] Received more than one vote from {author} at round {round}")] 43 | AuthorityReuse{ 44 | digest: Digest, 45 | author: PublicKey, 46 | round: Round, 47 | t: String, 48 | }, 49 | 50 | #[error("Received vote from unknown authority {0}")] 51 | UnknownAuthority(PublicKey), 52 | 53 | #[error("Received QC without a quorum")] 54 | QCRequiresQuorum, 55 | 56 | #[error("Received TC without a quorum")] 57 | TCRequiresQuorum, 58 | 59 | #[error("Malformed block {0}")] 60 | MalformedBlock(Digest), 61 | 62 | #[error("Received block {digest} from leader {leader} at round {round}")] 63 | WrongLeader { 64 | digest: Digest, 65 | leader: PublicKey, 66 | round: Round, 67 | }, 68 | 69 | #[error("Invalid payload")] 70 | InvalidPayload, 71 | 72 | #[error("Failed to retrieve parent {wait_on} for block {deliver}")] 73 | StoreReadTimeout { 74 | wait_on: Digest, 75 | deliver: Block, 76 | }, 77 | } 78 | -------------------------------------------------------------------------------- /hotstuff/consensus/src/helper.rs: -------------------------------------------------------------------------------- 1 | use crate::config::Committee; 2 | use crate::consensus::ConsensusMessage; 3 | use bytes::Bytes; 4 | use crypto::{Digest, PublicKey}; 5 | use log::{info, warn, debug}; 6 | use network::{SimpleSender, DvfMessage, VERSION}; 7 | use store::Store; 8 | use tokio::sync::mpsc::Receiver; 9 | 10 | #[cfg(test)] 11 | #[path = "tests/helper_tests.rs"] 12 | pub mod helper_tests; 13 | 14 | /// A task dedicated to help other authorities by replying to their sync requests. 15 | pub struct Helper { 16 | /// The committee information. 17 | committee: Committee, 18 | /// The persistent storage. 19 | store: Store, 20 | /// Input channel to receive sync requests. 21 | rx_requests: Receiver<(Digest, PublicKey)>, 22 | /// A network sender to reply to the sync requests. 23 | network: SimpleSender, 24 | validator_id: u64, 25 | exit: exit_future::Exit 26 | } 27 | 28 | impl Helper { 29 | pub fn spawn(committee: Committee, store: Store, rx_requests: Receiver<(Digest, PublicKey)>, validator_id: u64, exit: exit_future::Exit) { 30 | tokio::spawn(async move { 31 | Self { 32 | committee, 33 | store, 34 | rx_requests, 35 | network: SimpleSender::new(), 36 | validator_id, 37 | exit 38 | } 39 | .run() 40 | .await; 41 | }); 42 | } 43 | 44 | async fn run(&mut self) { 45 | loop { 46 | let exit = self.exit.clone(); 47 | tokio::select! { 48 | Some((digest, origin)) = self.rx_requests.recv() => { 49 | // TODO [issue #58]: Do some accounting to prevent bad nodes from monopolizing our resources. 50 | 51 | // get the requestors address. 52 | let address = match self.committee.address(&origin) { 53 | Some(x) => x, 54 | None => { 55 | warn!("Received sync request from unknown authority: {}", origin); 56 | continue; 57 | } 58 | }; 59 | debug!("[VA {}] Received sync request {}", self.validator_id, digest); 60 | // Reply to the request (if we can). 61 | if let Some(bytes) = self 62 | .store 63 | .read(digest.to_vec()) 64 | .await 65 | .expect("Failed to read from storage") 66 | { 67 | debug!("[VA {}] Found {}", self.validator_id, digest); 68 | let block = 69 | bincode::deserialize(&bytes).expect("Failed to deserialize our own block"); 70 | let message = bincode::serialize(&ConsensusMessage::Propose(block)) 71 | .expect("Failed to serialize block"); 72 | let dvf_message = DvfMessage { version: VERSION, validator_id: self.validator_id, message: message}; 73 | let serialized_msg = bincode::serialize(&dvf_message).unwrap(); 74 | debug!("[HELPER] Sending to {:?}", address); 75 | self.network.send(address, Bytes::from(serialized_msg)).await; 76 | } 77 | }, 78 | () = exit => { 79 | break; 80 | } 81 | } 82 | } 83 | info!("[VA {}] Shut down consensus helper", self.validator_id); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /hotstuff/consensus/src/leader.rs: -------------------------------------------------------------------------------- 1 | use crate::config::Committee; 2 | use crate::consensus::Round; 3 | use crypto::PublicKey; 4 | 5 | pub type LeaderElector = RRLeaderElector; 6 | 7 | pub struct RRLeaderElector { 8 | committee: Committee, 9 | } 10 | 11 | impl RRLeaderElector { 12 | pub fn new(committee: Committee) -> Self { 13 | Self { committee } 14 | } 15 | 16 | pub fn get_leader(&self, round: Round) -> PublicKey { 17 | let mut keys: Vec<_> = self.committee.authorities.keys().cloned().collect(); 18 | keys.sort(); 19 | keys[round as usize % self.committee.size()] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /hotstuff/consensus/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod error; 3 | mod aggregator; 4 | mod config; 5 | mod consensus; 6 | mod core; 7 | mod helper; 8 | mod leader; 9 | mod mempool; 10 | mod messages; 11 | mod proposer; 12 | mod synchronizer; 13 | mod timer; 14 | 15 | #[cfg(test)] 16 | #[path = "tests/common.rs"] 17 | mod common; 18 | 19 | pub use crate::config::{Committee, Parameters}; 20 | pub use crate::consensus::{Consensus, ConsensusReceiverHandler}; 21 | pub use crate::messages::{Block, QC, TC}; 22 | -------------------------------------------------------------------------------- /hotstuff/consensus/src/tests/aggregator_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::common::{committee, keys, qc, vote}; 3 | 4 | #[test] 5 | fn add_vote() { 6 | let mut aggregator = Aggregator::new(committee()); 7 | let result = aggregator.add_vote(vote()); 8 | assert!(result.is_ok()); 9 | assert!(result.unwrap().is_none()); 10 | } 11 | 12 | #[test] 13 | fn make_qc() { 14 | let mut aggregator = Aggregator::new(committee()); 15 | let mut keys = keys(); 16 | let qc = qc(); 17 | let hash = qc.digest(); 18 | let round = qc.round; 19 | 20 | // Add 2f+1 votes to the aggregator and ensure it returns the cryptographic 21 | // material to make a valid QC. 22 | let (public_key, secret_key) = keys.pop().unwrap(); 23 | let vote = Vote::new_from_key(hash.clone(), round, public_key, &secret_key); 24 | let result = aggregator.add_vote(vote); 25 | assert!(result.is_ok()); 26 | assert!(result.unwrap().is_none()); 27 | 28 | let (public_key, secret_key) = keys.pop().unwrap(); 29 | let vote = Vote::new_from_key(hash.clone(), round, public_key, &secret_key); 30 | let result = aggregator.add_vote(vote); 31 | assert!(result.is_ok()); 32 | assert!(result.unwrap().is_none()); 33 | 34 | let (public_key, secret_key) = keys.pop().unwrap(); 35 | let vote = Vote::new_from_key(hash.clone(), round, public_key, &secret_key); 36 | match aggregator.add_vote(vote) { 37 | Ok(Some(qc)) => assert!(qc.verify(&committee()).is_ok()), 38 | _ => assert!(false), 39 | } 40 | } 41 | 42 | #[test] 43 | fn cleanup() { 44 | let mut aggregator = Aggregator::new(committee()); 45 | 46 | // Add a vote and ensure it is in the aggregator memory. 47 | let result = aggregator.add_vote(vote()); 48 | assert!(result.is_ok()); 49 | assert_eq!(aggregator.votes_aggregators.len(), 1); 50 | assert!(aggregator.timeouts_aggregators.is_empty()); 51 | 52 | // Clean up the aggregator. 53 | aggregator.cleanup(&2); 54 | assert!(aggregator.votes_aggregators.is_empty()); 55 | assert!(aggregator.timeouts_aggregators.is_empty()); 56 | } 57 | -------------------------------------------------------------------------------- /hotstuff/consensus/src/tests/consensus_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::common::{committee_with_base_port, keys}; 3 | use crate::config::Parameters; 4 | use crypto::SecretKey; 5 | use futures::future::try_join_all; 6 | use std::fs; 7 | use tokio::sync::mpsc::channel; 8 | use tokio::task::JoinHandle; 9 | 10 | fn spawn_nodes( 11 | keys: Vec<(PublicKey, SecretKey)>, 12 | committee: Committee, 13 | store_path: &str, 14 | ) -> Vec> { 15 | keys.into_iter() 16 | .enumerate() 17 | .map(|(i, (name, secret))| { 18 | let committee = committee.clone(); 19 | let parameters = Parameters { 20 | timeout_delay: 100, 21 | ..Parameters::default() 22 | }; 23 | let store_path = format!("{}_{}", store_path, i); 24 | let _ = fs::remove_dir_all(&store_path); 25 | let store = Store::new(&store_path).unwrap(); 26 | let signature_service = SignatureService::new(secret); 27 | let (tx_consensus_to_mempool, mut rx_consensus_to_mempool) = channel(10); 28 | let (_tx_mempool_to_consensus, rx_mempool_to_consensus) = channel(1); 29 | let (tx_commit, mut rx_commit) = channel(1); 30 | 31 | // Sink the mempool channel. 32 | tokio::spawn(async move { 33 | loop { 34 | rx_consensus_to_mempool.recv().await; 35 | } 36 | }); 37 | 38 | // Spawn the consensus engine. 39 | tokio::spawn(async move { 40 | Consensus::spawn( 41 | name, 42 | committee, 43 | parameters, 44 | signature_service, 45 | store, 46 | rx_mempool_to_consensus, 47 | tx_consensus_to_mempool, 48 | tx_commit, 49 | ); 50 | 51 | rx_commit.recv().await.unwrap() 52 | }) 53 | }) 54 | .collect() 55 | } 56 | 57 | #[tokio::test] 58 | async fn end_to_end() { 59 | let committee = committee_with_base_port(15_000); 60 | 61 | // Run all nodes. 62 | let store_path = ".db_test_end_to_end"; 63 | let handles = spawn_nodes(keys(), committee, store_path); 64 | 65 | // Ensure all threads terminated correctly. 66 | let blocks = try_join_all(handles).await.unwrap(); 67 | assert!(blocks.windows(2).all(|w| w[0] == w[1])); 68 | } 69 | -------------------------------------------------------------------------------- /hotstuff/consensus/src/tests/helper_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::common::{block, committee_with_base_port, keys, listener}; 3 | use crypto::Hash as _; 4 | use std::fs; 5 | use tokio::sync::mpsc::channel; 6 | 7 | #[tokio::test] 8 | async fn sync_reply() { 9 | let (tx_request, rx_request) = channel(1); 10 | let (requestor, _) = keys().pop().unwrap(); 11 | let committee = committee_with_base_port(13_000); 12 | 13 | // Create a new test store. 14 | let path = ".db_test_sync_reply"; 15 | let _ = fs::remove_dir_all(path); 16 | let mut store = Store::new(path).unwrap(); 17 | 18 | // Add a batch to the store. 19 | let digest = block().digest(); 20 | let serialized = bincode::serialize(&block()).unwrap(); 21 | store.write(digest.to_vec(), serialized.clone()).await; 22 | 23 | // Spawn an `Helper` instance. 24 | Helper::spawn(committee.clone(), store, rx_request); 25 | 26 | // Spawn a listener to receive the sync reply. 27 | let address = committee.address(&requestor).unwrap(); 28 | let message = ConsensusMessage::Propose(block()); 29 | let expected = Bytes::from(bincode::serialize(&message).unwrap()); 30 | let handle = listener(address, Some(expected)); 31 | 32 | // Send a sync request. 33 | tx_request.send((digest, requestor)).await.unwrap(); 34 | 35 | // Ensure the requestor received the batch (ie. it did not panic). 36 | assert!(handle.await.is_ok()); 37 | } 38 | -------------------------------------------------------------------------------- /hotstuff/consensus/src/tests/messages_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::common::{committee, qc}; 3 | use crypto::generate_keypair; 4 | use rand::rngs::StdRng; 5 | use rand::SeedableRng as _; 6 | 7 | #[test] 8 | fn verify_valid_qc() { 9 | assert!(qc().verify(&committee()).is_ok()); 10 | } 11 | 12 | #[test] 13 | fn verify_qc_authority_reuse() { 14 | // Modify QC to reuse one authority. 15 | let mut qc = qc(); 16 | let _ = qc.votes.pop(); 17 | let vote = qc.votes[0].clone(); 18 | qc.votes.push(vote.clone()); 19 | 20 | // Verify the QC. 21 | match qc.verify(&committee()) { 22 | Err(ConsensusError::AuthorityReuse(name)) => assert_eq!(name, vote.0), 23 | _ => assert!(false), 24 | } 25 | } 26 | 27 | #[test] 28 | fn verify_qc_unknown_authority() { 29 | let mut qc = qc(); 30 | 31 | // Modify QC to add one unknown authority. 32 | let mut rng = StdRng::from_seed([1; 32]); 33 | let (unknown, _) = generate_keypair(&mut rng); 34 | let (_, sig) = qc.votes.pop().unwrap(); 35 | qc.votes.push((unknown, sig)); 36 | 37 | // Verify the QC. 38 | match qc.verify(&committee()) { 39 | Err(ConsensusError::UnknownAuthority(name)) => assert_eq!(name, unknown), 40 | _ => assert!(false), 41 | } 42 | } 43 | 44 | #[test] 45 | fn verify_qc_insufficient_stake() { 46 | // Modify QC to remove one authority. 47 | let mut qc = qc(); 48 | let _ = qc.votes.pop(); 49 | 50 | // Verify the QC. 51 | match qc.verify(&committee()) { 52 | Err(ConsensusError::QCRequiresQuorum) => assert!(true), 53 | _ => assert!(false), 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /hotstuff/consensus/src/tests/timer_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | #[tokio::test] 4 | async fn schedule() { 5 | let timer = Timer::new(100); 6 | let now = Instant::now(); 7 | timer.await; 8 | assert!(now.elapsed().as_millis() > 95); 9 | } 10 | -------------------------------------------------------------------------------- /hotstuff/consensus/src/timer.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | use std::pin::Pin; 3 | use std::task::{Context, Poll}; 4 | use tokio::time::{sleep, Duration, Instant, Sleep}; 5 | 6 | #[cfg(test)] 7 | #[path = "tests/timer_tests.rs"] 8 | pub mod timer_tests; 9 | 10 | pub struct Timer { 11 | duration: u64, 12 | sleep: Pin>, 13 | } 14 | 15 | impl Timer { 16 | pub fn new(duration: u64) -> Self { 17 | let sleep = Box::pin(sleep(Duration::from_millis(duration))); 18 | Self { duration, sleep } 19 | } 20 | 21 | pub fn reset(&mut self) { 22 | self.sleep 23 | .as_mut() 24 | .reset(Instant::now() + Duration::from_millis(self.duration)); 25 | } 26 | } 27 | 28 | impl Future for Timer { 29 | type Output = (); 30 | 31 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { 32 | self.sleep.as_mut().poll(cx) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /hotstuff/crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "crypto" 3 | version = "0.1.0" 4 | authors = ["Alberto Sonnino "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | tokio = { version = "1.5.0", features = ["sync", "rt", "macros"] } 10 | ed25519-dalek = { version = "2.1.1", features = ["batch"] } 11 | secp256k1 = { version = "0.24.0", features = ["global-context", "rand-std", "bitcoin_hashes", "std"] } 12 | serde = { version = "1.0", features = ["derive"] } 13 | base64 = "0.13.0" 14 | zeroize = { version = "1.4.2", features = ["zeroize_derive"] } -------------------------------------------------------------------------------- /hotstuff/mempool/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mempool" 3 | version = "0.1.0" 4 | authors = ["Alberto Sonnino "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | tokio = { version = "1.5.0", features = ["sync", "rt", "macros"] } 9 | ed25519-dalek = { version = "2.1.1", features = ["digest"] } 10 | serde = { version = "1.0", features = ["derive"] } 11 | bytes = "1.0.1" 12 | log = "0.4.14" 13 | bincode = "1.3.3" 14 | futures = "0.3.14" 15 | async-trait = "0.1.50" 16 | exit-future = "0.2.0" 17 | crypto = { path = "../crypto" } 18 | store = { path = "../store" } 19 | network = { path = "../network" } 20 | utils = { path = "../utils" } 21 | 22 | [dev-dependencies] 23 | tokio-util = { version = "0.6.2", features= ["codec"] } 24 | rand = "0.7.3" 25 | 26 | [features] 27 | benchmark = [] 28 | -------------------------------------------------------------------------------- /hotstuff/mempool/src/helper.rs: -------------------------------------------------------------------------------- 1 | use crate::config::Committee; 2 | use bytes::Bytes; 3 | use crypto::{Digest, PublicKey}; 4 | use log::{info, error, warn, debug}; 5 | use network::{SimpleSender, DvfMessage, VERSION}; 6 | use store::Store; 7 | use tokio::sync::mpsc::Receiver; 8 | 9 | #[cfg(test)] 10 | #[path = "tests/helper_tests.rs"] 11 | pub mod helper_tests; 12 | 13 | /// A task dedicated to help other authorities by replying to their batch requests. 14 | pub struct Helper { 15 | /// The committee information. 16 | committee: Committee, 17 | /// The persistent storage. 18 | store: Store, 19 | /// Input channel to receive batch requests. 20 | rx_request: Receiver<(Vec, PublicKey)>, 21 | /// A network sender to send the batches to the other mempools. 22 | network: SimpleSender, 23 | validator_id: u64, 24 | exit: exit_future::Exit 25 | } 26 | 27 | impl Helper { 28 | pub fn spawn( 29 | committee: Committee, 30 | store: Store, 31 | rx_request: Receiver<(Vec, PublicKey)>, 32 | validator_id: u64, 33 | exit: exit_future::Exit 34 | ) { 35 | tokio::spawn(async move { 36 | Self { 37 | committee, 38 | store, 39 | rx_request, 40 | network: SimpleSender::new(), 41 | validator_id: validator_id, 42 | exit: exit 43 | } 44 | .run() 45 | .await; 46 | }); 47 | } 48 | 49 | async fn run(&mut self) { 50 | loop { 51 | let exit = self.exit.clone(); 52 | tokio::select! { 53 | Some((digests, origin)) = self.rx_request.recv() => { 54 | // TODO [issue #7]: Do some accounting to prevent bad nodes from monopolizing our resources. 55 | 56 | // get the requestors address. 57 | let address = match self.committee.mempool_address(&origin) { 58 | Some(x) => x, 59 | None => { 60 | warn!("Received batch request from unknown authority: {}", origin); 61 | continue; 62 | } 63 | }; 64 | 65 | // Reply to the request (the best we can). 66 | for digest in digests { 67 | match self.store.read(digest.to_vec()).await { 68 | Ok(Some(data)) => { 69 | let dvf_message = DvfMessage { version: VERSION, validator_id: self.validator_id, message: data}; 70 | let serialized_msg = bincode::serialize(&dvf_message).unwrap(); 71 | debug!("[MemHELPER] Sending to {:?}", address); 72 | self.network.feed(address, Bytes::from(serialized_msg)).await 73 | }, 74 | Ok(None) => (), 75 | Err(e) => error!("{:?}", e), 76 | } 77 | } 78 | self.network.flush(address).await; 79 | }, 80 | () = exit => { 81 | break; 82 | } 83 | } 84 | 85 | } 86 | info!("[VA {}] Shut down mempool helper", self.validator_id); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /hotstuff/mempool/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod batch_maker; 2 | mod config; 3 | mod helper; 4 | mod mempool; 5 | mod processor; 6 | mod quorum_waiter; 7 | mod synchronizer; 8 | 9 | #[cfg(test)] 10 | #[path = "tests/common.rs"] 11 | mod common; 12 | 13 | pub use crate::config::{Committee, Parameters}; 14 | pub use crate::mempool::{ConsensusMempoolMessage, Mempool, MempoolMessage, TxReceiverHandler, MempoolReceiverHandler}; 15 | pub use crate::batch_maker::{Batch, Transaction}; 16 | -------------------------------------------------------------------------------- /hotstuff/mempool/src/processor.rs: -------------------------------------------------------------------------------- 1 | use crypto::Digest; 2 | use ed25519_dalek::Digest as _; 3 | use ed25519_dalek::Sha512; 4 | use std::convert::TryInto; 5 | use store::Store; 6 | use tokio::sync::mpsc::{Receiver}; 7 | use utils::monitored_channel::MonitoredSender; 8 | use log::{info}; 9 | 10 | #[cfg(test)] 11 | #[path = "tests/processor_tests.rs"] 12 | pub mod processor_tests; 13 | 14 | /// Indicates a serialized `MempoolMessage::Batch` message. 15 | pub type SerializedBatchMessage = Vec; 16 | 17 | /// Hashes and stores batches, it then outputs the batch's digest. 18 | pub struct Processor; 19 | 20 | impl Processor { 21 | pub fn spawn( 22 | // The persistent storage. 23 | store: Store, 24 | // Input channel to receive batches. 25 | mut rx_batch: Receiver, 26 | // Output channel to send out batches' digests. 27 | tx_digest: MonitoredSender, 28 | exit: exit_future::Exit 29 | ) { 30 | tokio::spawn(async move { 31 | loop { 32 | let exit = exit.clone(); 33 | tokio::select! { 34 | Some(batch) = rx_batch.recv() => { 35 | let digest = Digest(Sha512::digest(&batch).as_slice()[..32].try_into().unwrap()); 36 | 37 | // Store the batch. 38 | store.write(digest.to_vec(), batch).await; 39 | 40 | tx_digest.send(digest).await.expect("Failed to send digest"); 41 | }, 42 | () = exit => { 43 | break; 44 | } 45 | } 46 | } 47 | info!("Shutting down mempool processor"); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /hotstuff/mempool/src/tests/batch_maker_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::common::transaction; 3 | use tokio::sync::mpsc::channel; 4 | 5 | #[tokio::test] 6 | async fn make_batch() { 7 | let (tx_transaction, rx_transaction) = channel(1); 8 | let (tx_message, mut rx_message) = channel(1); 9 | let dummy_addresses = vec![(PublicKey::default(), "127.0.0.1:0".parse().unwrap())]; 10 | 11 | // Spawn a `BatchMaker` instance. 12 | BatchMaker::spawn( 13 | /* max_batch_size */ 200, 14 | /* max_batch_delay */ 1_000_000, // Ensure the timer is not triggered. 15 | rx_transaction, 16 | tx_message, 17 | /* mempool_addresses */ dummy_addresses, 18 | ); 19 | 20 | // Send enough transactions to seal a batch. 21 | tx_transaction.send(transaction()).await.unwrap(); 22 | tx_transaction.send(transaction()).await.unwrap(); 23 | 24 | // Ensure the batch is as expected. 25 | let expected_batch = vec![transaction(), transaction()]; 26 | let QuorumWaiterMessage { batch, handlers: _ } = rx_message.recv().await.unwrap(); 27 | match bincode::deserialize(&batch).unwrap() { 28 | MempoolMessage::Batch(batch) => assert_eq!(batch, expected_batch), 29 | _ => panic!("Unexpected message"), 30 | } 31 | } 32 | 33 | #[tokio::test] 34 | async fn batch_timeout() { 35 | let (tx_transaction, rx_transaction) = channel(1); 36 | let (tx_message, mut rx_message) = channel(1); 37 | let dummy_addresses = vec![(PublicKey::default(), "127.0.0.1:0".parse().unwrap())]; 38 | 39 | // Spawn a `BatchMaker` instance. 40 | BatchMaker::spawn( 41 | /* max_batch_size */ 200, 42 | /* max_batch_delay */ 50, // Ensure the timer is triggered. 43 | rx_transaction, 44 | tx_message, 45 | /* mempool_addresses */ dummy_addresses, 46 | ); 47 | 48 | // Do not send enough transactions to seal a batch.. 49 | tx_transaction.send(transaction()).await.unwrap(); 50 | 51 | // Ensure the batch is as expected. 52 | let expected_batch = vec![transaction()]; 53 | let QuorumWaiterMessage { batch, handlers: _ } = rx_message.recv().await.unwrap(); 54 | match bincode::deserialize(&batch).unwrap() { 55 | MempoolMessage::Batch(batch) => assert_eq!(batch, expected_batch), 56 | _ => panic!("Unexpected message"), 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /hotstuff/mempool/src/tests/common.rs: -------------------------------------------------------------------------------- 1 | use crate::batch_maker::{Batch, Transaction}; 2 | use crate::config::Committee; 3 | use crate::mempool::MempoolMessage; 4 | use bytes::Bytes; 5 | use crypto::{generate_keypair, Digest, PublicKey, SecretKey}; 6 | use ed25519_dalek::Digest as _; 7 | use ed25519_dalek::Sha512; 8 | use futures::sink::SinkExt as _; 9 | use futures::stream::StreamExt as _; 10 | use rand::rngs::StdRng; 11 | use rand::SeedableRng as _; 12 | use std::convert::TryInto as _; 13 | use std::net::SocketAddr; 14 | use tokio::net::TcpListener; 15 | use tokio::task::JoinHandle; 16 | use tokio_util::codec::{Framed, LengthDelimitedCodec}; 17 | 18 | // Fixture 19 | pub fn keys() -> Vec<(PublicKey, SecretKey)> { 20 | let mut rng = StdRng::from_seed([0; 32]); 21 | (0..4).map(|_| generate_keypair(&mut rng)).collect() 22 | } 23 | 24 | // Fixture 25 | pub fn committee() -> Committee { 26 | Committee::new( 27 | keys() 28 | .into_iter() 29 | .enumerate() 30 | .map(|(i, (name, _))| { 31 | let stake = 1; 32 | let front = format!("127.0.0.1:{}", 100 + i).parse().unwrap(); 33 | let mempool = format!("127.0.0.1:{}", 100 + i).parse().unwrap(); 34 | (name, stake, front, mempool) 35 | }) 36 | .collect(), 37 | /* epoch */ 100, 38 | ) 39 | } 40 | 41 | // Fixture. 42 | pub fn committee_with_base_port(base_port: u16) -> Committee { 43 | let mut committee = committee(); 44 | for authority in committee.authorities.values_mut() { 45 | let port = authority.transactions_address.port(); 46 | authority.transactions_address.set_port(base_port + port); 47 | 48 | let port = authority.mempool_address.port(); 49 | authority.mempool_address.set_port(base_port + port); 50 | } 51 | committee 52 | } 53 | 54 | // Fixture 55 | pub fn transaction() -> Transaction { 56 | vec![0; 100] 57 | } 58 | 59 | // Fixture 60 | pub fn batch() -> Batch { 61 | vec![transaction(), transaction()] 62 | } 63 | 64 | // Fixture 65 | pub fn serialized_batch() -> Vec { 66 | let message = MempoolMessage::Batch(batch()); 67 | bincode::serialize(&message).unwrap() 68 | } 69 | 70 | // Fixture 71 | pub fn batch_digest() -> Digest { 72 | Digest( 73 | Sha512::digest(&serialized_batch()).as_slice()[..32] 74 | .try_into() 75 | .unwrap(), 76 | ) 77 | } 78 | 79 | // Fixture 80 | pub fn listener(address: SocketAddr, expected: Option) -> JoinHandle<()> { 81 | tokio::spawn(async move { 82 | let listener = TcpListener::bind(&address).await.unwrap(); 83 | let (socket, _) = listener.accept().await.unwrap(); 84 | let transport = Framed::new(socket, LengthDelimitedCodec::new()); 85 | let (mut writer, mut reader) = transport.split(); 86 | match reader.next().await { 87 | Some(Ok(received)) => { 88 | writer.send(Bytes::from("Ack")).await.unwrap(); 89 | if let Some(expected) = expected { 90 | assert_eq!(received.freeze(), expected); 91 | } 92 | } 93 | _ => panic!("Failed to receive network message"), 94 | } 95 | }) 96 | } 97 | -------------------------------------------------------------------------------- /hotstuff/mempool/src/tests/helper_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::common::{batch_digest, committee_with_base_port, keys, listener, serialized_batch}; 3 | use std::fs; 4 | use tokio::sync::mpsc::channel; 5 | 6 | #[tokio::test] 7 | async fn batch_reply() { 8 | let (tx_request, rx_request) = channel(1); 9 | let (requestor, _) = keys().pop().unwrap(); 10 | let committee = committee_with_base_port(8_000); 11 | 12 | // Create a new test store. 13 | let path = ".db_test_batch_reply"; 14 | let _ = fs::remove_dir_all(path); 15 | let mut store = Store::new(path).unwrap(); 16 | 17 | // Add a batch to the store. 18 | store 19 | .write(batch_digest().to_vec(), serialized_batch()) 20 | .await; 21 | 22 | // Spawn an `Helper` instance. 23 | Helper::spawn(committee.clone(), store, rx_request); 24 | 25 | // Spawn a listener to receive the batch reply. 26 | let address = committee.mempool_address(&requestor).unwrap(); 27 | let expected = Bytes::from(serialized_batch()); 28 | let handle = listener(address, Some(expected)); 29 | 30 | // Send a batch request. 31 | let digests = vec![batch_digest()]; 32 | tx_request.send((digests, requestor)).await.unwrap(); 33 | 34 | // Ensure the requestor received the batch (ie. it did not panic). 35 | assert!(handle.await.is_ok()); 36 | } 37 | -------------------------------------------------------------------------------- /hotstuff/mempool/src/tests/mempool_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::common::{batch_digest, committee_with_base_port, keys, listener, transaction}; 3 | use network::SimpleSender; 4 | use std::fs; 5 | 6 | #[tokio::test] 7 | async fn handle_clients_transactions() { 8 | let (name, _) = keys().pop().unwrap(); 9 | let committee = committee_with_base_port(11_000); 10 | let parameters = Parameters { 11 | batch_size: 200, // Two transactions. 12 | ..Parameters::default() 13 | }; 14 | 15 | // Create a new test store. 16 | let path = ".db_test_handle_clients_transactions"; 17 | let _ = fs::remove_dir_all(path); 18 | let store = Store::new(path).unwrap(); 19 | 20 | // Spawn a `Mempool` instance. 21 | let (_tx_consensus_to_mempool, rx_consensus_to_mempool) = channel(1); 22 | let (tx_mempool_to_consensus, mut rx_mempool_to_consensus) = channel(1); 23 | Mempool::spawn( 24 | name, 25 | committee.clone(), 26 | parameters, 27 | store, 28 | rx_consensus_to_mempool, 29 | tx_mempool_to_consensus, 30 | ); 31 | 32 | // Spawn enough mempools' listeners to acknowledge our batches. 33 | for (_, address) in committee.broadcast_addresses(&name) { 34 | let _ = listener(address, /* expected */ None); 35 | } 36 | 37 | // Send enough transactions to create a batch. 38 | let mut network = SimpleSender::new(); 39 | let address = committee.transactions_address(&name).unwrap(); 40 | network.send(address, Bytes::from(transaction())).await; 41 | network.send(address, Bytes::from(transaction())).await; 42 | 43 | // Ensure the consensus got the batch digest. 44 | let received = rx_mempool_to_consensus.recv().await.unwrap(); 45 | assert_eq!(batch_digest(), received); 46 | } 47 | -------------------------------------------------------------------------------- /hotstuff/mempool/src/tests/processor_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::common::batch; 3 | use crate::mempool::MempoolMessage; 4 | use std::fs; 5 | use tokio::sync::mpsc::channel; 6 | 7 | #[tokio::test] 8 | async fn hash_and_store() { 9 | let (tx_batch, rx_batch) = channel(1); 10 | let (tx_digest, mut rx_digest) = channel(1); 11 | 12 | // Create a new test store. 13 | let path = ".db_test_hash_and_store"; 14 | let _ = fs::remove_dir_all(path); 15 | let mut store = Store::new(path).unwrap(); 16 | 17 | // Spawn a new `Processor` instance. 18 | Processor::spawn(store.clone(), rx_batch, tx_digest); 19 | 20 | // Send a batch to the `Processor`. 21 | let message = MempoolMessage::Batch(batch()); 22 | let serialized = bincode::serialize(&message).unwrap(); 23 | tx_batch.send(serialized.clone()).await.unwrap(); 24 | 25 | // Ensure the `Processor` outputs the batch's digest. 26 | let digest = Digest( 27 | Sha512::digest(&serialized).as_slice()[..32] 28 | .try_into() 29 | .unwrap(), 30 | ); 31 | let received = rx_digest.recv().await.unwrap(); 32 | assert_eq!(digest.clone(), received); 33 | 34 | // Ensure the `Processor` correctly stored the batch. 35 | let stored_batch = store.read(digest.to_vec()).await.unwrap(); 36 | assert!(stored_batch.is_some(), "The batch is not in the store"); 37 | assert_eq!(stored_batch.unwrap(), serialized); 38 | } 39 | -------------------------------------------------------------------------------- /hotstuff/mempool/src/tests/quorum_waiter_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::common::{batch, committee_with_base_port, keys, listener}; 3 | use crate::mempool::MempoolMessage; 4 | use bytes::Bytes; 5 | use futures::future::try_join_all; 6 | use network::ReliableSender; 7 | use tokio::sync::mpsc::channel; 8 | 9 | #[tokio::test] 10 | async fn wait_for_quorum() { 11 | let (tx_message, rx_message) = channel(1); 12 | let (tx_batch, mut rx_batch) = channel(1); 13 | let (myself, _) = keys().pop().unwrap(); 14 | let committee = committee_with_base_port(7_000); 15 | 16 | // Spawn a `QuorumWaiter` instance. 17 | QuorumWaiter::spawn(committee.clone(), /* stake */ 1, rx_message, tx_batch); 18 | 19 | // Make a batch. 20 | let message = MempoolMessage::Batch(batch()); 21 | let serialized = bincode::serialize(&message).unwrap(); 22 | let expected = Bytes::from(serialized.clone()); 23 | 24 | // Spawn enough listeners to acknowledge our batches. 25 | let mut names = Vec::new(); 26 | let mut addresses = Vec::new(); 27 | let mut listener_handles = Vec::new(); 28 | for (name, address) in committee.broadcast_addresses(&myself) { 29 | let handle = listener(address, Some(expected.clone())); 30 | names.push(name); 31 | addresses.push(address); 32 | listener_handles.push(handle); 33 | } 34 | 35 | // Broadcast the batch through the network. 36 | let bytes = Bytes::from(serialized.clone()); 37 | let handlers = ReliableSender::new().broadcast(addresses, bytes).await; 38 | 39 | // Forward the batch along with the handlers to the `QuorumWaiter`. 40 | let message = QuorumWaiterMessage { 41 | batch: serialized.clone(), 42 | handlers: names.into_iter().zip(handlers.into_iter()).collect(), 43 | }; 44 | tx_message.send(message).await.unwrap(); 45 | 46 | // Wait for the `QuorumWaiter` to gather enough acknowledgements and output the batch. 47 | let output = rx_batch.recv().await.unwrap(); 48 | assert_eq!(output, serialized); 49 | 50 | // Ensure the other listeners correctly received the batch. 51 | assert!(try_join_all(listener_handles).await.is_ok()); 52 | } 53 | -------------------------------------------------------------------------------- /hotstuff/mempool/src/tests/synchronizer_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::common::{batch_digest, committee_with_base_port, keys, listener}; 3 | use std::fs; 4 | use tokio::sync::mpsc::channel; 5 | 6 | #[tokio::test] 7 | async fn synchronize() { 8 | let (tx_message, rx_message) = channel(1); 9 | 10 | let mut keys = keys(); 11 | let (name, _) = keys.pop().unwrap(); 12 | let committee = committee_with_base_port(9_000); 13 | 14 | // Create a new test store. 15 | let path = ".db_test_synchronize"; 16 | let _ = fs::remove_dir_all(path); 17 | let store = Store::new(path).unwrap(); 18 | 19 | // Spawn a `Synchronizer` instance. 20 | Synchronizer::spawn( 21 | name, 22 | committee.clone(), 23 | store.clone(), 24 | /* gc_depth */ 50, // Not used in this test. 25 | /* sync_retry_delay */ 1_000_000, // Ensure it is not triggered. 26 | /* sync_retry_nodes */ 3, // Not used in this test. 27 | rx_message, 28 | ); 29 | 30 | // Spawn a listener to receive our batch requests. 31 | let (target, _) = keys.pop().unwrap(); 32 | let address = committee.mempool_address(&target).unwrap(); 33 | let missing = vec![batch_digest()]; 34 | let message = MempoolMessage::BatchRequest(missing.clone(), name); 35 | let serialized = bincode::serialize(&message).unwrap(); 36 | let handle = listener(address, Some(Bytes::from(serialized))); 37 | 38 | // Send a sync request. 39 | let message = ConsensusMempoolMessage::Synchronize(missing, target); 40 | tx_message.send(message).await.unwrap(); 41 | 42 | // Ensure the target receives the sync request. 43 | assert!(handle.await.is_ok()); 44 | } 45 | -------------------------------------------------------------------------------- /hotstuff/network/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "network" 3 | version = "0.1.0" 4 | authors = ["Alberto Sonnino "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | tokio = { version = "1.5.0", features = ["rt", "net", "sync", "macros", "time"] } 10 | tokio-util = { version = "0.6.6", features = ["codec"] } 11 | thiserror = "1.0.24" 12 | bytes = "1.0.1" 13 | log = "0.4.14" 14 | futures = "0.3.14" 15 | rand = { version = "0.7.3", features = ["small_rng"] } 16 | async-trait = "0.1.50" 17 | serde = { version = "1.0", features = ["derive"] } 18 | bincode = "1.3.3" 19 | utils = { path = "../utils" } 20 | exit-future = "0.2.0" 21 | 22 | # common 23 | dvf_version = { path = "../../common/dvf_version" } 24 | 25 | [dev-dependencies] 26 | -------------------------------------------------------------------------------- /hotstuff/network/src/dvf_message.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::fmt::Debug; 3 | 4 | pub use dvf_version::VERSION; 5 | 6 | #[derive(Debug, Serialize, Deserialize)] 7 | pub struct DvfMessage { 8 | pub version: u64, 9 | pub validator_id: u64, 10 | pub message: Vec 11 | } 12 | 13 | // #[derive(Debug, Serialize, Deserialize, Clone)] 14 | // pub enum DvfMessage { 15 | // VaMsg {version: u64, va_id: u64, msg: Vec}, 16 | // AckMsg {}, 17 | // } 18 | -------------------------------------------------------------------------------- /hotstuff/network/src/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright(C) Facebook, Inc. and its affiliates. 2 | use std::fmt::Debug; 3 | use std::net::SocketAddr; 4 | use thiserror::Error; 5 | 6 | #[derive(Error, Debug)] 7 | pub enum NetworkError { 8 | #[error("Failed to connect to {0} (retry {1}): {2}")] 9 | FailedToConnect(SocketAddr, u16, std::io::Error), 10 | 11 | #[error("Failed to accept connection: {0}")] 12 | FailedToListen(std::io::Error), 13 | 14 | #[error("Failed to send message to {0}: {1}")] 15 | FailedToSendMessage(SocketAddr, std::io::Error), 16 | 17 | #[error("Failed to receive message from {0}: {1}")] 18 | FailedToReceiveMessage(SocketAddr, std::io::Error), 19 | 20 | #[error("Failed to receive ACK from {0}")] 21 | FailedToReceiveAck(SocketAddr), 22 | 23 | #[error("Receive unexpected ACK from {0}")] 24 | UnexpectedAck(SocketAddr), 25 | 26 | #[error("Tokio sender channel is closed for {0}")] 27 | TokioChannelClosed(SocketAddr), 28 | } 29 | -------------------------------------------------------------------------------- /hotstuff/network/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright(C) Facebook, Inc. and its affiliates. 2 | mod error; 3 | mod receiver; 4 | mod reliable_sender; 5 | mod simple_sender; 6 | mod dvf_message; 7 | #[cfg(test)] 8 | #[path = "tests/common.rs"] 9 | pub mod common; 10 | 11 | pub const CHANNEL_CAPACITY: usize = 1_000; 12 | 13 | pub use crate::receiver::{MessageHandler, Receiver, Writer}; 14 | pub use crate::reliable_sender::{CancelHandler, ReliableSender}; 15 | pub use crate::simple_sender::SimpleSender; 16 | pub use crate::dvf_message::DvfMessage; 17 | pub use crate::dvf_message::VERSION; -------------------------------------------------------------------------------- /hotstuff/network/src/tests/common.rs: -------------------------------------------------------------------------------- 1 | // Copyright(C) Facebook, Inc. and its affiliates. 2 | use bytes::Bytes; 3 | use futures::sink::SinkExt as _; 4 | use futures::stream::StreamExt as _; 5 | use std::net::SocketAddr; 6 | use tokio::net::TcpListener; 7 | use tokio::task::JoinHandle; 8 | use tokio_util::codec::{Framed, LengthDelimitedCodec}; 9 | 10 | pub fn listener(address: SocketAddr, expected: String) -> JoinHandle<()> { 11 | tokio::spawn(async move { 12 | let listener = TcpListener::bind(&address).await.unwrap(); 13 | let (socket, _) = listener.accept().await.unwrap(); 14 | let transport = Framed::new(socket, LengthDelimitedCodec::new()); 15 | let (mut writer, mut reader) = transport.split(); 16 | match reader.next().await { 17 | Some(Ok(received)) => { 18 | assert_eq!(received, expected); 19 | writer.send(Bytes::from("Ack")).await.unwrap() 20 | } 21 | _ => panic!("Failed to receive network message"), 22 | } 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /hotstuff/network/src/tests/receiver_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright(C) Facebook, Inc. and its affiliates. 2 | use super::*; 3 | use futures::sink::SinkExt as _; 4 | use tokio::sync::mpsc::channel; 5 | use tokio::sync::mpsc::Sender; 6 | use tokio::time::{sleep, Duration}; 7 | 8 | #[derive(Clone)] 9 | struct TestHandler { 10 | deliver: Sender, 11 | } 12 | 13 | #[async_trait] 14 | impl MessageHandler for TestHandler { 15 | async fn dispatch(&self, writer: &mut Writer, message: Bytes) -> Result<(), Box> { 16 | // Reply with an ACK. 17 | let _ = writer.send(Bytes::from("Ack")).await; 18 | 19 | // Deserialize the message. 20 | let message = bincode::deserialize(&message).unwrap(); 21 | 22 | // Deliver the message to the application. 23 | self.deliver.send(message).await.unwrap(); 24 | Ok(()) 25 | } 26 | } 27 | 28 | #[tokio::test] 29 | async fn receive() { 30 | // Make the network receiver. 31 | let address = "127.0.0.1:4000".parse::().unwrap(); 32 | let (tx, mut rx) = channel(1); 33 | Receiver::spawn(address, TestHandler { deliver: tx }); 34 | sleep(Duration::from_millis(50)).await; 35 | 36 | // Send a message. 37 | let sent = "Hello, world!"; 38 | let bytes = Bytes::from(bincode::serialize(sent).unwrap()); 39 | let stream = TcpStream::connect(address).await.unwrap(); 40 | let mut transport = Framed::new(stream, LengthDelimitedCodec::new()); 41 | transport.send(bytes.clone()).await.unwrap(); 42 | 43 | // Ensure the message gets passed to the channel. 44 | let message = rx.recv().await; 45 | assert!(message.is_some()); 46 | let received = message.unwrap(); 47 | assert_eq!(received, sent); 48 | } 49 | -------------------------------------------------------------------------------- /hotstuff/network/src/tests/reliable_sender_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright(C) Facebook, Inc. and its affiliates. 2 | use super::*; 3 | use crate::common::listener; 4 | use futures::future::try_join_all; 5 | 6 | #[tokio::test] 7 | async fn send() { 8 | // Run a TCP server. 9 | let address = "127.0.0.1:5000".parse::().unwrap(); 10 | let message = "Hello, world!"; 11 | let handle = listener(address, message.to_string()); 12 | 13 | // Make the network sender and send the message. 14 | let mut sender = ReliableSender::new(); 15 | let cancel_handler = sender.send(address, Bytes::from(message)).await; 16 | 17 | // Ensure we get back an acknowledgement. 18 | assert!(cancel_handler.await.is_ok()); 19 | 20 | // Ensure the server received the expected message (ie. it did not panic). 21 | assert!(handle.await.is_ok()); 22 | } 23 | 24 | #[tokio::test] 25 | async fn broadcast() { 26 | // Run 3 TCP servers. 27 | let message = "Hello, world!"; 28 | let (handles, addresses): (Vec<_>, Vec<_>) = (0..3) 29 | .map(|x| { 30 | let address = format!("127.0.0.1:{}", 5_200 + x) 31 | .parse::() 32 | .unwrap(); 33 | (listener(address, message.to_string()), address) 34 | }) 35 | .collect::>() 36 | .into_iter() 37 | .unzip(); 38 | 39 | // Make the network sender and send the message. 40 | let mut sender = ReliableSender::new(); 41 | let cancel_handlers = sender.broadcast(addresses, Bytes::from(message)).await; 42 | 43 | // Ensure we get back an acknowledgement for each message. 44 | assert!(try_join_all(cancel_handlers).await.is_ok()); 45 | 46 | // Ensure all servers received the broadcast. 47 | assert!(try_join_all(handles).await.is_ok()); 48 | } 49 | 50 | #[tokio::test] 51 | async fn retry() { 52 | // Make the network sender and send the message (no listeners are running). 53 | let address = "127.0.0.1:5300".parse::().unwrap(); 54 | let message = "Hello, world!"; 55 | let mut sender = ReliableSender::new(); 56 | let cancel_handler = sender.send(address, Bytes::from(message)).await; 57 | 58 | // Run a TCP server. 59 | sleep(Duration::from_millis(50)).await; 60 | let handle = listener(address, message.to_string()); 61 | 62 | // Ensure we get back an acknowledgement. 63 | assert!(cancel_handler.await.is_ok()); 64 | 65 | // Ensure the server received the message (ie. it did not panic). 66 | assert!(handle.await.is_ok()); 67 | } 68 | -------------------------------------------------------------------------------- /hotstuff/network/src/tests/simple_sender_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright(C) Facebook, Inc. and its affiliates. 2 | use super::*; 3 | use crate::common::listener; 4 | use futures::future::try_join_all; 5 | 6 | #[tokio::test] 7 | async fn simple_send() { 8 | // Run a TCP server. 9 | let address = "127.0.0.1:6100".parse::().unwrap(); 10 | let message = "Hello, world!"; 11 | let handle = listener(address, message.to_string()); 12 | 13 | // Make the network sender and send the message. 14 | let mut sender = SimpleSender::new(); 15 | sender.send(address, Bytes::from(message)).await; 16 | 17 | // Ensure the server received the message (ie. it did not panic). 18 | assert!(handle.await.is_ok()); 19 | } 20 | 21 | #[tokio::test] 22 | async fn broadcast() { 23 | // Run 3 TCP servers. 24 | let message = "Hello, world!"; 25 | let (handles, addresses): (Vec<_>, Vec<_>) = (0..3) 26 | .map(|x| { 27 | let address = format!("127.0.0.1:{}", 6_200 + x) 28 | .parse::() 29 | .unwrap(); 30 | (listener(address, message.to_string()), address) 31 | }) 32 | .collect::>() 33 | .into_iter() 34 | .unzip(); 35 | 36 | // Make the network sender and send the message. 37 | let mut sender = SimpleSender::new(); 38 | sender.broadcast(addresses, Bytes::from(message)).await; 39 | 40 | // Ensure all servers received the broadcast. 41 | assert!(try_join_all(handles).await.is_ok()); 42 | } 43 | -------------------------------------------------------------------------------- /hotstuff/run.sh: -------------------------------------------------------------------------------- 1 | RUST_LOG=info cargo run --bin node run --keys=node_0.json --tx_address=127.0.0.1:25000 --mempool_address=127.0.0.1:25100 --consensus_address=127.0.0.1:25200 --dvfcore_address=127.0.0.1:25300 --store=db_0 --committee=committee.json 2 | 3 | RUST_LOG=info cargo run --bin node run --keys=node_1.json --tx_address=127.0.0.1:25001 --mempool_address=127.0.0.1:25101 --consensus_address=127.0.0.1:25201 --dvfcore_address=127.0.0.1:25301 --store=db_1 --committee=committee.json 4 | 5 | RUST_LOG=info cargo run --bin node run --keys=node_2.json --tx_address=127.0.0.1:25002 --mempool_address=127.0.0.1:25102 --consensus_address=127.0.0.1:25202 --dvfcore_address=127.0.0.1:25302 --store=db_2 --committee=committee.json 6 | 7 | RUST_LOG=info cargo run --bin node run --keys=node_3.json --tx_address=127.0.0.1:25003 --mempool_address=127.0.0.1:25103 --consensus_address=127.0.0.1:25203 --dvfcore_address=127.0.0.1:25303 --store=db_3 --committee=committee.json 8 | 9 | RUST_LOG=info cargo run --bin node run --keys=node_0.json --store=db_0 --committee=committee.json 10 | RUST_LOG=info cargo run --bin node run --keys=node_1.json --store=db_1 --committee=committee.json 11 | RUST_LOG=info cargo run --bin node run --keys=node_2.json --store=db_2 --committee=committee.json 12 | RUST_LOG=info cargo run --bin node run --keys=node_3.json --store=db_3 --committee=committee.json -------------------------------------------------------------------------------- /hotstuff/store/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "store" 3 | version = "0.1.0" 4 | authors = ["Alberto Sonnino "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | rocksdb = "0.22.0" 10 | tokio = { version = "1.3.0", features = ["sync", "macros", "rt"] } 11 | log = "0.4.0" 12 | utils = { path = "../utils" } 13 | -------------------------------------------------------------------------------- /hotstuff/store/src/tests/store_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use std::fs; 3 | 4 | #[tokio::test] 5 | async fn create_store() { 6 | // Create new store. 7 | let path = ".db_test_create_store"; 8 | let _ = fs::remove_dir_all(path); 9 | let store = Store::new(path); 10 | assert!(store.is_ok()); 11 | } 12 | 13 | #[tokio::test] 14 | async fn read_write_value() { 15 | // Create new store. 16 | let path = ".db_test_read_write_value"; 17 | let _ = fs::remove_dir_all(path); 18 | let mut store = Store::new(path).unwrap(); 19 | 20 | // Write value to the store. 21 | let key = vec![0u8, 1u8, 2u8, 3u8]; 22 | let value = vec![4u8, 5u8, 6u8, 7u8]; 23 | store.write(key.clone(), value.clone()).await; 24 | 25 | // Read value. 26 | let result = store.read(key).await; 27 | assert!(result.is_ok()); 28 | let read_value = result.unwrap(); 29 | assert!(read_value.is_some()); 30 | assert_eq!(read_value.unwrap(), value); 31 | } 32 | 33 | #[tokio::test] 34 | async fn read_unknown_key() { 35 | // Create new store. 36 | let path = ".db_test_read_unknown_key"; 37 | let _ = fs::remove_dir_all(path); 38 | let mut store = Store::new(path).unwrap(); 39 | 40 | // Try to read unknown key. 41 | let key = vec![0u8, 1u8, 2u8, 3u8]; 42 | let result = store.read(key).await; 43 | assert!(result.is_ok()); 44 | assert!(result.unwrap().is_none()); 45 | } 46 | 47 | #[tokio::test] 48 | async fn read_notify() { 49 | // Create new store. 50 | let path = ".db_test_read_notify"; 51 | let _ = fs::remove_dir_all(path); 52 | let mut store = Store::new(path).unwrap(); 53 | 54 | // Try to read a kew that does not yet exist. Then write a value 55 | // for that key and check that notify read returns the result. 56 | let key = vec![0u8, 1u8, 2u8, 3u8]; 57 | let value = vec![4u8, 5u8, 6u8, 7u8]; 58 | 59 | // Try to read a missing value. 60 | let mut store_copy = store.clone(); 61 | let key_copy = key.clone(); 62 | let value_copy = value.clone(); 63 | let handle = tokio::spawn(async move { 64 | match store_copy.notify_read(key_copy).await { 65 | Ok(v) => assert_eq!(v, value_copy), 66 | _ => assert!(false), 67 | } 68 | }); 69 | 70 | // Write the missing value and ensure the handle terminates correctly. 71 | store.write(key, value).await; 72 | assert!(handle.await.is_ok()); 73 | } 74 | -------------------------------------------------------------------------------- /hotstuff/utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "utils" 3 | version = "0.1.0" 4 | authors = ["zico "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | tokio = { version = "1.3.0", features = ["rt", "time", "macros", "sync"] } 10 | log = "0.4.0" 11 | exit-future = "0.2.0" -------------------------------------------------------------------------------- /hotstuff/utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod monitored_channel; 2 | pub mod size_monitor; -------------------------------------------------------------------------------- /hotstuff/utils/src/monitored_channel.rs: -------------------------------------------------------------------------------- 1 | use tokio::sync::mpsc::{channel, Sender, Receiver}; 2 | use tokio::sync::mpsc::error::SendError; 3 | use tokio::time::{sleep, Duration}; 4 | use log::{warn}; 5 | 6 | #[derive(Clone)] 7 | pub struct MonitoredSender { 8 | pub inner: Sender, 9 | _tag: String, 10 | _level: String, 11 | } 12 | 13 | impl MonitoredSender 14 | where T: Send + 'static { 15 | pub fn new( 16 | sender: Sender, 17 | tag: String, 18 | level: String, 19 | ) -> Self { 20 | let sender_copy = sender.clone(); 21 | let tag_copy = tag.clone(); 22 | let level_copy = level.clone(); 23 | tokio::spawn(async move { 24 | MonitoredSender::log(sender_copy, tag_copy, level_copy).await; 25 | }); 26 | 27 | Self { 28 | inner: sender.clone(), 29 | _tag: tag, 30 | _level: level, 31 | } 32 | } 33 | 34 | pub async fn send(&self, msg: T) -> Result<(), SendError> { 35 | self.inner.send(msg).await 36 | } 37 | 38 | async fn log(sender: Sender, tag: String, _level: String) { 39 | loop { 40 | sleep(Duration::from_millis(60_000)).await; 41 | if sender.is_closed() { 42 | break; 43 | } 44 | // if level == "debug" { 45 | // debug!("[{}] remaining capacity: {}", tag, sender.capacity()); 46 | // } 47 | // else { 48 | // info!("[{}] remaining capacity: {}", tag, sender.capacity()); 49 | // } 50 | if sender.capacity() == 0 { 51 | warn!("[{}] Low remaining capacity: {}", tag, sender.capacity()); 52 | } 53 | } 54 | } 55 | } 56 | 57 | 58 | #[derive(Clone)] 59 | pub struct MonitoredChannel; 60 | 61 | impl MonitoredChannel { 62 | pub fn new(capacity: usize, tag: String, level: &str) -> (MonitoredSender, Receiver) { 63 | let (sender, receiver) = channel(capacity); 64 | 65 | let channel = MonitoredSender::new( 66 | sender, 67 | tag, 68 | level.to_string(), 69 | ); 70 | 71 | (channel, receiver) 72 | } 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /hotstuff/utils/src/size_monitor.rs: -------------------------------------------------------------------------------- 1 | use tokio::time::{sleep, Duration}; 2 | use tokio::sync::{RwLock}; 3 | use std::sync::{Arc}; 4 | use log::{info, debug}; 5 | use std::collections::HashMap; 6 | use std::collections::VecDeque; 7 | use std::marker::Send; 8 | 9 | pub struct SizeMonitor; 10 | 11 | impl SizeMonitor { 12 | 13 | pub fn monitor_hashmap(x: HashMap, tag: String, level: String) -> Arc>> { 14 | let y = Arc::new(RwLock::new(x)); 15 | let y_copy = y.clone(); 16 | tokio::spawn(async move { 17 | loop { 18 | sleep(Duration::from_millis(60_000)).await; 19 | if level == "debug" { 20 | debug!("[{}] monitored hashmap size: {}", tag, y_copy.read().await.len()); 21 | } 22 | else { 23 | info!("[{}] monitored hashmap size: {}", tag, y_copy.read().await.len()); 24 | } 25 | } 26 | }); 27 | y 28 | } 29 | 30 | pub fn monitor_vecdeque(x: VecDeque, tag: String, level: String) -> Arc>> { 31 | let y = Arc::new(RwLock::new(x)); 32 | let y_copy = y.clone(); 33 | tokio::spawn(async move { 34 | loop { 35 | sleep(Duration::from_millis(60_000)).await; 36 | if level == "debug" { 37 | debug!("[{}] monitored vecdeque size: {}", tag, y_copy.read().await.len()); 38 | } 39 | else { 40 | info!("[{}] monitored vecdeque size: {}", tag, y_copy.read().await.len()); 41 | } 42 | } 43 | }); 44 | y 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /imgs/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/imgs/architecture.png -------------------------------------------------------------------------------- /imgs/operatpr-setup1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/imgs/operatpr-setup1.png -------------------------------------------------------------------------------- /imgs/operatpr-setup2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/imgs/operatpr-setup2.png -------------------------------------------------------------------------------- /imgs/operatpr-setup3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/imgs/operatpr-setup3.png -------------------------------------------------------------------------------- /imgs/operatpr-setup4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/imgs/operatpr-setup4.png -------------------------------------------------------------------------------- /imgs/operatpr-setup5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/imgs/operatpr-setup5.png -------------------------------------------------------------------------------- /imgs/operatpr-setup6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaState/SafeStakeOperator/6f7f63439b311afa12fb0ab01f744fa3329f3820/imgs/operatpr-setup6.png -------------------------------------------------------------------------------- /scripts/clean_container_log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | log_path=$(sudo docker inspect --format='{{.LogPath}}' $1) 4 | sudo truncate -s 0 $log_path -------------------------------------------------------------------------------- /src/boot_node/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "boot_node" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | bincode = "1" 8 | clap = { version = "4.5.4", features = ["derive", "cargo", "wrap_help"] } 9 | clap_utils = { path = "../../lighthouse/common/clap_utils" } 10 | directory = { path = "../../lighthouse/common/directory" } 11 | dirs = "3" 12 | dvf_utils = { path = "../../lighthouse/common/dvf_utils" } 13 | lighthouse_network = { path = "../../lighthouse/beacon_node/lighthouse_network" } 14 | prost = "0.12" 15 | safestake_crypto = { path = "../../lighthouse/safestake_crypto" } 16 | safestake_database ={ path = "../../lighthouse/validator_client/safestake_database" } 17 | serde = { version = "1", features = ["derive"] } 18 | slashing_protection = { path = "../../lighthouse/validator_client/slashing_protection" } 19 | slog = { version = "2", features = ["max_level_debug", "release_max_level_debug", "nested-values"] } 20 | store = { path = "../../lighthouse/beacon_node/store" } 21 | task_executor = { path = "../../lighthouse/common/task_executor" } 22 | tonic = "0.11" 23 | hex = "0.4" 24 | [build-dependencies] 25 | tonic-build = { version = "0.11.0", features = ["prost"] } 26 | -------------------------------------------------------------------------------- /src/boot_node/bootnode.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package bootnode; 4 | 5 | message QueryNodeAddressRequest { 6 | uint64 version = 1; 7 | bytes operator_public_key = 2; 8 | } 9 | 10 | message QueryNodeAddressResponse { 11 | bytes address = 1; 12 | uint64 seq = 2; 13 | } 14 | 15 | service Bootnode { 16 | rpc QueryNodeAddress(QueryNodeAddressRequest) returns(QueryNodeAddressResponse) {} 17 | } -------------------------------------------------------------------------------- /src/boot_node/build.rs: -------------------------------------------------------------------------------- 1 | // This is a stub for determining the build profile, see `build_profile_name`. 2 | 3 | fn main() -> Result<(), Box> { 4 | let proto_files = ["./bootnode.proto"]; 5 | let includes = ["./"]; 6 | tonic_build::configure().compile(&proto_files, &includes)?; 7 | Ok(()) 8 | } 9 | -------------------------------------------------------------------------------- /src/boot_node/src/boot_service.rs: -------------------------------------------------------------------------------- 1 | use crate::proto::bootnode_server::Bootnode; 2 | use crate::proto::*; 3 | use dvf_utils::VERSION; 4 | use safestake_crypto::secp::PublicKey; 5 | use safestake_database::SafeStakeDatabase; 6 | use tonic::{Request, Response, Status}; 7 | pub struct BootService { 8 | pub db: SafeStakeDatabase, 9 | } 10 | use slashing_protection::NotSafe; 11 | 12 | #[tonic::async_trait] 13 | impl Bootnode for BootService { 14 | async fn query_node_address( 15 | &self, 16 | request: Request, 17 | ) -> Result, Status> { 18 | let req = request.into_inner(); 19 | if req.version != VERSION { 20 | return Err(Status::internal(format!( 21 | "version mismatch, expected {}, got {}", 22 | VERSION, req.version 23 | ))); 24 | } 25 | if req.operator_public_key.len() != 33 { 26 | return Err(Status::internal(format!( 27 | "unkown format of node public key, length: {}", 28 | req.operator_public_key.len() 29 | ))); 30 | } 31 | let node_public_key = PublicKey(req.operator_public_key.try_into().unwrap()); 32 | 33 | match self.db.with_transaction(|txn| { 34 | let addr = self 35 | .db 36 | .query_operator_socket_address(txn, &node_public_key)?; 37 | let seq = self.db.query_operator_seq(txn, &node_public_key)?; 38 | Ok::<(std::net::SocketAddr, u64), NotSafe>((addr, seq)) 39 | }) { 40 | Ok((addr, seq)) => Ok(Response::new(QueryNodeAddressResponse { 41 | address: bincode::serialize(&addr).unwrap(), 42 | seq, 43 | })), 44 | Err(_) => Err(Status::internal(format!( 45 | "node {} not found", 46 | node_public_key.base64() 47 | ))), 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/boot_node/src/config.rs: -------------------------------------------------------------------------------- 1 | use clap::ArgMatches; 2 | use clap_utils::parse_required; 3 | use directory::DEFAULT_ROOT_DIR; 4 | use dvf_utils::ROOT_VERSION; 5 | use serde::{Deserialize, Serialize}; 6 | use slog::{info, Logger}; 7 | use std::net::{IpAddr, Ipv4Addr}; 8 | use std::path::PathBuf; 9 | 10 | #[derive(Clone, Debug, Serialize, Deserialize)] 11 | pub struct Config { 12 | pub ip: IpAddr, 13 | pub port: u16, 14 | pub root_dir: PathBuf, 15 | } 16 | 17 | impl Default for Config { 18 | fn default() -> Self { 19 | Self { 20 | ip: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 21 | port: 9005, 22 | root_dir: dirs::home_dir() 23 | .unwrap_or_else(|| PathBuf::from(".")) 24 | .join(DEFAULT_ROOT_DIR) 25 | .join(format!("v{}", ROOT_VERSION)) 26 | .join("mainnet"), 27 | } 28 | } 29 | } 30 | 31 | impl Config { 32 | pub fn from_cli(cli_args: &ArgMatches, log: &Logger) -> Result { 33 | let mut config = Config::default(); 34 | config.ip = parse_required(cli_args, "ip")?; 35 | info!(log, "read operator ip"; "operator ip" => %config.ip); 36 | 37 | config.port = parse_required(cli_args, "port")?; 38 | info!(log, "read port"; "port" => config.port); 39 | 40 | config.root_dir = dirs::home_dir() 41 | .unwrap_or_else(|| PathBuf::from(".")) 42 | .join(DEFAULT_ROOT_DIR) 43 | .join(format!("v{}", ROOT_VERSION)); 44 | 45 | Ok(config) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/boot_node/src/proto.rs: -------------------------------------------------------------------------------- 1 | include!(concat!(env!("OUT_DIR"), "/bootnode.rs")); 2 | -------------------------------------------------------------------------------- /src/cli.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use serde::{Deserialize, Serialize}; 3 | use validator_client::cli::ValidatorClient; 4 | 5 | #[derive(Parser, Clone, Deserialize, Serialize, Debug)] 6 | pub enum LighthouseSubcommands { 7 | #[clap(name = "validator_client")] 8 | ValidatorClient(Box), 9 | } 10 | -------------------------------------------------------------------------------- /src/crypto/define.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use miracl_core::bls12381::big; 3 | use miracl_core::bls12381::big::BIG; 4 | use miracl_core::bls12381::dbig::DBIG; 5 | use miracl_core::bls12381::ecp::ECP; 6 | use miracl_core::bls12381::ecp2::ECP2; 7 | use miracl_core::bls12381::fp12::FP12; 8 | use miracl_core::bls12381::rom; 9 | use num_bigint::{BigInt, Sign}; 10 | 11 | pub use miracl_core::bls12381::pair; 12 | 13 | pub type BigNum = BIG; 14 | pub type DBigNum = DBIG; 15 | pub type G1 = ECP; 16 | pub type G2 = ECP2; 17 | pub type Gt = FP12; 18 | 19 | pub const MB: usize = big::MODBYTES as usize; 20 | 21 | pub type G1Vector = Vec; 22 | pub type G2Vector = Vec; 23 | 24 | lazy_static! { 25 | // CURVE_ORDER is a 255-bit prime 26 | // It equals: 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 (https://github.com/zkcrypto/bls12_381) 27 | // The presentation in rom::CURVE_ORDER seems a little different because it only uses 58 bits in each CHUNK (set in big::BASEBITS), 28 | // hence there is some bit shifting, but the number is the same. 29 | pub static ref CURVE_ORDER: BigNum = BigNum::new_ints(&rom::CURVE_ORDER); 30 | static ref BUF: [u8; MB] = { 31 | let mut m = [0; MB]; 32 | CURVE_ORDER.tobytes(&mut m); 33 | m 34 | }; 35 | pub static ref MODULUS: BigInt = BigInt::from_bytes_be(Sign::Plus, &BUF[..]); 36 | pub static ref DBIG_ZERO: DBigNum = DBigNum::new(); 37 | } 38 | -------------------------------------------------------------------------------- /src/crypto/impls/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod blst; 2 | -------------------------------------------------------------------------------- /src/crypto/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod define; 2 | pub mod dkg; 3 | pub mod elgamal; 4 | pub mod generic_threshold; 5 | pub mod impls; 6 | 7 | macro_rules! define_mod { 8 | ($name: ident, $mod: path) => { 9 | pub mod $name { 10 | use $mod as bls_variant; 11 | 12 | use crate::crypto::generic_threshold::*; 13 | 14 | pub type ThresholdSignature = 15 | GenericThresholdSignature; 16 | } 17 | }; 18 | } 19 | 20 | define_mod!( 21 | blst_threshold_implementations, 22 | crate::crypto::impls::blst::types 23 | ); 24 | pub use blst_threshold_implementations::*; 25 | -------------------------------------------------------------------------------- /src/dvf_key_tool/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dvf_key_tool" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | dvf_utils = { path = "../../lighthouse/common/dvf_utils" } 8 | safestake_crypto = { path = "../../lighthouse/safestake_crypto" } 9 | dirs = "3" -------------------------------------------------------------------------------- /src/dvf_key_tool/src/main.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::fs; 3 | 4 | use dvf_utils::ROOT_VERSION; 5 | use safestake_crypto::secret::Export as _; 6 | use safestake_crypto::secret::Secret; 7 | 8 | pub const DEFAULT_SECRET_DIR: &str = "node_key.json"; 9 | pub const DEFAULT_ROOT_DIR: &str = ".lighthouse"; 10 | 11 | 12 | fn main() { 13 | println!("------dvf_key_tool------"); 14 | 15 | let network = std::env::args() 16 | .nth(1) 17 | .expect("ERROR: there is no valid network argument"); 18 | let base_dir = dirs::home_dir() 19 | .expect("ERROR: home dir is valid") 20 | .join(DEFAULT_ROOT_DIR) 21 | .join(format!("v{}", ROOT_VERSION)) 22 | .join(&network); 23 | let secret_dir = base_dir.join(DEFAULT_SECRET_DIR); 24 | 25 | //generate secret key if not exists 26 | if secret_dir.exists() { 27 | println!( 28 | "INFO: secret file has been generated, path: {}", 29 | &secret_dir.to_str().unwrap() 30 | ); 31 | let secret = Secret::read(&secret_dir) 32 | .expect("ERROR: can't read secret file, unexpect error happened."); 33 | println!("INFO: node public key {}", secret.name.base64()); 34 | } else { 35 | let secret = Secret::new(); 36 | if !base_dir.exists() { 37 | fs::create_dir_all(&base_dir).unwrap_or_else(|why| { 38 | println!("ERROR: can't create dir {:?}", why.kind()); 39 | return; 40 | }); 41 | } 42 | secret 43 | .write(&secret_dir) 44 | .expect("ERROR: Can't write to file"); 45 | println!("INFO: node public key {}", secret.name.base64()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // #[macro_use] 2 | // extern crate downcast_rs; 3 | // pub mod crypto; 4 | // pub mod math; 5 | // pub mod utils; 6 | // // pub mod simulator; 7 | // pub mod deposit; 8 | // pub mod exit; 9 | // pub mod network; 10 | // pub mod node; 11 | // pub mod test_utils; 12 | // pub mod validation; 13 | // pub const DEFAULT_CHANNEL_CAPACITY: usize = 1_000; 14 | -------------------------------------------------------------------------------- /src/math/bigint_ext.rs: -------------------------------------------------------------------------------- 1 | use crate::crypto::define::MODULUS; 2 | use miracl_core::bls12381::big::BIG; 3 | use num_bigint::{BigInt, Sign}; 4 | 5 | pub trait Ring { 6 | fn reduce(&self, m: &BigInt) -> Self; 7 | } 8 | 9 | impl Ring for BigInt { 10 | fn reduce(&self, m: &BigInt) -> BigInt { 11 | let mut result = self.clone(); 12 | result %= m; 13 | if result.sign() == Sign::Minus { 14 | result += m; 15 | } 16 | result 17 | } 18 | } 19 | 20 | #[allow(non_snake_case)] 21 | pub trait ToBIG { 22 | fn to_BIG(&self) -> BIG; 23 | } 24 | 25 | impl ToBIG for BigInt { 26 | fn to_BIG(&self) -> BIG { 27 | let reduced = self.reduce(&MODULUS); 28 | BIG::fromstring(reduced.to_str_radix(16)) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/math/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bigint_ext; 2 | pub mod polynomial; 3 | -------------------------------------------------------------------------------- /src/metrics.rs: -------------------------------------------------------------------------------- 1 | use lighthouse_version::VERSION; 2 | pub use metrics::*; 3 | use slog::{error, Logger}; 4 | use std::sync::LazyLock; 5 | use std::time::{SystemTime, UNIX_EPOCH}; 6 | 7 | pub static PROCESS_START_TIME_SECONDS: LazyLock> = LazyLock::new(|| { 8 | try_create_int_gauge( 9 | "process_start_time_seconds", 10 | "The unix timestamp at which the process was started", 11 | ) 12 | }); 13 | 14 | pub static LIGHTHOUSE_VERSION: LazyLock> = LazyLock::new(|| { 15 | try_create_int_gauge_vec( 16 | "lighthouse_info", 17 | "The build of Lighthouse running on the server", 18 | &["version"], 19 | ) 20 | }); 21 | 22 | pub fn expose_process_start_time(log: &Logger) { 23 | match SystemTime::now().duration_since(UNIX_EPOCH) { 24 | Ok(duration) => set_gauge(&PROCESS_START_TIME_SECONDS, duration.as_secs() as i64), 25 | Err(e) => error!( 26 | log, 27 | "Failed to read system time"; 28 | "error" => %e 29 | ), 30 | } 31 | } 32 | 33 | pub fn expose_lighthouse_version() { 34 | set_gauge_vec(&LIGHTHOUSE_VERSION, &[VERSION], 1); 35 | } 36 | -------------------------------------------------------------------------------- /src/network/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod io_committee; 2 | -------------------------------------------------------------------------------- /src/node/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | pub mod contract; 3 | pub mod db; 4 | pub mod discovery; 5 | pub mod dvfcore; 6 | pub mod node; 7 | pub mod status_report; 8 | pub mod utils; 9 | -------------------------------------------------------------------------------- /src/node/status_report.rs: -------------------------------------------------------------------------------- 1 | use crate::node::config::{API_ADDRESS, STATUS_REPORT_URL}; 2 | use crate::node::utils::request_to_web_server; 3 | use crate::node::utils::SignDigest; 4 | use crate::validation::http_metrics::metrics; 5 | use hscrypto::SecretKey; 6 | use serde::Serialize; 7 | use std::net::SocketAddr; 8 | use std::time::Duration; 9 | #[derive(Debug, Serialize)] 10 | pub struct StatusReportRequest { 11 | #[serde(rename = "operatorId")] 12 | pub operator_id: u32, 13 | pub address: String, 14 | #[serde(rename = "validatorEnabled")] 15 | pub validator_enabled: usize, 16 | #[serde(rename = "validatorTotal")] 17 | pub validator_total: usize, 18 | #[serde(rename = "signedBlocks")] 19 | pub signed_blocks: usize, 20 | #[serde(rename = "signedAttestation")] 21 | pub signed_attestation: usize, 22 | pub version: usize, 23 | #[serde(rename = "connectedNodes")] 24 | pub connected_nodes: usize, 25 | #[serde(skip_serializing_if = "Option::is_none")] 26 | pub sign_hex: Option, 27 | } 28 | 29 | impl SignDigest for StatusReportRequest {} 30 | 31 | pub struct StatusReport {} 32 | 33 | impl StatusReport { 34 | pub fn spawn(address: SocketAddr, operator_id: u32, secret: SecretKey) { 35 | tokio::spawn(async move { 36 | let mut report_interval = tokio::time::interval(Duration::from_secs(60 * 5)); 37 | loop { 38 | report_interval.tick().await; 39 | let mut report_body = StatusReportRequest { 40 | operator_id, 41 | address: address.to_string(), 42 | validator_enabled: metrics::int_gauge(&metrics::ENABLED_VALIDATORS_COUNT) 43 | as usize, 44 | validator_total: metrics::int_gauge(&metrics::TOTAL_VALIDATORS_COUNT) as usize, 45 | signed_blocks: metrics::int_counter_vec( 46 | &metrics::SIGNED_BLOCKS_TOTAL, 47 | &[metrics::SUCCESS], 48 | ) as usize, 49 | signed_attestation: metrics::int_counter_vec( 50 | &metrics::SIGNED_ATTESTATIONS_TOTAL, 51 | &[metrics::SUCCESS], 52 | ) as usize, 53 | version: dvf_version::SOFTWARE_VERSION as usize, 54 | connected_nodes: metrics::int_counter(&metrics::DVT_VC_CONNECTED_NODES) 55 | as usize, 56 | sign_hex: None, 57 | }; 58 | report_body.sign_hex = Some(report_body.sign_digest(&secret).unwrap()); 59 | log::info!("[Dvf Status Report] Body: {:?}", &report_body); 60 | let url_str = API_ADDRESS.get().unwrap().to_owned() + STATUS_REPORT_URL; 61 | tokio::spawn(async move { 62 | _ = request_to_web_server(report_body, &url_str).await; 63 | }); 64 | } 65 | }); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test_utils/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::crypto::ThresholdSignature; 2 | // use validator_dir::{ValidatorDir, BuilderError}; 3 | // use std::path::{Path, PathBuf}; 4 | // use validator_dir::insecure_keys::{INSECURE_PASSWORD,}; 5 | use types::test_utils::generate_deterministic_keypair; 6 | // use std::iter::zip; 7 | use bls::Keypair; 8 | use std::collections::HashMap; 9 | 10 | pub struct ThresholdKeyPack { 11 | pub kp: Keypair, 12 | pub kps: HashMap, 13 | pub threshold: u64, 14 | } 15 | 16 | pub fn generate_deterministic_threshold_keypairs( 17 | validator_id: u64, 18 | node_ids: &[u64], 19 | threshold: usize, 20 | ) -> ThresholdKeyPack { 21 | let kp = generate_deterministic_keypair(validator_id as usize); 22 | 23 | let mut m_threshold = ThresholdSignature::new(threshold); 24 | let kps = m_threshold 25 | .deterministic_key_split(&kp.sk, node_ids) 26 | .unwrap(); 27 | 28 | ThresholdKeyPack { 29 | kp, 30 | kps, 31 | threshold: threshold as u64, 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/utils/error.rs: -------------------------------------------------------------------------------- 1 | use bls::Error as BlsError; 2 | use blst::BLST_ERROR as BlstError; 3 | 4 | pub fn require(status: bool, msg: &'static str) { 5 | if !status { 6 | panic!("{}", msg); 7 | } 8 | } 9 | 10 | #[derive(Clone, Debug, PartialEq)] 11 | pub enum DvfError { 12 | BlsError(BlsError), 13 | BlstError(BlstError), 14 | /// The consensus protocol failed. 15 | ConsensusFailure(String), 16 | /// Key generation failed. 17 | KeyGenError(String), 18 | /// Threshold signature aggregation failed due to insufficient valid signatures. 19 | InsufficientSignatures { 20 | got: usize, 21 | expected: usize, 22 | }, 23 | /// Threshold signature aggregation failed due to insufficient valid signatures. 24 | InsufficientValidSignatures { 25 | got: usize, 26 | expected: usize, 27 | }, 28 | /// Invalid operator signature 29 | InvalidSignatureShare { 30 | id: u64, 31 | }, 32 | /// Invalid operator id 33 | InvalidOperatorId { 34 | id: u64, 35 | }, 36 | /// Different length 37 | DifferentLength { 38 | x: usize, 39 | y: usize, 40 | }, 41 | /// 42 | InvalidLength, 43 | /// Should not call the function specified by the string 44 | UnexpectedCall(String), 45 | /// Error propogated from Store 46 | StoreError(String), 47 | /// Vss share verification 48 | VssShareVerificationFailed, 49 | /// Dispute claim 50 | InvalidDkgShare(Vec<(u64, u64)>), 51 | /// Commitment 52 | CommitmentVerificationFailed, 53 | /// Zero knowledge proof 54 | ZKProofInvalidInput, 55 | /// Zero knowledge proof verification 56 | ZKVerificationFailed, 57 | InsufficientValidPks, 58 | /// Socket address is not available 59 | SocketAddrUnknown, 60 | /// Validator store is not construted yet 61 | ValidatorStoreNotReady, 62 | /// Unknown error 63 | Unknown, 64 | /// BeaconNode client error 65 | BeaconNodeClientError, 66 | /// Get beacon genesis error 67 | BeaconNodeGenesisError, 68 | /// Get beacon validator data error 69 | BeaconNodeValidatorError(String), 70 | /// Get beacon state fork error 71 | BeaconNodeStateForkError(String), 72 | } 73 | 74 | impl From for DvfError { 75 | fn from(e: BlsError) -> DvfError { 76 | DvfError::BlsError(e) 77 | } 78 | } 79 | 80 | impl From for DvfError { 81 | fn from(e: BlstError) -> DvfError { 82 | DvfError::BlstError(e) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/utils/ip_util.rs: -------------------------------------------------------------------------------- 1 | use std::net::{IpAddr, UdpSocket}; 2 | 3 | pub fn get_local_ip() -> String { 4 | let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); 5 | socket.connect("8.8.8.8:80").unwrap(); 6 | let local_addr = socket.local_addr().unwrap(); 7 | let ip = local_addr.ip(); 8 | match ip { 9 | IpAddr::V4(ipv4) => ipv4.to_string(), 10 | IpAddr::V6(ipv6) => ipv6.to_string(), 11 | } 12 | } 13 | 14 | /// tracing_test https://docs.rs/tracing-test/latest/tracing_test/ 15 | /// https://stackoverflow.com/questions/72884779/how-to-print-tracing-output-in-tests 16 | #[cfg(test)] 17 | mod tests { 18 | use tracing::debug; 19 | use tracing_test::traced_test; 20 | 21 | // Note this useful idiom: importing names from outer (for mod tests) scope. 22 | use super::*; 23 | 24 | #[traced_test] 25 | #[test] 26 | fn test_get_pub_ip() { 27 | debug!("{}", get_local_ip()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod blst_utils; 2 | pub mod error; 3 | pub mod ip_util; 4 | pub mod rand_utils; 5 | -------------------------------------------------------------------------------- /src/utils/rand_utils.rs: -------------------------------------------------------------------------------- 1 | use num_bigint::{BigInt, RandBigInt}; 2 | use num_traits::Zero; 3 | use rand::distributions::Uniform; 4 | use rand::rngs::StdRng; 5 | use rand::{Rng, SeedableRng}; 6 | 7 | pub trait Sample { 8 | fn sample(&mut self, modulus: &T) -> T; 9 | fn sample_range(&mut self, low: &T, high: &T) -> T; 10 | fn sample_vec(&mut self, len: usize, modulus: &T) -> Vec; 11 | fn sample_range_vec(&mut self, len: usize, low: &T, high: &T) -> Vec; 12 | fn sample_array(&mut self, modulus: &T) -> [T; L]; 13 | fn sample_range_array(&mut self, low: &T, high: &T) -> [T; L]; 14 | } 15 | 16 | trait RandUtils { 17 | type Kernel; 18 | 19 | fn get_rng() -> Self::Kernel; 20 | fn get_seeded_rng(seed: &[u8; 32]) -> Self::Kernel; 21 | } 22 | 23 | #[derive(Debug)] 24 | pub struct RandUtilsRng { 25 | // Keep an internal RNG member to avoid having to initiate a new one in every functionality call 26 | pub rng: StdRng, 27 | } 28 | 29 | impl Default for RandUtilsRng { 30 | fn default() -> Self { 31 | Self::new() 32 | } 33 | } 34 | 35 | impl RandUtilsRng { 36 | pub fn new() -> Self { 37 | Self { 38 | rng: Self::get_rng(), 39 | } 40 | } 41 | 42 | pub fn from_seed(seed: &[u8; 32]) -> Self { 43 | Self { 44 | rng: Self::get_seeded_rng(seed), 45 | } 46 | } 47 | } 48 | 49 | impl RandUtils for RandUtilsRng { 50 | type Kernel = StdRng; 51 | 52 | fn get_rng() -> Self::Kernel { 53 | StdRng::from_entropy() 54 | } 55 | 56 | fn get_seeded_rng(seed: &[u8; 32]) -> Self::Kernel { 57 | StdRng::from_seed(*seed) 58 | } 59 | } 60 | 61 | impl Sample for RandUtilsRng { 62 | fn sample(&mut self, modulus: &BigInt) -> BigInt { 63 | self.rng.gen_bigint_range(&BigInt::zero(), modulus) 64 | } 65 | 66 | fn sample_range(&mut self, low: &BigInt, high: &BigInt) -> BigInt { 67 | self.rng.gen_bigint_range(low, high) 68 | } 69 | 70 | fn sample_vec(&mut self, len: usize, modulus: &BigInt) -> Vec { 71 | let range = Uniform::from(BigInt::zero()..modulus.clone()); 72 | /* 73 | The grammar '(&mut self.rng).sample_iter(...)' might seem a little difficult to understand. Check the following 3 links: 74 | https://rust-random.github.io/rand/rand/trait.Rng.html#method.sample_iter 75 | https://rust-random.github.io/rand/rand/trait.RngCore.html#impl-RngCore-for-%26%27a%20mut%20R 76 | https://stackoverflow.com/questions/28005134/how-do-i-implement-the-add-trait-for-a-reference-to-a-struct 77 | 78 | Basically, it is because RngCore is also implemented for the REFERENCE of any type that implements RngCore + Sized. 79 | Hence here we are taking the reference by value, which is just a simple copy of the reference, but not moving the ownership. 80 | */ 81 | (&mut self.rng).sample_iter(&range).take(len).collect() 82 | } 83 | 84 | fn sample_range_vec(&mut self, len: usize, low: &BigInt, high: &BigInt) -> Vec { 85 | let range = Uniform::from(low.clone()..high.clone()); 86 | (&mut self.rng).sample_iter(&range).take(len).collect() 87 | } 88 | 89 | fn sample_array(&mut self, modulus: &BigInt) -> [BigInt; L] { 90 | array_init::array_init(|_| self.sample(modulus)) 91 | } 92 | 93 | fn sample_range_array(&mut self, low: &BigInt, high: &BigInt) -> [BigInt; L] { 94 | array_init::array_init(|_| self.sample_range(low, high)) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/validation/check_synced.rs: -------------------------------------------------------------------------------- 1 | use crate::validation::beacon_node_fallback::CandidateError; 2 | use eth2::BeaconNodeHttpClient; 3 | use slog::{debug, error, warn, Logger}; 4 | use slot_clock::SlotClock; 5 | 6 | /// A distance in slots. 7 | const SYNC_TOLERANCE: u64 = 4; 8 | 9 | /// Returns 10 | /// 11 | /// `Ok(())` if the beacon node is synced and ready for action, 12 | /// `Err(CandidateError::Offline)` if the beacon node is unreachable, 13 | /// `Err(CandidateError::NotSynced)` if the beacon node indicates that it is syncing **AND** 14 | /// it is more than `SYNC_TOLERANCE` behind the highest 15 | /// known slot. 16 | /// 17 | /// The second condition means the even if the beacon node thinks that it's syncing, we'll still 18 | /// try to use it if it's close enough to the head. 19 | pub async fn check_synced( 20 | beacon_node: &BeaconNodeHttpClient, 21 | slot_clock: &T, 22 | log_opt: Option<&Logger>, 23 | ) -> Result<(), CandidateError> { 24 | let resp = match beacon_node.get_node_syncing().await { 25 | Ok(resp) => resp, 26 | Err(e) => { 27 | if let Some(log) = log_opt { 28 | warn!( 29 | log, 30 | "Unable connect to beacon node"; 31 | "error" => %e 32 | ) 33 | } 34 | 35 | return Err(CandidateError::Offline); 36 | } 37 | }; 38 | 39 | let is_synced = !resp.data.is_syncing || (resp.data.sync_distance.as_u64() < SYNC_TOLERANCE); 40 | 41 | if let Some(log) = log_opt { 42 | if !is_synced { 43 | debug!( 44 | log, 45 | "Beacon node sync status"; 46 | "status" => format!("{:?}", resp), 47 | ); 48 | 49 | warn!( 50 | log, 51 | "Beacon node is not synced"; 52 | "sync_distance" => resp.data.sync_distance.as_u64(), 53 | "head_slot" => resp.data.head_slot.as_u64(), 54 | "endpoint" => %beacon_node, 55 | ); 56 | } 57 | 58 | if let Some(local_slot) = slot_clock.now() { 59 | let remote_slot = resp.data.head_slot + resp.data.sync_distance; 60 | if remote_slot + 1 < local_slot || local_slot + 1 < remote_slot { 61 | error!( 62 | log, 63 | "Time discrepancy with beacon node"; 64 | "msg" => "check the system time on this host and the beacon node", 65 | "beacon_node_slot" => remote_slot, 66 | "local_slot" => local_slot, 67 | "endpoint" => %beacon_node, 68 | ); 69 | } 70 | } 71 | } 72 | 73 | if is_synced { 74 | Ok(()) 75 | } else { 76 | Err(CandidateError::NotSynced) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/validation/eth2_keystore_share/keystore_share.rs: -------------------------------------------------------------------------------- 1 | //! Reference: lighthouse/crypto/eth2_keystore::keystore 2 | //! 3 | //! Provides a JSON keystore share for a BLS keypair 4 | 5 | use bls::PublicKey; 6 | use eth2_keystore::{Keystore, Uuid}; 7 | use serde::{Deserialize, Serialize}; 8 | use std::fs::File; 9 | use std::io::{Read, Write}; 10 | use std::path::Path; 11 | 12 | use eth2_keystore::Error as KeyStoreError; 13 | 14 | /// Provides a BLS keystore share. 15 | /// 16 | /// Use `KeystoreShareBuilder` to create a new keystore share. 17 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 18 | #[serde(deny_unknown_fields)] 19 | pub struct KeystoreShare { 20 | pub keystore: Keystore, 21 | pub master_public_key: PublicKey, 22 | pub master_id: u64, 23 | pub share_id: u64, 24 | } 25 | 26 | impl KeystoreShare { 27 | pub fn new( 28 | keystore: Keystore, 29 | master_public_key: PublicKey, 30 | master_id: u64, 31 | share_id: u64, 32 | ) -> Self { 33 | Self { 34 | keystore, 35 | master_public_key, 36 | master_id, 37 | share_id, 38 | } 39 | } 40 | 41 | /// Returns the UUID for the keystore. 42 | pub fn uuid(&self) -> &Uuid { 43 | self.keystore.uuid() 44 | } 45 | 46 | /// Encodes `self` as a JSON object. 47 | pub fn to_json_string(&self) -> Result { 48 | serde_json::to_string(self).map_err(|e| KeyStoreError::UnableToSerialize(format!("{}", e))) 49 | } 50 | 51 | /// Returns `self` from an encoded JSON object. 52 | pub fn from_json_str(json_string: &str) -> Result { 53 | serde_json::from_str(json_string).map_err(|e| KeyStoreError::InvalidJson(format!("{}", e))) 54 | } 55 | 56 | /// Encodes self as a JSON object to the given `writer`. 57 | pub fn to_json_writer(&self, writer: W) -> Result<(), KeyStoreError> { 58 | serde_json::to_writer(writer, self).map_err(|e| KeyStoreError::WriteError(format!("{}", e))) 59 | } 60 | 61 | /// Instantiates `self` from a JSON `reader`. 62 | pub fn from_json_reader(reader: R) -> Result { 63 | serde_json::from_reader(reader).map_err(|e| KeyStoreError::ReadError(format!("{}", e))) 64 | } 65 | 66 | /// Instantiates `self` by reading a JSON file at `path`. 67 | pub fn from_json_file>(path: P) -> Result { 68 | File::options() 69 | .read(true) 70 | .write(false) 71 | .create(false) 72 | .open(path) 73 | .map_err(|e| KeyStoreError::ReadError(format!("{}", e))) 74 | .and_then(Self::from_json_reader) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/validation/eth2_keystore_share/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod keystore_share; 2 | -------------------------------------------------------------------------------- /src/validation/generic_operator_committee.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::error::DvfError; 2 | use crate::validation::operator::TOperator; 3 | use async_trait::async_trait; 4 | use std::sync::Arc; 5 | // use tokio::sync::mpsc::Receiver; 6 | use tokio::sync::RwLock; 7 | use types::{Hash256, PublicKey, Signature}; 8 | /// Operator committee for a validator. 9 | /// 10 | #[async_trait] 11 | pub trait TOperatorCommittee: Send { 12 | fn new( 13 | validator_id: u64, 14 | validator_public_key: PublicKey, 15 | t: usize, 16 | // rx_consensus: Receiver, 17 | ) -> Self; 18 | fn validator_id(&self) -> u64; 19 | async fn add_operator(&mut self, operator_id: u64, operator: Arc>); 20 | // async fn consensus(&self, msg: Hash256) -> Result<(), DvfError>; 21 | async fn consensus_on_duty(&self, data: &[u8]) -> Result<(), DvfError>; 22 | async fn sign(&self, msg: Hash256) -> Result<(Signature, Vec), DvfError>; 23 | async fn get_leader(&self, nonce: u64) -> u64; 24 | async fn get_op_pos(&self, op_id: u64) -> usize; 25 | async fn is_leader_active(&self, nonce: u64) -> bool; 26 | fn get_validator_pk(&self) -> PublicKey; 27 | fn threshold(&self) -> usize; 28 | } 29 | 30 | /// Generic operator committee who delegates most functionalities to an underlying committee implementation (specified through the generic type parameter) 31 | pub struct GenericOperatorCommittee { 32 | cmt: Committee, 33 | } 34 | 35 | impl GenericOperatorCommittee 36 | where 37 | Committee: TOperatorCommittee, 38 | { 39 | pub fn new( 40 | validator_id: u64, 41 | validator_public_key: PublicKey, 42 | threshold: usize, 43 | // rx_consensus: Receiver, 44 | ) -> Self { 45 | Self { 46 | cmt: TOperatorCommittee::new( 47 | validator_id, 48 | validator_public_key, 49 | threshold, 50 | // rx_consensus, 51 | ), 52 | } 53 | } 54 | 55 | pub fn validator_id(&self) -> u64 { 56 | self.cmt.validator_id() 57 | } 58 | 59 | pub async fn add_operator(&mut self, operator_id: u64, operator: Arc>) { 60 | self.cmt.add_operator(operator_id, operator).await; 61 | } 62 | 63 | pub fn threshold(&self) -> usize { 64 | self.cmt.threshold() 65 | } 66 | 67 | pub async fn sign(&self, msg: Hash256) -> Result<(Signature, Vec), DvfError> { 68 | self.cmt.sign(msg).await 69 | } 70 | 71 | pub async fn get_leader(&self, nonce: u64) -> u64 { 72 | self.cmt.get_leader(nonce).await 73 | } 74 | 75 | pub fn get_validator_pk(&self) -> PublicKey { 76 | self.cmt.get_validator_pk() 77 | } 78 | 79 | pub async fn get_op_pos(&self, op_id: u64) -> usize { 80 | self.cmt.get_op_pos(op_id).await 81 | } 82 | 83 | pub async fn consensus_on_duty(&self, data: &[u8]) { 84 | let _ = self.cmt.consensus_on_duty(data).await; 85 | } 86 | 87 | pub async fn is_leader_active(&self, nonce: u64) -> bool { 88 | self.cmt.is_leader_active(nonce).await 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/validation/impls/mod.rs: -------------------------------------------------------------------------------- 1 | // pub mod fake; 2 | pub mod hotstuff; 3 | -------------------------------------------------------------------------------- /src/validation/latency.rs: -------------------------------------------------------------------------------- 1 | use crate::validation::{http_metrics::metrics, BeaconNodeFallback}; 2 | use environment::RuntimeContext; 3 | use slog::debug; 4 | use slot_clock::SlotClock; 5 | use std::sync::Arc; 6 | use tokio::time::sleep; 7 | use types::EthSpec; 8 | 9 | /// The latency service will run 11/12ths of the way through the slot. 10 | pub const SLOT_DELAY_MULTIPLIER: u32 = 11; 11 | pub const SLOT_DELAY_DENOMINATOR: u32 = 12; 12 | 13 | /// Starts a service that periodically checks the latency between the VC and the 14 | /// candidate BNs. 15 | pub fn start_latency_service( 16 | context: RuntimeContext, 17 | slot_clock: T, 18 | beacon_nodes: Arc>, 19 | ) { 20 | let log = context.log().clone(); 21 | 22 | let future = async move { 23 | loop { 24 | let sleep_time = slot_clock 25 | .duration_to_next_slot() 26 | .map(|next_slot| { 27 | // This is 11/12ths through the next slot. On mainnet this 28 | // will happen in the 11th second of each slot, one second 29 | // before the next slot. 30 | next_slot + (next_slot / SLOT_DELAY_DENOMINATOR) * SLOT_DELAY_MULTIPLIER 31 | }) 32 | // If we can't read the slot clock, just wait one slot. Running 33 | // the measurement at a non-exact time is not a big issue. 34 | .unwrap_or_else(|| slot_clock.slot_duration()); 35 | 36 | // Sleep until it's time to perform the measurement. 37 | sleep(sleep_time).await; 38 | 39 | for (i, measurement) in beacon_nodes.measure_latency().await.iter().enumerate() { 40 | if let Some(latency) = measurement.latency { 41 | debug!( 42 | log, 43 | "Measured BN latency"; 44 | "node" => &measurement.beacon_node_id, 45 | "latency" => latency.as_millis(), 46 | ); 47 | metrics::observe_timer_vec( 48 | &metrics::VC_BEACON_NODE_LATENCY, 49 | &[&measurement.beacon_node_id], 50 | latency, 51 | ); 52 | if i == 0 { 53 | metrics::observe_duration( 54 | &metrics::VC_BEACON_NODE_LATENCY_PRIMARY_ENDPOINT, 55 | latency, 56 | ); 57 | } 58 | } 59 | } 60 | } 61 | }; 62 | 63 | context.executor.spawn(future, "latency"); 64 | } 65 | -------------------------------------------------------------------------------- /src/validation/operator_committees.rs: -------------------------------------------------------------------------------- 1 | use crate::node::config::invalid_addr; 2 | use crate::validation::operator::RemoteOperator; 3 | use crate::validation::operator_committee_definitions::OperatorCommitteeDefinition; 4 | use crate::validation::OperatorCommittee; 5 | use std::sync::Arc; 6 | use tokio::sync::RwLock; 7 | // use types::Hash256; 8 | // use crate::DEFAULT_CHANNEL_CAPACITY; 9 | // use hsutils::monitored_channel::{MonitoredChannel, MonitoredSender}; 10 | 11 | impl OperatorCommittee { 12 | pub async fn from_definition(def: OperatorCommitteeDefinition) -> Self { 13 | // let (tx, rx) = MonitoredChannel::new( 14 | // DEFAULT_CHANNEL_CAPACITY, 15 | // format!("{}-dvf-op-committee", def.validator_id), 16 | // "debug", 17 | // ); 18 | 19 | let mut committee = Self::new( 20 | def.validator_id, 21 | def.validator_public_key.clone(), 22 | def.threshold as usize, 23 | // rx, 24 | ); 25 | for i in 0..(def.total as usize) { 26 | let addr = def.base_socket_addresses[i].unwrap_or(invalid_addr()); 27 | let operator = RemoteOperator::new( 28 | def.validator_id, 29 | def.operator_ids[i], 30 | def.node_public_keys[i].clone(), 31 | def.operator_public_keys[i].clone(), 32 | addr, 33 | ); 34 | committee 35 | .add_operator(def.operator_ids[i], Arc::new(RwLock::new(operator))) 36 | .await; 37 | } 38 | committee 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/validation/validator_dir/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod share_builder; 2 | -------------------------------------------------------------------------------- /tests/test_generic_threshold.rs: -------------------------------------------------------------------------------- 1 | use bls::{PublicKey, Signature}; 2 | use dvf::crypto::ThresholdSignature; 3 | use ethereum_hashing::{Context, Sha256Context}; 4 | use types::Hash256; 5 | 6 | #[test] 7 | fn test_generic_threshold() { 8 | let t = 5; 9 | let n = 10; 10 | let mut m_threshold = ThresholdSignature::new(t); 11 | let ids = (1..n + 1).map(|k| k as u64).collect::>(); 12 | let (kp, kps) = m_threshold.key_gen(&ids).unwrap(); 13 | 14 | let pks: Vec<&PublicKey> = ids.iter().map(|id| &kps[id].pk).collect(); 15 | let message = "hello world"; 16 | let mut context = Context::new(); 17 | context.update(message.as_bytes()); 18 | let message = Hash256::from_slice(&context.finalize()); 19 | 20 | let mut sigs: Vec = Vec::new(); 21 | for id in ids.iter() { 22 | sigs.push(kps[id].sk.sign(message)); 23 | } 24 | let sigs_ref: Vec<&Signature> = sigs.iter().map(|s| s).collect(); 25 | //let pks_ref: Vec<&PublicKey> = pks.iter().map(|s| s).collect(); 26 | let agg_sig = m_threshold 27 | .threshold_aggregate(&sigs_ref[..], &pks[..], &ids[..], message) 28 | .unwrap(); 29 | 30 | let sig = kp.sk.sign(message); 31 | 32 | let status1 = agg_sig.verify(&kp.pk, message); 33 | let status2 = sig.verify(&kp.pk, message); 34 | 35 | assert!(status1, "Signature verification failed"); 36 | assert!(status2, "Aggregate signature verification failed"); 37 | assert_eq!(agg_sig, sig, "Signature not match"); 38 | } 39 | -------------------------------------------------------------------------------- /tests/test_operator_committee.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | use dvf::crypto::ThresholdSignature; 3 | use dvf::validation::operator::LocalOperator; 4 | use dvf::validation::OperatorCommittee; 5 | use ethereum_hashing::{Context, Sha256Context}; 6 | use futures::executor::block_on; 7 | use std::sync::Arc; 8 | use types::Hash256; 9 | 10 | #[cfg(feature = "fake_committee")] 11 | #[test] 12 | fn test_fake_operator_committee() { 13 | let t: usize = 5; 14 | let n: usize = 10; 15 | 16 | let mut m_threshold = ThresholdSignature::new(t); 17 | let (kp, kps, ids) = m_threshold.key_gen(n); 18 | 19 | let mut committee = OperatorCommittee::new(0, kp.pk.clone(), t); 20 | for i in 0..n { 21 | let operator = Arc::new(RwLock::new(LocalOperator::new( 22 | ids[i], 23 | Arc::new(kps[i].clone()), 24 | ))); 25 | committee.add_operator(ids[i], operator); 26 | } 27 | 28 | let message = "hello world"; 29 | let mut context = Context::new(); 30 | context.update(message.as_bytes()); 31 | let message = Hash256::from_slice(&context.finalize()); 32 | 33 | let sig1 = block_on(committee.sign(message)).unwrap(); 34 | let sig2 = kp.sk.sign(message); 35 | 36 | let status1 = sig1.verify(&kp.pk, message); 37 | let status2 = sig2.verify(&kp.pk, message); 38 | 39 | assert!(status1, "Signature verification failed"); 40 | assert!(status2, "Aggregate signature verification failed"); 41 | assert_eq!(sig1, sig2, "Signature not match"); 42 | } 43 | --------------------------------------------------------------------------------