Integrate BEEFY (#9833)

* Initial project setup and skeleton (#4)

* initial project setup for beefy gadget client

* update editorconfig

* update gitignore

* add initial skeleton for beefy gadget worker

* add skeleton for gossip processing

* add app crypto

* move around some code

* add basic flow for voting

* add logic for picking blocks to sign

* add rustfmt config

* add example node with beefy gadget

* use u32::next_power_of_two

* make maximum periodicity configurable

* add copyright header

* rename max_periodicity to min_interval

* CI stuff (#5)

* CI stuff.

* Fix workspace.

* cargo fmt --all

* Add license for beefy-gadget

* One toolchain to rule them all.

* Clippy.

* Fix clippy.

* Clippy in the runtime.

* Fix clippy grumbles.

* cargo fmt --all

* Primitives & Light Client examples (#8)

* Primitives.

* Docs.

* Document primitives.

* Simple tests.

* Light client examples.

* Fix stuff.

* cargo fmt --all

* Add a bunch of tests for imports.

* Add more examples.

* cargo fmt --all

* Fix clippy.

* cargo fmt --all

* Apply suggestions from code review

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

* Add GRANDPA / FG clarifications.

* Fix min number of signatures.

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

* Update to substrate master (#22)

* update to substrate master

* update dependencies

* fix clippy issues

Co-authored-by: Tomasz Drwięga <tomasz@parity.io>

* Add beefy pallet (#25)

* move beefy application crypto to primitives

* make primitives compile under no_std

* add beefy pallet that maintains authority set

* add beefy pallet to node example runtime

* tabify node-example cargo.toml files

* use double quotes in Cargo.toml files

* add missing hex-literal dependency

* add runtime api to fetch BEEFY authorities

* fix clippy warnings

* rename beefy-pallet to pallet-beefy

* sort dependencies in node-example/runtime/Cargo.toml

* Signed commitments rpc pubsub (#26)

* move beefy application crypto to primitives

* make primitives compile under no_std

* add beefy pallet that maintains authority set

* add beefy pallet to node example runtime

* tabify node-example cargo.toml files

* use double quotes in Cargo.toml files

* add missing hex-literal dependency

* add runtime api to fetch BEEFY authorities

* fix clippy warnings

* gadget: use commitment and signedcommitment

* gadget: send notifications for signed commitments

* gadget: add rpc pubsub for signed commitments

* node-example: enable beefy rpc

* gadget: fix clippy warnings

* rename beefy-pallet to pallet-beefy

* sort dependencies in node-example/runtime/Cargo.toml

* gadget: add documentation on SignedCommitment rpc wrapper type

* gadget: add todos about dummy beefy commitments

* gadget: remove redundant closure

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Integrate MMR and deposit root into the digest. (#24)

* Add basic MMR.

* Deposit digest item.

* cargo fmt --all

* Merge with primitives.

* cargo fmt --all

* Fix extra spaces.

* cargo fmt --all

* Switch branch.

* remove stray whitespace

* update to latest td-mmr commit

* fix clippy error

Co-authored-by: André Silva <andrerfosilva@gmail.com>

* use new mmr root as commitment payload (#27)

* use new mmr root as commitment payload

* fix mmr root codec index

* warn on MMR root digest not found

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* add type alias for MMR root hash

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Bump serde_json from 1.0.59 to 1.0.60 (#28)

* Update to latest substrate. (#32)

* Update to latest substrate.

* Fix tests.

* cargo fmt --all

* Switch to master.

* Bump serde from 1.0.117 to 1.0.118 (#29)

* Bump serde from 1.0.117 to 1.0.118

Bumps [serde](https://github.com/serde-rs/serde) from 1.0.117 to 1.0.118.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.117...v1.0.118)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

* Bump arc-swap.

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
Co-authored-by: Tomasz Drwięga <tomasz@parity.io>

* Remove transition flag (#35)

* Get rid of is_set_transition_flag

* Fix tests.

* cargo fmt --all

* Bump futures from 0.3.9 to 0.3.12 (#50)

* Bump log from 0.4.11 to 0.4.13 (#52)

* Bump Substrate and Deps (#57)

* Update README (#58)

* Update README

* Apply suggestions from code review

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* address review comments

* missed a typo

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Add validator set to the pallet. (#65)

* Bump Substrate and Deps (#71)

* Bump Substrate and Deps

* pin serde and syn

* bump Substrate again for '__Nonexhaustive' fix

* add cargo deny ignore

* Beefy pallet test (#74)

* setup mock

* test session change

* silence beefy

* clippy still

* no change - no log

* clippy again

* Apply suggestions from code review

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* code review changes, added additional test

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Beefy node cleanup (#75)

* bump serde

* bump substrate, scale-codec 2.0.0

* we need a proper beefy node

* rename primitives as well

* Sort members.

Co-authored-by: Tomasz Drwięga <tomasz@parity.io>

* Migrate beefy-pallet to FRAMEv2 (#76)

* migrate beefy-pallet to FRAMEv2

* Code review

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Run BEEFY worker as non-validator (#77)

* run BEEFY worker as non-validator

* don't check for roloe.is_authority

* change enum type name

* Bump Substrate and Deps (#79)

* Add BEEFY gadget as extra peer set (#80)

* Add BEEFY gadget as extra peer set

* use BEEFY protocol

* Add ValidatorSetId to BEEFY digest (#85)

* add ValidatorSetId to BEEFY digest

* apply review changes

* Bump Substrate and Deps (#91)

* Bump Substrate and Deps

* Bump Substrate again in order to include a hot-fix

* redo again

* use CryptoStore issue

* cargo fmt

* Bump serde_json from 1.0.63 to 1.0.64 (#93)

* Track BEEFY validator set (#94)

* Track BEEFY validator set

* Add validator_set_id to BeefyWorker

* Make validattor_set_id optional

* Ad 92 (#97)

* sign_commitment()

* Error handling todo

* Add error type (#99)

* Add error type

* Address review

* Extract worker and round logic (#104)

* Bump serde from 1.0.123 to 1.0.124 (#106)

* Rework BeefyAPI (#110)

* Initialize BeefyWorker with current validator set (#111)

* Update toolchain (#115)

* Use nightly toolchain

* dongradde to latest clippy stable

* GH workflow trail and error

* next try

* use stable for clippy

* update wasm builder

* yet another try

* fun with CI

* no env var

* and one more

* allow from_over_into bco contruct_runtime

* back to start

* well ...

* full circle

* old version was still used

* Bump Substrate and Deps (#117)

* Bump Substrate and Deps

* cargo fmt should enforce uniform imports

* merge some imports

* Delayed BEEFY worker initialization (#121)

* lifecycle state

* add Client convenience trait

* rework trait identifiers

* WIP

* rework BeefyWorker::new() signature

* Delayed BEEFY gadget initialization

* address review

* Bump substrate. (#123)

* Bump substrate.

* Fix tests.

* Lower log-level for a missing validator set (#124)

* lower log-level for a missing validator set

* move best_finalized_block initialization

* Setup Prometheus metrics (#125)

* setup Prometheus metrics

* expose validator set id

* cargo fmt

* Update beefy-gadget/src/lib.rs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* add vote messages gossiped metric

* track authorities change, before checking for MMR root digest

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Make Client convenience trait public (#126)

* Bump serde from 1.0.124 to 1.0.125 (#131)

* Reset rounds on new validator set. (#133)

* Re-set rounds on new validator set.

* Fix docs.

* Bump Substrate and Deps (#134)

* beefy: authority set changes fixes (#139)

* node: fix grandpa peers set config

* gadget: update best finalized number only when finalized with beefy

* gadget: process authorities changes regardless of vote status

* gadget: remove superfluous signature type (#140)

* node: fix grandpa peers set config

* gadget: update best finalized number only when finalized with beefy

* gadget: process authorities changes regardless of vote status

* gadget: remove superfluous signature type

Co-authored-by: Tomasz Drwięga <tomasz@parity.io>

* gadget: reduce gossip spam (#141)

* node: fix grandpa peers set config

* gadget: update best finalized number only when finalized with beefy

* gadget: process authorities changes regardless of vote status

* gadget: remove superfluous signature type

* gadget: only gossip last 5 rounds

* gadget: note round to gossip validator before gossiping message

* gadget: fix clippy warnings

* gadget: update docs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
Co-authored-by: adoerr <0xad@gmx.net>

* gadget: verify SignedCommitment message signature (#142)

* gadget: verify SignedCommitment message signature

* gadget: log messages with bad sigs

* gadget: move todo comment

* Bump futures from 0.3.13 to 0.3.14 (#145)

* Milestone 1 (#144)

* use best_finalized, prevent race

* make best_finalized_block an Option, should_vote_on bails on None

* Bump futures from 0.3.13 to 0.3.14

* Revert futures bump

* Revert "Revert futures bump"

This reverts commit a1b5e7e9bac526f2897ebfdfee7f02dd29a13ac5.

* Revert "Bump futures from 0.3.13 to 0.3.14"

This reverts commit a4e508b118ad2c4b52909d24143c284073961458.

* debug msg if the bail voting

* validator_set()

* local_id()

* get rid of worker state

* Apply review suggestions

* fix should_vote_on()

* Extract BeefyGossipValidator (#147)

* Extract BeefyGossipValidator

* Apply review suggestions

* Add block_delta parameter to start_beefy_gadget (#151)

* Add block_delta parameter

* rename to min_block_delta

* Add additional metrics (#152)

* Add additional metrics

* add skipped session metric

* add some comment for temp metric

* don't log under info for every concluded round (#156)

* don't log error on missing validator keys (#157)

* don't log error on missing validator keys

* remove unused import

* Fix validator set change handling (#158)

* reduce some logs from debug to trace

* fix validator set changes handling

* rename validator module to gossip

* run rustfmt

* Fix should_vote_on() (#160)

* Fix should_vote_on()

* by the textbook

* fix the algorithm

* Apply review suggestions

* don't use NumberFor in vote_target

Co-authored-by: André Silva <andrerfosilva@gmail.com>

* Make KeyStore optional (#173)

* Use builder pattern for NonDefaultSetConfig (#178)

Co-authored-by: adoerr <0xad@gmx.net>

* Append SignedCommitment to block justifications (#177)

* Append SignedCommitment

* add BeefyParams

* add WorkerParams

* use warn

* versioned variant for SignedCommitment

* Bump serde from 1.0.125 to 1.0.126 (#184)

Bumps [serde](https://github.com/serde-rs/serde) from 1.0.125 to 1.0.126.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.125...v1.0.126)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump strum from 0.20.0 to 0.21.0 (#195)

* Bump strum from 0.20.0 to 0.21.0

Bumps [strum](https://github.com/Peternator7/strum) from 0.20.0 to 0.21.0.
- [Release notes](https://github.com/Peternator7/strum/releases)
- [Changelog](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Peternator7/strum/commits)

---
updated-dependencies:
- dependency-name: strum
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* use dervie feature for strum; clippy and deny housekeeping

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: adoerr <0xad@gmx.net>

* Make concluded round an info log (#200)

* Remove external crypto trait bounds (#207)

* BeefyKeystore newtype

* WIP

* remove mod ecdsa

* WIP

* fix tests

* some polishing

* Rename AuthorityId to BeefyId to avoid type conflict in UI (#211)

* Add trace points; Reduce MAX_LIVE_GOSSIP_ROUNDS (#210)

* Add trace points; Reduce MAX_LIVE_GOSSIP_ROUNDS

* log local authority id

* Additional initial authority id's (#217)

* Scratch concluded rounds

* adjust testnet doc

* fix authority key typo

* We don't want no scratches

* address review comments

* Fix note_round() (#219)

* rename BeefyGossipValidator

* Fix note_round()

* use const for assert

* put message trace points back in

* test case note_same_round_twice()

* address review comments

* remove redundant check

* Use LocalKeystore for tests (#224)

* private_keys()

* Use LocalKeystore for tests

* Use keystore helper

* Address review

* some reformatting

* Cache known votes in gossip (#227)

* Implement known messages cache.

* Add tests.

* Appease clippy.

* More clippy

Co-authored-by: adoerr <0xad@gmx.net>

* Some key store sanity checks (#232)

* verify vote message

* verify_validator_set()

* rework logging

* some rework

* Tone down warnings.

* Add signature verification.

* Tone down more.

* Fix clippy

Co-authored-by: Tomasz Drwięga <tomasz@parity.io>

* Use Binary Merkle Tree instead of a trie (#225)

* Binary tree merkle root.

* Add proofs and verification.

* Clean up debug.

* Use BEEFY addresses instead of pubkeys.

* Use new merkle tree.

* Optimize allocations.

* Add test for larger trees.

* Add tests for larger cases.

* Appease clippy

* Appease clippy2.

* Fix proof generation & verification.

* Add more test data.

* Fix CLI.

* Update README

* Bump version.

* Update docs.

* Rename beefy-merkle-root to beefy-merkle-tree

Co-authored-by: adoerr <0xad@gmx.net>

* Bump Substrate and Deps (#235)

* BEEFY+MMR pallet (#236)

* Add MMR leaf format to primitives.

* Fix tests

* Initial work on the BEEFY-MMR pallet.

* Add tests to MMR pallet.

* Use eth addresses.

* Use binary merkle tree.

* Bump libsecp256k1

* Fix compilation.

* Bump deps.

* Appease cargo deny.

* Re-format.

* Module-level docs.

* no-std fix.

* update README

Co-authored-by: adoerr <0xad@gmx.net>

* Fix noting rounds for non-authorities (#238)

* Bump env_logger from 0.8.4 to 0.9.0 (#242)

Bumps [env_logger](https://github.com/env-logger-rs/env_logger) from 0.8.4 to 0.9.0.
- [Release notes](https://github.com/env-logger-rs/env_logger/releases)
- [Changelog](https://github.com/env-logger-rs/env_logger/blob/main/CHANGELOG.md)
- [Commits](https://github.com/env-logger-rs/env_logger/compare/v0.8.4...v0.9.0)

---
updated-dependencies:
- dependency-name: env_logger
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* gadget: add global timeout for rebroadcasting messages (#243)

* gadget: add global timeout for rebroadcasting messages

* update rustfmt.toml

* make message_allowed() a debug trace

Co-authored-by: adoerr <0xad@gmx.net>

* Bump Substrate and Deps (#245)

* Bump Substrate and Deps

* Bump Substrate again

* Bump futures from 0.3.15 to 0.3.16 (#247)

Bumps [futures](https://github.com/rust-lang/futures-rs) from 0.3.15 to 0.3.16.
- [Release notes](https://github.com/rust-lang/futures-rs/releases)
- [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.15...0.3.16)

---
updated-dependencies:
- dependency-name: futures
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump libsecp256k1 from 0.5.0 to 0.6.0 (#249)

* Bump libsecp256k1 from 0.5.0 to 0.6.0

Bumps [libsecp256k1](https://github.com/paritytech/libsecp256k1) from 0.5.0 to 0.6.0.
- [Release notes](https://github.com/paritytech/libsecp256k1/releases)
- [Changelog](https://github.com/paritytech/libsecp256k1/blob/master/CHANGELOG.md)
- [Commits](https://github.com/paritytech/libsecp256k1/commits)

---
updated-dependencies:
- dependency-name: libsecp256k1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* use correct crate name

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: adoerr <0xad@gmx.net>

* Derive `scale_info::TypeInfo` for types used in polkadot (#218)

* Add scale-info TypeInfo derives

* Update scale-info

* Add crates.io patches

* Use substrate aj-metadata-vnext branch

* Revert master branch substrate deps

* Add scale-info to beefy-pallet

* scale-info v0.9.0

* Remove github dependencies and patches

* More TypeInfo derives

* Update scale-info to 0.10.0

* Add missing scale-info dependency

* Add missing TypeInfo derive

* Hide TypeInfo under a feature.

Co-authored-by: Tomasz Drwięga <tomasz@parity.io>

* Bump serde from 1.0.126 to 1.0.127 (#260)

Bumps [serde](https://github.com/serde-rs/serde) from 1.0.126 to 1.0.127.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.126...v1.0.127)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump Substrate and Deps (#262)

* Update jsonrpc (#265)

* Update jsonrpc

* Update Substrate

* bump Substrate and Deps (#268)

* Bump serde from 1.0.127 to 1.0.128 (#272)

Bumps [serde](https://github.com/serde-rs/serde) from 1.0.127 to 1.0.128.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.127...v1.0.128)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix spelling (#271)

* Bump serde from 1.0.128 to 1.0.130 (#276)

Bumps [serde](https://github.com/serde-rs/serde) from 1.0.128 to 1.0.130.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.128...v1.0.130)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump scale-info from 0.10.0 to 0.12.0 (#275)

Bumps [scale-info](https://github.com/paritytech/scale-info) from 0.10.0 to 0.12.0.
- [Release notes](https://github.com/paritytech/scale-info/releases)
- [Changelog](https://github.com/paritytech/scale-info/blob/master/CHANGELOG.md)
- [Commits](https://github.com/paritytech/scale-info/commits)

---
updated-dependencies:
- dependency-name: scale-info
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: adoerr <0xad@gmx.net>

* Update to scale-info 1.0 (#278)

* bump substrate (#282)

* bump Substrate and Deps

* cargo fmt

Co-authored-by: Wenfeng Wang <kalot.wang@gmail.com>

* Update worker.rs (#287)

* Bump anyhow from 1.0.43 to 1.0.44 (#290)

* Bump anyhow from 1.0.43 to 1.0.44

Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.43 to 1.0.44.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.43...1.0.44)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* derive Default

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: adoerr <0xad@gmx.net>

* Remove optional `scale-info` feature (#292)

* Make scale-info dependency non-optional

* Remove feature gated TypeInfo derives

* Import TypeInfo

* Update substrate

* Fix up runtime

* prune .git suffix (#294)

* remove unused deps (#295)

* remove unused deps

* update lock file

* Bump libsecp256k1 from 0.6.0 to 0.7.0 (#296)

* Bump libsecp256k1 from 0.6.0 to 0.7.0

Bumps [libsecp256k1](https://github.com/paritytech/libsecp256k1) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/paritytech/libsecp256k1/releases)
- [Changelog](https://github.com/paritytech/libsecp256k1/blob/master/CHANGELOG.md)
- [Commits](https://github.com/paritytech/libsecp256k1/commits)

---
updated-dependencies:
- dependency-name: libsecp256k1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* update sec advisories

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: adoerr <0xad@gmx.net>

* clean compile

* use path dependencies

* beefy-gadget license header

* pallet-beefy license header

* pallet-beefy-mmr license header

* beefy-primitves license header

* carg fmt

* more formatting

* shorten line

* downgrade parity-scale-codec to 2.2.0

* use path dependency for Prometheus endpoint

* remove clippy annotations

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
Co-authored-by: Tomasz Drwięga <tomasz@parity.io>
Co-authored-by: André Silva <andrerfosilva@gmail.com>
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Andrew Jones <ascjones@gmail.com>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
Co-authored-by: drewstone <drewstone329@gmail.com>
Co-authored-by: Andronik Ordian <write@reusable.software>
Co-authored-by: Wenfeng Wang <kalot.wang@gmail.com>
Co-authored-by: Joshy Orndorff <JoshOrndorff@users.noreply.github.com>
Co-authored-by: Squirrel <gilescope@gmail.com>
This commit is contained in:
Andreas Doerr
2021-09-23 21:02:30 +02:00
committed by GitHub
parent 6845666c5c
commit 283c8daa81
31 changed files with 4992 additions and 12 deletions
@@ -0,0 +1,23 @@
[package]
name = "beefy-merkle-tree"
version = "4.0.0-dev"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "Apache-2.0"
description = "A no-std/Substrate compatible library to construct binary merkle tree."
[dependencies]
hex = { version = "0.4", optional = true, default-features = false }
log = { version = "0.4", optional = true, default-features = false }
tiny-keccak = { version = "2.0.2", features = ["keccak"], optional = true }
[dev-dependencies]
env_logger = "0.9"
hex = "0.4"
hex-literal = "0.3"
[features]
debug = ["hex", "log"]
default = ["std", "debug", "keccak"]
keccak = ["tiny-keccak"]
std = []
@@ -0,0 +1,806 @@
// This file is part of Substrate.
// Copyright (C) 2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
//! This crate implements a simple binary Merkle Tree utilities required for inter-op with Ethereum
//! bridge & Solidity contract.
//!
//! The implementation is optimised for usage within Substrate Runtime and supports no-std
//! compilation targets.
//!
//! Merkle Tree is constructed from arbitrary-length leaves, that are initially hashed using the
//! same [Hasher] as the inner nodes.
//! Inner nodes are created by concatenating child hashes and hashing again. The implementation
//! does not perform any sorting of the input data (leaves) nor when inner nodes are created.
//!
//! If the number of leaves is not even, last leave (hash of) is promoted to the upper layer.
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
/// Supported hashing output size.
///
/// The size is restricted to 32 bytes to allow for a more optimised implementation.
pub type Hash = [u8; 32];
/// Generic hasher trait.
///
/// Implement the function to support custom way of hashing data.
/// The implementation must return a [Hash] type, so only 32-byte output hashes are supported.
pub trait Hasher {
/// Hash given arbitrary-length piece of data.
fn hash(data: &[u8]) -> Hash;
}
#[cfg(feature = "keccak")]
mod keccak256 {
use tiny_keccak::{Hasher as _, Keccak};
/// Keccak256 hasher implementation.
pub struct Keccak256;
impl Keccak256 {
/// Hash given data.
pub fn hash(data: &[u8]) -> super::Hash {
<Keccak256 as super::Hasher>::hash(data)
}
}
impl super::Hasher for Keccak256 {
fn hash(data: &[u8]) -> super::Hash {
let mut keccak = Keccak::v256();
keccak.update(data);
let mut output = [0_u8; 32];
keccak.finalize(&mut output);
output
}
}
}
#[cfg(feature = "keccak")]
pub use keccak256::Keccak256;
/// Construct a root hash of a Binary Merkle Tree created from given leaves.
///
/// See crate-level docs for details about Merkle Tree construction.
///
/// In case an empty list of leaves is passed the function returns a 0-filled hash.
pub fn merkle_root<H, I, T>(leaves: I) -> Hash
where
H: Hasher,
I: IntoIterator<Item = T>,
T: AsRef<[u8]>,
{
let iter = leaves.into_iter().map(|l| H::hash(l.as_ref()));
merkelize::<H, _, _>(iter, &mut ())
}
fn merkelize<H, V, I>(leaves: I, visitor: &mut V) -> Hash
where
H: Hasher,
V: Visitor,
I: Iterator<Item = Hash>,
{
let upper = Vec::with_capacity(leaves.size_hint().0);
let mut next = match merkelize_row::<H, _, _>(leaves, upper, visitor) {
Ok(root) => return root,
Err(next) if next.is_empty() => return Hash::default(),
Err(next) => next,
};
let mut upper = Vec::with_capacity((next.len() + 1) / 2);
loop {
visitor.move_up();
match merkelize_row::<H, _, _>(next.drain(..), upper, visitor) {
Ok(root) => return root,
Err(t) => {
// swap collections to avoid allocations
upper = next;
next = t;
},
};
}
}
/// A generated merkle proof.
///
/// The structure contains all necessary data to later on verify the proof and the leaf itself.
#[derive(Debug, PartialEq, Eq)]
pub struct MerkleProof<T> {
/// Root hash of generated merkle tree.
pub root: Hash,
/// Proof items (does not contain the leaf hash, nor the root obviously).
///
/// This vec contains all inner node hashes necessary to reconstruct the root hash given the
/// leaf hash.
pub proof: Vec<Hash>,
/// Number of leaves in the original tree.
///
/// This is needed to detect a case where we have an odd number of leaves that "get promoted"
/// to upper layers.
pub number_of_leaves: usize,
/// Index of the leaf the proof is for (0-based).
pub leaf_index: usize,
/// Leaf content.
pub leaf: T,
}
/// A trait of object inspecting merkle root creation.
///
/// It can be passed to [`merkelize_row`] or [`merkelize`] functions and will be notified
/// about tree traversal.
trait Visitor {
/// We are moving one level up in the tree.
fn move_up(&mut self);
/// We are creating an inner node from given `left` and `right` nodes.
///
/// Note that in case of last odd node in the row `right` might be empty.
/// The method will also visit the `root` hash (level 0).
///
/// The `index` is an index of `left` item.
fn visit(&mut self, index: usize, left: &Option<Hash>, right: &Option<Hash>);
}
/// No-op implementation of the visitor.
impl Visitor for () {
fn move_up(&mut self) {}
fn visit(&mut self, _index: usize, _left: &Option<Hash>, _right: &Option<Hash>) {}
}
/// Construct a Merkle Proof for leaves given by indices.
///
/// The function constructs a (partial) Merkle Tree first and stores all elements required
/// to prove requested item (leaf) given the root hash.
///
/// Both the Proof and the Root Hash is returned.
///
/// # Panic
///
/// The function will panic if given [`leaf_index`] is greater than the number of leaves.
pub fn merkle_proof<H, I, T>(leaves: I, leaf_index: usize) -> MerkleProof<T>
where
H: Hasher,
I: IntoIterator<Item = T>,
I::IntoIter: ExactSizeIterator,
T: AsRef<[u8]>,
{
let mut leaf = None;
let iter = leaves.into_iter().enumerate().map(|(idx, l)| {
let hash = H::hash(l.as_ref());
if idx == leaf_index {
leaf = Some(l);
}
hash
});
/// The struct collects a proof for single leaf.
struct ProofCollection {
proof: Vec<Hash>,
position: usize,
}
impl ProofCollection {
fn new(position: usize) -> Self {
ProofCollection { proof: Default::default(), position }
}
}
impl Visitor for ProofCollection {
fn move_up(&mut self) {
self.position /= 2;
}
fn visit(&mut self, index: usize, left: &Option<Hash>, right: &Option<Hash>) {
// we are at left branch - right goes to the proof.
if self.position == index {
if let Some(right) = right {
self.proof.push(*right);
}
}
// we are at right branch - left goes to the proof.
if self.position == index + 1 {
if let Some(left) = left {
self.proof.push(*left);
}
}
}
}
let number_of_leaves = iter.len();
let mut collect_proof = ProofCollection::new(leaf_index);
let root = merkelize::<H, _, _>(iter, &mut collect_proof);
let leaf = leaf.expect("Requested `leaf_index` is greater than number of leaves.");
#[cfg(feature = "debug")]
log::debug!(
"[merkle_proof] Proof: {:?}",
collect_proof.proof.iter().map(hex::encode).collect::<Vec<_>>()
);
MerkleProof { root, proof: collect_proof.proof, number_of_leaves, leaf_index, leaf }
}
/// Leaf node for proof verification.
///
/// Can be either a value that needs to be hashed first,
/// or the hash itself.
#[derive(Debug, PartialEq, Eq)]
pub enum Leaf<'a> {
/// Leaf content.
Value(&'a [u8]),
/// Hash of the leaf content.
Hash(Hash),
}
impl<'a, T: AsRef<[u8]>> From<&'a T> for Leaf<'a> {
fn from(v: &'a T) -> Self {
Leaf::Value(v.as_ref())
}
}
impl<'a> From<Hash> for Leaf<'a> {
fn from(v: Hash) -> Self {
Leaf::Hash(v)
}
}
/// Verify Merkle Proof correctness versus given root hash.
///
/// The proof is NOT expected to contain leaf hash as the first
/// element, but only all adjacent nodes required to eventually by process of
/// concatenating and hashing end up with given root hash.
///
/// The proof must not contain the root hash.
pub fn verify_proof<'a, H, P, L>(
root: &'a Hash,
proof: P,
number_of_leaves: usize,
leaf_index: usize,
leaf: L,
) -> bool
where
H: Hasher,
P: IntoIterator<Item = Hash>,
L: Into<Leaf<'a>>,
{
if leaf_index >= number_of_leaves {
return false
}
let leaf_hash = match leaf.into() {
Leaf::Value(content) => H::hash(content),
Leaf::Hash(hash) => hash,
};
let mut combined = [0_u8; 64];
let mut position = leaf_index;
let mut width = number_of_leaves;
let computed = proof.into_iter().fold(leaf_hash, |a, b| {
if position % 2 == 1 || position + 1 == width {
combined[0..32].copy_from_slice(&b);
combined[32..64].copy_from_slice(&a);
} else {
combined[0..32].copy_from_slice(&a);
combined[32..64].copy_from_slice(&b);
}
let hash = H::hash(&combined);
#[cfg(feature = "debug")]
log::debug!(
"[verify_proof]: (a, b) {:?}, {:?} => {:?} ({:?}) hash",
hex::encode(a),
hex::encode(b),
hex::encode(hash),
hex::encode(combined)
);
position /= 2;
width = ((width - 1) / 2) + 1;
hash
});
root == &computed
}
/// Processes a single row (layer) of a tree by taking pairs of elements,
/// concatenating them, hashing and placing into resulting vector.
///
/// In case only one element is provided it is returned via `Ok` result, in any other case (also an
/// empty iterator) an `Err` with the inner nodes of upper layer is returned.
fn merkelize_row<H, V, I>(
mut iter: I,
mut next: Vec<Hash>,
visitor: &mut V,
) -> Result<Hash, Vec<Hash>>
where
H: Hasher,
V: Visitor,
I: Iterator<Item = Hash>,
{
#[cfg(feature = "debug")]
log::debug!("[merkelize_row]");
next.clear();
let mut index = 0;
let mut combined = [0_u8; 64];
loop {
let a = iter.next();
let b = iter.next();
visitor.visit(index, &a, &b);
#[cfg(feature = "debug")]
log::debug!(" {:?}\n {:?}", a.as_ref().map(hex::encode), b.as_ref().map(hex::encode));
index += 2;
match (a, b) {
(Some(a), Some(b)) => {
combined[0..32].copy_from_slice(&a);
combined[32..64].copy_from_slice(&b);
next.push(H::hash(&combined));
},
// Odd number of items. Promote the item to the upper layer.
(Some(a), None) if !next.is_empty() => {
next.push(a);
},
// Last item = root.
(Some(a), None) => return Ok(a),
// Finish up, no more items.
_ => {
#[cfg(feature = "debug")]
log::debug!(
"[merkelize_row] Next: {:?}",
next.iter().map(hex::encode).collect::<Vec<_>>()
);
return Err(next)
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
#[test]
fn should_generate_empty_root() {
// given
let _ = env_logger::try_init();
let data: Vec<[u8; 1]> = Default::default();
// when
let out = merkle_root::<Keccak256, _, _>(data);
// then
assert_eq!(
hex::encode(&out),
"0000000000000000000000000000000000000000000000000000000000000000"
);
}
#[test]
fn should_generate_single_root() {
// given
let _ = env_logger::try_init();
let data = vec![hex!("E04CC55ebEE1cBCE552f250e85c57B70B2E2625b")];
// when
let out = merkle_root::<Keccak256, _, _>(data);
// then
assert_eq!(
hex::encode(&out),
"aeb47a269393297f4b0a3c9c9cfd00c7a4195255274cf39d83dabc2fcc9ff3d7"
);
}
#[test]
fn should_generate_root_pow_2() {
// given
let _ = env_logger::try_init();
let data = vec![
hex!("E04CC55ebEE1cBCE552f250e85c57B70B2E2625b"),
hex!("25451A4de12dcCc2D166922fA938E900fCc4ED24"),
];
// when
let out = merkle_root::<Keccak256, _, _>(data);
// then
assert_eq!(
hex::encode(&out),
"697ea2a8fe5b03468548a7a413424a6292ab44a82a6f5cc594c3fa7dda7ce402"
);
}
#[test]
fn should_generate_root_complex() {
let _ = env_logger::try_init();
let test = |root, data| {
assert_eq!(hex::encode(&merkle_root::<Keccak256, _, _>(data)), root);
};
test(
"aff1208e69c9e8be9b584b07ebac4e48a1ee9d15ce3afe20b77a4d29e4175aa3",
vec!["a", "b", "c"],
);
test(
"b8912f7269068901f231a965adfefbc10f0eedcfa61852b103efd54dac7db3d7",
vec!["a", "b", "a"],
);
test(
"dc8e73fe6903148ff5079baecc043983625c23b39f31537e322cd0deee09fa9c",
vec!["a", "b", "a", "b"],
);
test(
"fb3b3be94be9e983ba5e094c9c51a7d96a4fa2e5d8e891df00ca89ba05bb1239",
vec!["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"],
);
}
#[test]
fn should_generate_and_verify_proof_simple() {
// given
let _ = env_logger::try_init();
let data = vec!["a", "b", "c"];
// when
let proof0 = merkle_proof::<Keccak256, _, _>(data.clone(), 0);
assert!(verify_proof::<Keccak256, _, _>(
&proof0.root,
proof0.proof.clone(),
data.len(),
proof0.leaf_index,
&proof0.leaf,
));
let proof1 = merkle_proof::<Keccak256, _, _>(data.clone(), 1);
assert!(verify_proof::<Keccak256, _, _>(
&proof1.root,
proof1.proof,
data.len(),
proof1.leaf_index,
&proof1.leaf,
));
let proof2 = merkle_proof::<Keccak256, _, _>(data.clone(), 2);
assert!(verify_proof::<Keccak256, _, _>(
&proof2.root,
proof2.proof,
data.len(),
proof2.leaf_index,
&proof2.leaf
));
// then
assert_eq!(hex::encode(proof0.root), hex::encode(proof1.root));
assert_eq!(hex::encode(proof2.root), hex::encode(proof1.root));
assert!(!verify_proof::<Keccak256, _, _>(
&hex!("fb3b3be94be9e983ba5e094c9c51a7d96a4fa2e5d8e891df00ca89ba05bb1239"),
proof0.proof,
data.len(),
proof0.leaf_index,
&proof0.leaf
));
assert!(!verify_proof::<Keccak256, _, _>(
&proof0.root,
vec![],
data.len(),
proof0.leaf_index,
&proof0.leaf
));
}
#[test]
fn should_generate_and_verify_proof_complex() {
// given
let _ = env_logger::try_init();
let data = vec!["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
for l in 0..data.len() {
// when
let proof = merkle_proof::<Keccak256, _, _>(data.clone(), l);
// then
assert!(verify_proof::<Keccak256, _, _>(
&proof.root,
proof.proof,
data.len(),
proof.leaf_index,
&proof.leaf
));
}
}
#[test]
fn should_generate_and_verify_proof_large() {
// given
let _ = env_logger::try_init();
let mut data = vec![];
for i in 1..16 {
for c in 'a'..'z' {
if c as usize % i != 0 {
data.push(c.to_string());
}
}
for l in 0..data.len() {
// when
let proof = merkle_proof::<Keccak256, _, _>(data.clone(), l);
// then
assert!(verify_proof::<Keccak256, _, _>(
&proof.root,
proof.proof,
data.len(),
proof.leaf_index,
&proof.leaf
));
}
}
}
#[test]
fn should_generate_and_verify_proof_large_tree() {
// given
let _ = env_logger::try_init();
let mut data = vec![];
for i in 0..6000 {
data.push(format!("{}", i));
}
for l in (0..data.len()).step_by(13) {
// when
let proof = merkle_proof::<Keccak256, _, _>(data.clone(), l);
// then
assert!(verify_proof::<Keccak256, _, _>(
&proof.root,
proof.proof,
data.len(),
proof.leaf_index,
&proof.leaf
));
}
}
#[test]
#[should_panic]
fn should_panic_on_invalid_leaf_index() {
let _ = env_logger::try_init();
merkle_proof::<Keccak256, _, _>(vec!["a"], 5);
}
#[test]
fn should_generate_and_verify_proof_on_test_data() {
let addresses = vec![
"0x9aF1Ca5941148eB6A3e9b9C741b69738292C533f",
"0xDD6ca953fddA25c496165D9040F7F77f75B75002",
"0x60e9C47B64Bc1C7C906E891255EaEC19123E7F42",
"0xfa4859480Aa6D899858DE54334d2911E01C070df",
"0x19B9b128470584F7209eEf65B69F3624549Abe6d",
"0xC436aC1f261802C4494504A11fc2926C726cB83b",
"0xc304C8C2c12522F78aD1E28dD86b9947D7744bd0",
"0xDa0C2Cba6e832E55dE89cF4033affc90CC147352",
"0xf850Fd22c96e3501Aad4CDCBf38E4AEC95622411",
"0x684918D4387CEb5E7eda969042f036E226E50642",
"0x963F0A1bFbb6813C0AC88FcDe6ceB96EA634A595",
"0x39B38ad74b8bCc5CE564f7a27Ac19037A95B6099",
"0xC2Dec7Fdd1fef3ee95aD88EC8F3Cd5bd4065f3C7",
"0x9E311f05c2b6A43C2CCF16fB2209491BaBc2ec01",
"0x927607C30eCE4Ef274e250d0bf414d4a210b16f0",
"0x98882bcf85E1E2DFF780D0eB360678C1cf443266",
"0xFBb50191cd0662049E7C4EE32830a4Cc9B353047",
"0x963854fc2C358c48C3F9F0A598B9572c581B8DEF",
"0xF9D7Bc222cF6e3e07bF66711e6f409E51aB75292",
"0xF2E3fd32D063F8bBAcB9e6Ea8101C2edd899AFe6",
"0x407a5b9047B76E8668570120A96d580589fd1325",
"0xEAD9726FAFB900A07dAd24a43AE941d2eFDD6E97",
"0x42f5C8D9384034A9030313B51125C32a526b6ee8",
"0x158fD2529Bc4116570Eb7C80CC76FEf33ad5eD95",
"0x0A436EE2E4dEF3383Cf4546d4278326Ccc82514E",
"0x34229A215db8FeaC93Caf8B5B255e3c6eA51d855",
"0xEb3B7CF8B1840242CB98A732BA464a17D00b5dDF",
"0x2079692bf9ab2d6dc7D79BBDdEE71611E9aA3B72",
"0x46e2A67e5d450e2Cf7317779f8274a2a630f3C9B",
"0xA7Ece4A5390DAB18D08201aE18800375caD78aab",
"0x15E1c0D24D62057Bf082Cb2253dA11Ef0d469570",
"0xADDEF4C9b5687Eb1F7E55F2251916200A3598878",
"0xe0B16Fb96F936035db2b5A68EB37D470fED2f013",
"0x0c9A84993feaa779ae21E39F9793d09e6b69B62D",
"0x3bc4D5148906F70F0A7D1e2756572655fd8b7B34",
"0xFf4675C26903D5319795cbd3a44b109E7DDD9fDe",
"0xCec4450569A8945C6D2Aba0045e4339030128a92",
"0x85f0584B10950E421A32F471635b424063FD8405",
"0xb38bEe7Bdc0bC43c096e206EFdFEad63869929E3",
"0xc9609466274Fef19D0e58E1Ee3b321D5C141067E",
"0xa08EA868cF75268E7401021E9f945BAe73872ecc",
"0x67C9Cb1A29E964Fe87Ff669735cf7eb87f6868fE",
"0x1B6BEF636aFcdd6085cD4455BbcC93796A12F6E2",
"0x46B37b243E09540b55cF91C333188e7D5FD786dD",
"0x8E719E272f62Fa97da93CF9C941F5e53AA09e44a",
"0xa511B7E7DB9cb24AD5c89fBb6032C7a9c2EfA0a5",
"0x4D11FDcAeD335d839132AD450B02af974A3A66f8",
"0xB8cf790a5090E709B4619E1F335317114294E17E",
"0x7f0f57eA064A83210Cafd3a536866ffD2C5eDCB3",
"0xC03C848A4521356EF800e399D889e9c2A25D1f9E",
"0xC6b03DF05cb686D933DD31fCa5A993bF823dc4FE",
"0x58611696b6a8102cf95A32c25612E4cEF32b910F",
"0x2ed4bC7197AEF13560F6771D930Bf907772DE3CE",
"0x3C5E58f334306be029B0e47e119b8977B2639eb4",
"0x288646a1a4FeeC560B349d210263c609aDF649a6",
"0xb4F4981E0d027Dc2B3c86afA0D0fC03d317e83C0",
"0xaAE4A87F8058feDA3971f9DEd639Ec9189aA2500",
"0x355069DA35E598913d8736E5B8340527099960b8",
"0x3cf5A0F274cd243C0A186d9fCBdADad089821B93",
"0xca55155dCc4591538A8A0ca322a56EB0E4aD03C4",
"0xE824D0268366ec5C4F23652b8eD70D552B1F2b8B",
"0x84C3e9B25AE8a9b39FF5E331F9A597F2DCf27Ca9",
"0xcA0018e278751De10d26539915d9c7E7503432FE",
"0xf13077dE6191D6c1509ac7E088b8BE7Fe656c28b",
"0x7a6bcA1ec9Db506e47ac6FD86D001c2aBc59C531",
"0xeA7f9A2A9dd6Ba9bc93ca615C3Ddf26973146911",
"0x8D0d8577e16F8731d4F8712BAbFa97aF4c453458",
"0xB7a7855629dF104246997e9ACa0E6510df75d0ea",
"0x5C1009BDC70b0C8Ab2e5a53931672ab448C17c89",
"0x40B47D1AfefEF5eF41e0789F0285DE7b1C31631C",
"0x5086933d549cEcEB20652CE00973703CF10Da373",
"0xeb364f6FE356882F92ae9314fa96116Cf65F47d8",
"0xdC4D31516A416cEf533C01a92D9a04bbdb85EE67",
"0x9b36E086E5A274332AFd3D8509e12ca5F6af918d",
"0xBC26394fF36e1673aE0608ce91A53B9768aD0D76",
"0x81B5AB400be9e563fA476c100BE898C09966426c",
"0x9d93C8ae5793054D28278A5DE6d4653EC79e90FE",
"0x3B8E75804F71e121008991E3177fc942b6c28F50",
"0xC6Eb5886eB43dD473f5BB4e21e56E08dA464D9B4",
"0xfdf1277b71A73c813cD0e1a94B800f4B1Db66DBE",
"0xc2ff2cCc98971556670e287Ff0CC39DA795231ad",
"0x76b7E1473f0D0A87E9B4a14E2B179266802740f5",
"0xA7Bc965660a6EF4687CCa4F69A97563163A3C2Ef",
"0xB9C2b47888B9F8f7D03dC1de83F3F55E738CebD3",
"0xEd400162E6Dd6bD2271728FFb04176bF770De94a",
"0xE3E8331156700339142189B6E555DCb2c0962750",
"0xbf62e342Bc7706a448EdD52AE871d9C4497A53b1",
"0xb9d7A1A111eed75714a0AcD2dd467E872eE6B03D",
"0x03942919DFD0383b8c574AB8A701d89fd4bfA69D",
"0x0Ef4C92355D3c8c7050DFeb319790EFCcBE6fe9e",
"0xA6895a3cf0C60212a73B3891948ACEcF1753f25E",
"0x0Ed509239DB59ef3503ded3d31013C983d52803A",
"0xc4CE8abD123BfAFc4deFf37c7D11DeCd5c350EE4",
"0x4A4Bf59f7038eDcd8597004f35d7Ee24a7Bdd2d3",
"0x5769E8e8A2656b5ed6b6e6fa2a2bFAeaf970BB87",
"0xf9E15cCE181332F4F57386687c1776b66C377060",
"0xc98f8d4843D56a46C21171900d3eE538Cc74dbb5",
"0x3605965B47544Ce4302b988788B8195601AE4dEd",
"0xe993BDfdcAac2e65018efeE0F69A12678031c71d",
"0x274fDf8801385D3FAc954BCc1446Af45f5a8304c",
"0xBFb3f476fcD6429F4a475bA23cEFdDdd85c6b964",
"0x806cD16588Fe812ae740e931f95A289aFb4a4B50",
"0xa89488CE3bD9C25C3aF797D1bbE6CA689De79d81",
"0xd412f1AfAcf0Ebf3Cd324593A231Fc74CC488B12",
"0xd1f715b2D7951d54bc31210BbD41852D9BF98Ed1",
"0xf65aD707c344171F467b2ADba3d14f312219cE23",
"0x2971a4b242e9566dEF7bcdB7347f5E484E11919B",
"0x12b113D6827E07E7D426649fBd605f427da52314",
"0x1c6CA45171CDb9856A6C9Dba9c5F1216913C1e97",
"0x11cC6ee1d74963Db23294FCE1E3e0A0555779CeA",
"0x8Aa1C721255CDC8F895E4E4c782D86726b068667",
"0xA2cDC1f37510814485129aC6310b22dF04e9Bbf0",
"0xCf531b71d388EB3f5889F1f78E0d77f6fb109767",
"0xBe703e3545B2510979A0cb0C440C0Fba55c6dCB5",
"0x30a35886F989db39c797D8C93880180Fdd71b0c8",
"0x1071370D981F60c47A9Cd27ac0A61873a372cBB2",
"0x3515d74A11e0Cb65F0F46cB70ecf91dD1712daaa",
"0x50500a3c2b7b1229c6884505D00ac6Be29Aecd0C",
"0x9A223c2a11D4FD3585103B21B161a2B771aDA3d1",
"0xd7218df03AD0907e6c08E707B15d9BD14285e657",
"0x76CfD72eF5f93D1a44aD1F80856797fBE060c70a",
"0x44d093cB745944991EFF5cBa151AA6602d6f5420",
"0x626516DfF43bf09A71eb6fd1510E124F96ED0Cde",
"0x6530824632dfe099304E2DC5701cA99E6d031E08",
"0x57e6c423d6a7607160d6379A0c335025A14DaFC0",
"0x3966D4AD461Ef150E0B10163C81E79b9029E69c3",
"0xF608aCfd0C286E23721a3c347b2b65039f6690F1",
"0xbfB8FAac31A25646681936977837f7740fCd0072",
"0xd80aa634a623a7ED1F069a1a3A28a173061705c7",
"0x9122a77B36363e24e12E1E2D73F87b32926D3dF5",
"0x62562f0d1cD31315bCCf176049B6279B2bfc39C2",
"0x48aBF7A2a7119e5675059E27a7082ba7F38498b2",
"0xb4596983AB9A9166b29517acD634415807569e5F",
"0x52519D16E20BC8f5E96Da6d736963e85b2adA118",
"0x7663893C3dC0850EfC5391f5E5887eD723e51B83",
"0x5FF323a29bCC3B5b4B107e177EccEF4272959e61",
"0xee6e499AdDf4364D75c05D50d9344e9daA5A9AdF",
"0x1631b0BD31fF904aD67dD58994C6C2051CDe4E75",
"0xbc208e9723D44B9811C428f6A55722a26204eEF2",
"0xe76103a222Ee2C7Cf05B580858CEe625C4dc00E1",
"0xC71Bb2DBC51760f4fc2D46D84464410760971B8a",
"0xB4C18811e6BFe564D69E12c224FFc57351f7a7ff",
"0xD11DB0F5b41061A887cB7eE9c8711438844C298A",
"0xB931269934A3D4432c084bAAc3d0de8143199F4f",
"0x070037cc85C761946ec43ea2b8A2d5729908A2a1",
"0x2E34aa8C95Ffdbb37f14dCfBcA69291c55Ba48DE",
"0x052D93e8d9220787c31d6D83f87eC7dB088E998f",
"0x498dAC6C69b8b9ad645217050054840f1D91D029",
"0xE4F7D60f9d84301e1fFFd01385a585F3A11F8E89",
"0xEa637992f30eA06460732EDCBaCDa89355c2a107",
"0x4960d8Da07c27CB6Be48a79B96dD70657c57a6bF",
"0x7e471A003C8C9fdc8789Ded9C3dbe371d8aa0329",
"0xd24265Cc10eecb9e8d355CCc0dE4b11C556E74D7",
"0xDE59C8f7557Af779674f41CA2cA855d571018690",
"0x2fA8A6b3b6226d8efC9d8f6EBDc73Ca33DDcA4d8",
"0xe44102664c6c2024673Ff07DFe66E187Db77c65f",
"0x94E3f4f90a5f7CBF2cc2623e66B8583248F01022",
"0x0383EdBbc21D73DEd039E9C1Ff6bf56017b4CC40",
"0x64C3E49898B88d1E0f0d02DA23E0c00A2Cd0cA99",
"0xF4ccfB67b938d82B70bAb20975acFAe402E812E1",
"0x4f9ee5829e9852E32E7BC154D02c91D8E203e074",
"0xb006312eF9713463bB33D22De60444Ba95609f6B",
"0x7Cbe76ef69B52110DDb2e3b441C04dDb11D63248",
"0x70ADEEa65488F439392B869b1Df7241EF317e221",
"0x64C0bf8AA36Ba590477585Bc0D2BDa7970769463",
"0xA4cDc98593CE52d01Fe5Ca47CB3dA5320e0D7592",
"0xc26B34D375533fFc4c5276282Fa5D660F3d8cbcB",
];
let root = hex!("72b0acd7c302a84f1f6b6cefe0ba7194b7398afb440e1b44a9dbbe270394ca53");
let data = addresses
.into_iter()
.map(|address| hex::decode(&address[2..]).unwrap())
.collect::<Vec<_>>();
for l in 0..data.len() {
// when
let proof = merkle_proof::<Keccak256, _, _>(data.clone(), l);
assert_eq!(hex::encode(&proof.root), hex::encode(&root));
assert_eq!(proof.leaf_index, l);
assert_eq!(&proof.leaf, &data[l]);
// then
assert!(verify_proof::<Keccak256, _, _>(
&proof.root,
proof.proof,
data.len(),
proof.leaf_index,
&proof.leaf
));
}
let proof = merkle_proof::<Keccak256, _, _>(data.clone(), data.len() - 1);
assert_eq!(
proof,
MerkleProof {
root,
proof: vec![
hex!("340bcb1d49b2d82802ddbcf5b85043edb3427b65d09d7f758fbc76932ad2da2f"),
hex!("ba0580e5bd530bc93d61276df7969fb5b4ae8f1864b4a28c280249575198ff1f"),
hex!("d02609d2bbdb28aa25f58b85afec937d5a4c85d37925bce6d0cf802f9d76ba79"),
hex!("ae3f8991955ed884613b0a5f40295902eea0e0abe5858fc520b72959bc016d4e"),
],
number_of_leaves: data.len(),
leaf_index: data.len() - 1,
leaf: hex!("c26B34D375533fFc4c5276282Fa5D660F3d8cbcB").to_vec(),
}
);
}
}