├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── CODEOWNERS ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE-APACHE2 ├── LICENSE-MIT ├── README.md ├── bounded-collections ├── CHANGELOG.md ├── Cargo.toml ├── README.md └── src │ ├── bounded_btree_map.rs │ ├── bounded_btree_set.rs │ ├── bounded_vec.rs │ ├── const_int.rs │ ├── lib.rs │ ├── test.rs │ └── weak_bounded_vec.rs ├── ethbloom ├── CHANGELOG.md ├── Cargo.toml ├── benches │ ├── bloom.rs │ └── unrolling.rs └── src │ └── lib.rs ├── ethereum-types ├── CHANGELOG.md ├── Cargo.toml ├── src │ ├── hash.rs │ ├── lib.rs │ └── uint.rs └── tests │ └── serde.rs ├── fixed-hash ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── benches │ └── cmp.rs └── src │ ├── hash.rs │ ├── lib.rs │ └── tests.rs ├── keccak-hash ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── benches │ └── keccak_256.rs └── src │ └── lib.rs ├── kvdb-memorydb ├── CHANGELOG.md ├── Cargo.toml └── src │ └── lib.rs ├── kvdb-rocksdb ├── CHANGELOG.md ├── Cargo.toml ├── benches │ ├── .gitignore │ └── bench_read_perf.rs ├── examples │ └── memtest.rs └── src │ ├── iter.rs │ ├── lib.rs │ └── stats.rs ├── kvdb-shared-tests ├── CHANGELOG.md ├── Cargo.toml └── src │ └── lib.rs ├── kvdb ├── CHANGELOG.md ├── Cargo.toml └── src │ ├── io_stats.rs │ └── lib.rs ├── license-header ├── parity-bytes ├── CHANGELOG.md ├── Cargo.toml ├── README.md └── src │ └── lib.rs ├── primitive-types ├── CHANGELOG.md ├── Cargo.toml ├── impls │ ├── codec │ │ ├── CHANGELOG.md │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── num-traits │ │ ├── CHANGELOG.md │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── rlp │ │ ├── CHANGELOG.md │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── serde │ │ ├── CHANGELOG.md │ │ ├── Cargo.toml │ │ ├── benches │ │ ├── impl_serde.rs │ │ └── input.rs │ │ └── src │ │ ├── lib.rs │ │ └── serialize.rs ├── src │ ├── fp_conversion.rs │ ├── json_schema.rs │ └── lib.rs └── tests │ ├── fp_conversion.rs │ ├── num_traits.rs │ └── scale_info.rs ├── rlp-derive ├── CHANGELOG.md ├── Cargo.toml ├── src │ ├── de.rs │ ├── en.rs │ └── lib.rs └── tests │ └── rlp.rs ├── rlp ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── benches │ └── rlp.rs ├── src │ ├── error.rs │ ├── impls.rs │ ├── lib.rs │ ├── rlpin.rs │ ├── stream.rs │ └── traits.rs └── tests │ └── tests.rs ├── rustfmt.toml └── uint ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── benches └── bigint.rs ├── examples └── modular.rs ├── fuzz ├── .gitignore ├── Cargo.toml ├── README.md └── fuzz_targets │ ├── div_mod.rs │ ├── div_mod_word.rs │ └── isqrt.rs ├── src ├── lib.rs └── uint.rs └── tests └── uint_tests.rs /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | indent_style=tab 4 | indent_size=tab 5 | tab_width=4 6 | end_of_line=lf 7 | charset=utf-8 8 | trim_trailing_whitespace=true 9 | max_line_length=120 10 | insert_final_newline=true 11 | 12 | [*.{yml,sh}] 13 | indent_style=space 14 | indent_size=2 15 | tab_width=8 16 | end_of_line=lf 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | labels: ["A2-insubstantial", "M5-dependencies"] 6 | schedule: 7 | interval: "daily" 8 | - package-ecosystem: github-actions 9 | directory: '/' 10 | labels: ["A2-insubstantial", "M5-dependencies"] 11 | schedule: 12 | interval: daily 13 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | push: 4 | branches: 5 | - master 6 | 7 | name: Continuous integration 8 | 9 | jobs: 10 | check: 11 | name: Check 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: actions-rs/toolchain@v1 16 | with: 17 | profile: minimal 18 | toolchain: stable 19 | override: true 20 | 21 | - run: sudo apt-get install libclang-dev 22 | 23 | - name: Rust Cache 24 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 25 | 26 | - uses: actions-rs/cargo@v1 27 | with: 28 | command: check 29 | args: --workspace --all-targets 30 | 31 | test: 32 | name: Test 33 | runs-on: ${{ matrix.os }} 34 | strategy: 35 | matrix: 36 | os: 37 | - ubuntu-latest 38 | - macOS-latest 39 | steps: 40 | - uses: actions/checkout@v4 41 | - uses: actions-rs/toolchain@v1 42 | with: 43 | profile: minimal 44 | toolchain: stable 45 | override: true 46 | 47 | - name: Install Clang (Ubuntu) 48 | if: ${{ runner.os == 'Linux' }} 49 | run: sudo apt-get install libclang-dev 50 | - name: Workaround macOS Clang 51 | if: ${{ runner.os == 'macOS' }} 52 | run: brew link llvm@15 53 | 54 | - name: Rust Cache 55 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 56 | 57 | - run: rustup target add wasm32-unknown-unknown 58 | 59 | - name: Test no-default-features 60 | uses: actions-rs/cargo@v1 61 | with: 62 | command: test 63 | args: --workspace --no-default-features 64 | 65 | - name: Test default features 66 | uses: actions-rs/cargo@v1 67 | with: 68 | command: test 69 | args: --workspace 70 | 71 | - name: Test uint 72 | uses: actions-rs/cargo@v1 73 | with: 74 | command: test 75 | args: -p uint --all-features 76 | 77 | - name: Test fixed-hash no_std 78 | run: cargo test -p fixed-hash --no-default-features --features='rustc-hex' 79 | 80 | - name: Test fixed-hash all-features 81 | uses: actions-rs/cargo@v1 82 | with: 83 | command: test 84 | args: -p fixed-hash --all-features 85 | 86 | - name: Test primitive-types no_std 87 | run: cargo test -p primitive-types --no-default-features --features='scale-info,num-traits,serde_no_std' 88 | 89 | - name: Test primitive-types all-features 90 | uses: actions-rs/cargo@v1 91 | with: 92 | command: test 93 | args: -p primitive-types --all-features 94 | 95 | - name: Build ethereum-types no_std 96 | run: cargo build -p ethereum-types --no-default-features --features='serialize,rlp' --target=wasm32-unknown-unknown 97 | 98 | - name: Test ethereum-types all-features 99 | uses: actions-rs/cargo@v1 100 | with: 101 | command: test 102 | args: -p ethereum-types --all-features 103 | 104 | - name: Test ethbloom all-features 105 | uses: actions-rs/cargo@v1 106 | with: 107 | command: test 108 | args: -p ethbloom --all-features 109 | 110 | - name: Test bounded-collections no_std 111 | uses: actions-rs/cargo@v1 112 | with: 113 | command: test 114 | args: -p bounded-collections --no-default-features 115 | 116 | - name: Test bounded-collections no_std,serde 117 | uses: actions-rs/cargo@v1 118 | with: 119 | command: test 120 | args: -p bounded-collections --no-default-features --features=serde 121 | 122 | - name: Test bounded-collections all-features 123 | uses: actions-rs/cargo@v1 124 | with: 125 | command: test 126 | args: -p bounded-collections --all-features 127 | 128 | test_windows: 129 | name: Test Windows 130 | runs-on: windows-latest 131 | steps: 132 | - uses: actions/checkout@v4 133 | - uses: actions-rs/toolchain@v1 134 | with: 135 | profile: minimal 136 | toolchain: stable 137 | override: true 138 | 139 | - name: Rust Cache 140 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 141 | 142 | - uses: actions-rs/cargo@v1 143 | with: 144 | command: test 145 | args: --workspace --exclude kvdb-rocksdb 146 | 147 | fmt: 148 | name: Rustfmt 149 | runs-on: ubuntu-latest 150 | steps: 151 | - uses: actions/checkout@v4 152 | - uses: actions-rs/toolchain@v1 153 | with: 154 | profile: minimal 155 | toolchain: nightly 156 | override: true 157 | - run: rustup component add rustfmt 158 | - uses: actions-rs/cargo@v1 159 | with: 160 | command: fmt 161 | args: --all -- --check 162 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | 3 | **/Cargo.lock 4 | 5 | **/*.rs.bk 6 | 7 | *.o 8 | *.so 9 | *.rlib 10 | *.dll 11 | .gdb_history 12 | 13 | *.exe 14 | 15 | .DS_Store 16 | 17 | .idea 18 | .vscode 19 | *.iml 20 | *.swp 21 | *.swo 22 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lists some code owners. 2 | # 3 | # A codeowner just oversees some part of the codebase. If an owned file is changed then the 4 | # corresponding codeowner receives a review request. An approval of the codeowner might be 5 | # required for merging a PR (depends on repository settings). 6 | # 7 | # For details about syntax, see: 8 | # https://help.github.com/en/articles/about-code-owners 9 | # But here are some important notes: 10 | # 11 | # - Glob syntax is git-like, e.g. `/core` means the core directory in the root, unlike `core` 12 | # which can be everywhere. 13 | # - Multiple owners are supported. 14 | # - Either handle (e.g, @github_user or @github_org/team) or email can be used. Keep in mind, 15 | # that handles might work better because they are more recognizable on GitHub, 16 | # eyou can use them for mentioning unlike an email. 17 | # - The latest matching rule, if multiple, takes precedence. 18 | 19 | # main codeowner 20 | 21 | # CI 22 | /.github/ @paritytech/ci 23 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to parity-common 2 | 3 | parity-common welcomes contribution from everyone in the form of suggestions, bug 4 | reports, pull requests, and feedback. This document gives some guidance if you 5 | are thinking of helping us. 6 | 7 | Please reach out here in a GitHub issue if we can do anything to help you contribute. 8 | 9 | ## Submitting bug reports and feature requests 10 | 11 | When reporting a bug or asking for help, please include enough details so that 12 | the people helping you can reproduce the behavior you are seeing. For some tips 13 | on how to approach this, read about how to produce a [Minimal, Complete, and 14 | Verifiable example]. 15 | 16 | [Minimal, Complete, and Verifiable example]: https://stackoverflow.com/help/mcve 17 | 18 | When making a feature request, please make it clear what problem you intend to 19 | solve with the feature, any ideas for how parity-common could support solving that problem, any possible alternatives, and any disadvantages. 20 | 21 | ## Versioning 22 | 23 | As many crates in the rust ecosystem, all crates in parity-common follow [semantic versioning]. This means bumping PATCH version on bug fixes that don't break backwards compatibility, MINOR version on new features and MAJOR version otherwise (MAJOR.MINOR.PATCH). Versions < 1.0 are considered to have the format 0.MAJOR.MINOR, which means bumping MINOR version for all non-breaking changes. 24 | 25 | For checking whether a change is SemVer-breaking, please refer to https://doc.rust-lang.org/cargo/reference/semver.html. 26 | 27 | Bumping versions should be done in a separate from regular code changes PR. 28 | 29 | [semantic versioning]: https://semver.org/ 30 | 31 | ## Releasing a new version 32 | 33 | This part of the guidelines is for parity-common maintainers. 34 | 35 | When making a new release make sure to follow these steps: 36 | * Submit a PR with a version bump and list all major and breaking changes in the crate's changelog 37 | 38 | After the PR is merged into master: 39 | * `cargo publish` on the latest master (try with `--dry-run` first) 40 | * Add a git tag in format `-v`, 41 | e.g. `git tag impl-serde-v0.2.2` and push it with `git push origin impl-serde-v0.2.2` 42 | 43 | ## Conduct 44 | 45 | We follow [Substrate Code of Conduct]. 46 | 47 | [Substrate Code of Conduct]: https://github.com/paritytech/substrate/blob/master/CODE_OF_CONDUCT.adoc 48 | 49 | ## Attribution 50 | 51 | This guideline is adapted from [Serde's CONTRIBUTING guide]. 52 | 53 | [Serde's CONTRIBUTING guide]: https://github.com/serde-rs/serde/blob/master/CONTRIBUTING.md 54 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace.package] 2 | authors = ["Parity Technologies "] 3 | edition = "2021" 4 | license = "MIT OR Apache-2.0" 5 | homepage = "https://github.com/paritytech/parity-common" 6 | repository = "https://github.com/paritytech/parity-common" 7 | 8 | [workspace] 9 | resolver = "2" 10 | members = [ 11 | "fixed-hash", 12 | "keccak-hash", 13 | "kvdb", 14 | "kvdb-memorydb", 15 | "kvdb-rocksdb", 16 | "kvdb-shared-tests", 17 | "parity-bytes", 18 | "rlp", 19 | "rlp-derive", 20 | "uint", 21 | "primitive-types", 22 | "bounded-collections", 23 | "ethereum-types", 24 | "ethbloom", 25 | ] 26 | 27 | [workspace.dependencies] 28 | serde_json = "1.0.41" 29 | criterion = "0.5.1" 30 | rand = { version = "0.8.0", default-features = false } 31 | hex-literal = "0.4.1" 32 | scale-info = { version = ">=1.0, <3", default-features = false } 33 | quickcheck = "1" 34 | rustc-hex = { version = "2.0.1", default-features = false } 35 | static_assertions = "1.0.0" 36 | arbitrary = "1.0" 37 | tiny-keccak = "2.0" 38 | crunchy = { version = "0.2.2", default-features = false } 39 | serde = { version = "1.0.101", default-features = false } 40 | scale-codec = { package = "parity-scale-codec", version = "3.7.4", default-features = false } 41 | jam-codec = { version = "0.1.0", default-features = false } 42 | log = { version = "0.4.17", default-features = false } 43 | schemars = ">=0.8.12" 44 | tempfile = "3.1.0" 45 | smallvec = "1.0.0" 46 | parking_lot = "0.12.0" 47 | num_cpus = "1.10.1" 48 | regex = "1.3.1" 49 | rocksdb = { version = "0.23.0", default-features = false } 50 | alloc_counter = "0.0.4" 51 | sysinfo = "0.30.13" 52 | ctrlc = "3.1.4" 53 | chrono = "0.4" 54 | num-traits = { version = "0.2", default-features = false } 55 | integer-sqrt = "0.1" 56 | bytes = { version = "1", default-features = false } 57 | syn = "2.0.72" 58 | quote = "1.0.2" 59 | proc-macro2 = "1.0.8" 60 | byteorder = { version = "1.4.2", default-features = false } 61 | hex = { version = "0.4", default-features = false } 62 | num-bigint = "0.4.0" 63 | rug = { version = "1.6.0", default-features = false } 64 | jsonschema = { version = "0.23", default-features = false } 65 | serde_derive = "1.0.101" 66 | 67 | ethbloom = { path = "./ethbloom", default-features = false } 68 | ethereum-types = { path = "./ethereum-types" } 69 | fixed-hash = { path = "./fixed-hash", default-features = false } 70 | uint = { path = "./uint", default-features = false } 71 | uint-crate = { path = "./uint", package = "uint", default-features = false } 72 | primitive-types = { path = "./primitive-types", default-features = false } 73 | impl-codec = { path = "./primitive-types/impls/codec", default-features = false } 74 | impl-num-traits = { path = "./primitive-types/impls/num-traits", default-features = false } 75 | impl-rlp = { path = "./primitive-types/impls/rlp", default-features = false } 76 | impl-serde = { path = "./primitive-types/impls/serde", default-features = false } 77 | kvdb = { path = "./kvdb" } 78 | kvdb-shared-tests = { path = "./kvdb-shared-tests" } 79 | keccak-hash = { path = "./keccak-hash" } 80 | rlp = { path = "./rlp" } 81 | rlp-derive = { path = "./rlp-derive" } 82 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2020 Parity Technologies 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Continuous integration](https://github.com/paritytech/parity-common/actions/workflows/ci.yml/badge.svg)](https://github.com/paritytech/parity-common/actions/workflows/ci.yml) 2 | 3 | # parity-common 4 | Collection of crates used in [Parity Technologies](https://www.paritytech.io/) projects 5 | -------------------------------------------------------------------------------- /bounded-collections/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [0.3.0] - 2025-05-21 8 | - Jam codec support [#914](https://github.com/paritytech/parity-common/pull/914) 9 | 10 | ## [0.2.4] - 2025-03-20 11 | - Implement DecodeWithMemTracking for BoundedBTreeMap [#906](https://github.com/paritytech/parity-common/pull/906) 12 | 13 | ## [0.2.3] - 2025-02-11 14 | - Implement DecodeWithMemTracking for some structs [#897](https://github.com/paritytech/parity-common/pull/897) 15 | 16 | ## [0.2.2] - 2024-11-08 17 | - Added `ConstInt` and `ConstUint` types. [#878](https://github.com/paritytech/parity-common/pull/878) 18 | 19 | ## [0.2.1] - 2024-10-08 20 | - Added `serde` support for `BoundedBTreeMap`. [#870](https://github.com/paritytech/parity-common/pull/870) 21 | 22 | ## [0.2.0] - 2024-01-29 23 | - Added `try_rotate_left` and `try_rotate_right` to `BoundedVec`. [#800](https://github.com/paritytech/parity-common/pull/800) 24 | 25 | ## [0.1.9] - 2023-10-10 26 | - Added `serde` support for `BoundedBTreeSet`. [#781](https://github.com/paritytech/parity-common/pull/781) 27 | 28 | ## [0.1.8] - 2023-06-11 29 | - Altered return types of `BoundedVec::force_insert_keep_` functions to return the element in case of error. 30 | - Added `new` and `clear` to `BoundedVec`. 31 | 32 | ## [0.1.7] - 2023-05-05 33 | - Added `serde` feature, which can be enabled for no `std` deployments. 34 | 35 | ## [0.1.6] - 2023-04-27 36 | - Added `Clone` and `Default` derive to the `impl_const_get!` macro and thereby all `Const*` types. 37 | - Fixed `Debug` impl for `impl_const_get!` and all `Const*` types to also print the value and not just the type name. 38 | 39 | ## [0.1.5] - 2023-02-13 40 | - Fixed `Hash` impl (previously it could not be used in practice, because the size bound was required to also implement `Hash`). 41 | 42 | ## [0.1.4] - 2023-01-28 43 | - Fixed unnecessary decoding and allocations for bounded types, when the decoded length is greater than the allowed bound. 44 | - Add `Hash` derivation (when `feature = "std"`) for bounded types. 45 | 46 | ## [0.1.3] - 2023-01-27 47 | - Removed non-existent `bounded` mod reference. [#715](https://github.com/paritytech/parity-common/pull/715) 48 | 49 | ## [0.1.2] - 2023-01-27 50 | - Ensured `bounded-collections` crate compiles under `no_std`. [#712](https://github.com/paritytech/parity-common/pull/712) 51 | 52 | ## [0.1.1] - 2023-01-26 53 | - Made `alloc` public. [#711](https://github.com/paritytech/parity-common/pull/711) 54 | - Removed a reference to `sp_core` in the comments. [#710](https://github.com/paritytech/parity-common/pull/710) 55 | 56 | ## [0.1.0] - 2023-01-26 57 | - Wrote better description for `bounded-collections`. [#709](https://github.com/paritytech/parity-common/pull/709) 58 | - Added `bounded-collections` crate. [#708](https://github.com/paritytech/parity-common/pull/708) 59 | -------------------------------------------------------------------------------- /bounded-collections/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bounded-collections" 3 | version = "0.3.0" 4 | description = "Bounded types and their supporting traits" 5 | readme = "README.md" 6 | rust-version = "1.79.0" 7 | authors.workspace = true 8 | edition.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | serde = { workspace = true, features = ["alloc", "derive"], optional = true } 15 | scale-codec = { workspace = true, default-features = false, features = ["max-encoded-len"], optional = true } 16 | scale-info = { workspace = true, features = ["derive"], optional = true } 17 | jam-codec = { workspace = true, features = ["derive","max-encoded-len"], optional = true } 18 | log = { workspace = true } 19 | schemars = { workspace = true, optional = true } 20 | 21 | [dev-dependencies] 22 | serde_json = { workspace = true } 23 | 24 | [features] 25 | default = ["std"] 26 | json-schema = ["dep:schemars"] 27 | std = [ 28 | "log/std", 29 | "jam-codec/std", 30 | "scale-codec/std", 31 | "scale-info/std", 32 | "serde/std", 33 | ] 34 | scale-codec = [ "scale-info" ] 35 | -------------------------------------------------------------------------------- /bounded-collections/README.md: -------------------------------------------------------------------------------- 1 | # Bounded Collections 2 | 3 | Bounded types and their supporting traits. -------------------------------------------------------------------------------- /bounded-collections/src/const_int.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) Parity Technologies (UK) Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use crate::{Get, TypedGet}; 10 | use core::marker::PhantomData; 11 | 12 | // Numbers which have constant upper and lower bounds. 13 | trait ConstBounded { 14 | const MIN: T; 15 | const MAX: T; 16 | } 17 | 18 | macro_rules! impl_const_bounded { 19 | ($bound:ty, $t:ty) => { 20 | impl ConstBounded<$bound> for $t { 21 | const MIN: $bound = <$t>::MIN as $bound; 22 | const MAX: $bound = <$t>::MAX as $bound; 23 | } 24 | }; 25 | } 26 | 27 | impl_const_bounded!(u128, u8); 28 | impl_const_bounded!(u128, u16); 29 | impl_const_bounded!(u128, u32); 30 | impl_const_bounded!(u128, u64); 31 | impl_const_bounded!(u128, u128); 32 | impl_const_bounded!(u128, usize); 33 | 34 | impl_const_bounded!(i128, i8); 35 | impl_const_bounded!(i128, i16); 36 | impl_const_bounded!(i128, i32); 37 | impl_const_bounded!(i128, i64); 38 | impl_const_bounded!(i128, i128); 39 | 40 | // Check whether a unsigned integer is within the bounds of a type. 41 | struct CheckOverflowU128, const N: u128>(PhantomData); 42 | 43 | impl, const N: u128> CheckOverflowU128 { 44 | const ASSERTION: () = assert!(N >= T::MIN && N <= T::MAX); 45 | } 46 | 47 | // Check whether an integer is within the bounds of a type. 48 | struct CheckOverflowI128, const N: i128>(PhantomData); 49 | 50 | impl, const N: i128> CheckOverflowI128 { 51 | const ASSERTION: () = assert!(N >= T::MIN && N <= T::MAX); 52 | } 53 | 54 | /// Const getter for unsigned integers. 55 | /// 56 | /// # Compile-time checks 57 | /// 58 | /// ```compile_fail 59 | /// # use bounded_collections::{ConstUint, Get}; 60 | /// let _ = as Get>::get(); 61 | /// ``` 62 | #[derive(Default, Clone)] 63 | pub struct ConstUint; 64 | 65 | impl core::fmt::Debug for ConstUint { 66 | fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { 67 | fmt.write_str(&alloc::format!("ConstUint<{}>", N)) 68 | } 69 | } 70 | 71 | impl TypedGet for ConstUint { 72 | type Type = u128; 73 | fn get() -> u128 { 74 | N 75 | } 76 | } 77 | 78 | /// Const getter for signed integers. 79 | #[derive(Default, Clone)] 80 | pub struct ConstInt; 81 | 82 | impl core::fmt::Debug for ConstInt { 83 | fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { 84 | fmt.write_str(&alloc::format!("ConstInt<{}>", N)) 85 | } 86 | } 87 | 88 | impl TypedGet for ConstInt { 89 | type Type = i128; 90 | fn get() -> i128 { 91 | N 92 | } 93 | } 94 | 95 | macro_rules! impl_const_int { 96 | ($t:ident, $check:ident, $bound:ty, $target:ty) => { 97 | impl Get<$target> for $t { 98 | fn get() -> $target { 99 | let _ = <$check<$target, N>>::ASSERTION; 100 | N as $target 101 | } 102 | } 103 | impl Get> for $t { 104 | fn get() -> Option<$target> { 105 | let _ = <$check<$target, N>>::ASSERTION; 106 | Some(N as $target) 107 | } 108 | } 109 | }; 110 | } 111 | 112 | impl_const_int!(ConstUint, CheckOverflowU128, u128, u8); 113 | impl_const_int!(ConstUint, CheckOverflowU128, u128, u16); 114 | impl_const_int!(ConstUint, CheckOverflowU128, u128, u32); 115 | impl_const_int!(ConstUint, CheckOverflowU128, u128, u64); 116 | impl_const_int!(ConstUint, CheckOverflowU128, u128, u128); 117 | impl_const_int!(ConstUint, CheckOverflowU128, u128, usize); 118 | 119 | impl_const_int!(ConstInt, CheckOverflowI128, i128, i8); 120 | impl_const_int!(ConstInt, CheckOverflowI128, i128, i16); 121 | impl_const_int!(ConstInt, CheckOverflowI128, i128, i32); 122 | impl_const_int!(ConstInt, CheckOverflowI128, i128, i64); 123 | impl_const_int!(ConstInt, CheckOverflowI128, i128, i128); 124 | 125 | #[cfg(test)] 126 | mod tests { 127 | use super::*; 128 | 129 | #[test] 130 | fn const_uint_works() { 131 | assert_eq!( as Get>::get(), 42); 132 | assert_eq!( as Get>>::get(), Some(42)); 133 | assert_eq!( as Get>::get(), 42); 134 | assert_eq!( as Get>::get(), 42); 135 | assert_eq!( as Get>::get(), 42); 136 | assert_eq!( as Get>::get(), 42); 137 | assert_eq!( as Get>::get(), 42); 138 | assert_eq!( as TypedGet>::get(), 42); 139 | // compile-time error 140 | // assert_eq!( as Get>::get() as u128, 256); 141 | } 142 | 143 | #[test] 144 | fn const_int_works() { 145 | assert_eq!( as Get>::get(), -42); 146 | assert_eq!( as Get>>::get(), Some(-42)); 147 | assert_eq!( as Get>::get(), -42); 148 | assert_eq!( as Get>::get(), -42); 149 | assert_eq!( as Get>::get(), -42); 150 | assert_eq!( as Get>::get(), -42); 151 | assert_eq!( as TypedGet>::get(), -42); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /bounded-collections/src/test.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Tests for the `bounded-collections` crate. 10 | 11 | #![cfg(test)] 12 | 13 | use crate::*; 14 | use core::fmt::Debug; 15 | 16 | #[test] 17 | #[allow(path_statements)] 18 | fn const_impl_default_clone_debug() { 19 | struct ImplsDefault(T); 20 | 21 | ImplsDefault::>; 22 | ImplsDefault::>; 23 | ImplsDefault::>; 24 | ImplsDefault::>; 25 | ImplsDefault::>; 26 | ImplsDefault::>; 27 | ImplsDefault::>; 28 | ImplsDefault::>; 29 | ImplsDefault::>; 30 | ImplsDefault::>; 31 | ImplsDefault::>; 32 | ImplsDefault::>; 33 | } 34 | 35 | #[test] 36 | #[cfg(feature = "std")] 37 | fn const_debug_fmt() { 38 | assert_eq!(format!("{:?}", ConstBool:: {}), "ConstBool"); 39 | assert_eq!(format!("{:?}", ConstBool:: {}), "ConstBool"); 40 | assert_eq!(format!("{:?}", ConstU8::<255> {}), "ConstU8<255>"); 41 | assert_eq!(format!("{:?}", ConstU16::<50> {}), "ConstU16<50>"); 42 | assert_eq!(format!("{:?}", ConstU32::<10> {}), "ConstU32<10>"); 43 | assert_eq!(format!("{:?}", ConstU64::<99> {}), "ConstU64<99>"); 44 | assert_eq!(format!("{:?}", ConstU128::<100> {}), "ConstU128<100>"); 45 | assert_eq!(format!("{:?}", ConstI8::<-127> {}), "ConstI8<-127>"); 46 | assert_eq!(format!("{:?}", ConstI16::<-50> {}), "ConstI16<-50>"); 47 | assert_eq!(format!("{:?}", ConstI32::<-10> {}), "ConstI32<-10>"); 48 | assert_eq!(format!("{:?}", ConstI64::<-99> {}), "ConstI64<-99>"); 49 | assert_eq!(format!("{:?}", ConstI128::<-100> {}), "ConstI128<-100>"); 50 | } 51 | -------------------------------------------------------------------------------- /ethbloom/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.14.1] - 2024-09-12 10 | - Updated `impl-serde` to 0.5. [#859](https://github.com/paritytech/parity-common/pull/859) 11 | - Updated `impl-codec` to 0.7. [#860](https://github.com/paritytech/parity-common/pull/860) 12 | 13 | ## [0.13.0] - 2022-09-20 14 | - Updated `fixed-hash` to 0.8. [#680](https://github.com/paritytech/parity-common/pull/680) 15 | 16 | ## [0.12.1] - 2022-02-07 17 | - Updated `scale-info` to ">=1.0, <3". [#627](https://github.com/paritytech/parity-common/pull/627) 18 | 19 | ## [0.12.0] - 2022-02-04 20 | ### Breaking 21 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 22 | - Updated `impl-codec` to 0.6. [#623](https://github.com/paritytech/parity-common/pull/623) 23 | 24 | ## [0.11.1] - 2021-09-30 25 | - Combined `scale-info` feature into `codec`. [#593](https://github.com/paritytech/parity-common/pull/593) 26 | 27 | ## [0.11.0] - 2021-01-27 28 | ### Breaking 29 | - Updated `impl-codec` to 0.5. [#510](https://github.com/paritytech/parity-common/pull/510) 30 | 31 | ### Potentially-breaking 32 | - `serialize` feature no longer pulls `std`. [#503](https://github.com/paritytech/parity-common/pull/503) 33 | 34 | ## [0.10.0] - 2021-01-05 35 | ### Breaking 36 | - Updated `rlp` to 0.5. [#463](https://github.com/paritytech/parity-common/pull/463) 37 | 38 | ## [0.9.2] - 2020-05-18 39 | - Added `codec` feature. [#393](https://github.com/paritytech/parity-common/pull/393) 40 | 41 | ## [0.9.1] - 2020-04-27 42 | - Added `arbitrary` feature. [#378](https://github.com/paritytech/parity-common/pull/378) 43 | 44 | ## [0.9.0] - 2020-03-16 45 | - Removed `libc` feature. [#317](https://github.com/paritytech/parity-common/pull/317) 46 | - License changed from MIT to dual MIT/Apache2. [#342](https://github.com/paritytech/parity-common/pull/342) 47 | 48 | ## [0.8.1] - 2019-10-24 49 | ### Dependencies 50 | - Updated dependencies. [#239](https://github.com/paritytech/parity-common/pull/239) 51 | -------------------------------------------------------------------------------- /ethbloom/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ethbloom" 3 | version = "0.14.1" 4 | description = "Ethereum bloom filter" 5 | rust-version = "1.56.1" 6 | authors.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | tiny-keccak = { workspace = true, features = ["keccak"] } 14 | crunchy = { workspace = true, features = ["limit_256"] } 15 | fixed-hash = { workspace = true } 16 | impl-serde = { workspace = true, optional = true } 17 | impl-rlp = { workspace = true, optional = true } 18 | impl-codec = { workspace = true, optional = true } 19 | scale-info = { workspace = true, features = ["derive"], optional = true } 20 | 21 | [dev-dependencies] 22 | criterion = { workspace = true } 23 | rand = { workspace = true, default-features = true } 24 | hex-literal = { workspace = true } 25 | 26 | [features] 27 | default = ["std", "rlp", "serialize", "rustc-hex"] 28 | std = ["fixed-hash/std", "crunchy/std"] 29 | serialize = ["impl-serde"] 30 | rustc-hex = ["fixed-hash/rustc-hex"] 31 | arbitrary = ["fixed-hash/arbitrary"] 32 | rlp = ["impl-rlp"] 33 | codec = ["impl-codec", "scale-info"] 34 | 35 | [[bench]] 36 | name = "bloom" 37 | path = "benches/bloom.rs" 38 | harness = false 39 | 40 | [[bench]] 41 | name = "unrolling" 42 | path = "benches/unrolling.rs" 43 | harness = false 44 | -------------------------------------------------------------------------------- /ethbloom/benches/bloom.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use criterion::{criterion_group, criterion_main, Criterion}; 10 | use ethbloom::{Bloom, Input}; 11 | use hex_literal::hex; 12 | use tiny_keccak::{Hasher, Keccak}; 13 | 14 | fn test_bloom() -> Bloom { 15 | use std::str::FromStr; 16 | Bloom::from_str( 17 | "00000000000000000000000000000000\ 18 | 00000000100000000000000000000000\ 19 | 00000000000000000000000000000000\ 20 | 00000000000000000000000000000000\ 21 | 00000000000000000000000000000000\ 22 | 00000000000000000000000000000000\ 23 | 00000002020000000000000000000000\ 24 | 00000000000000000000000800000000\ 25 | 10000000000000000000000000000000\ 26 | 00000000000000000000001000000000\ 27 | 00000000000000000000000000000000\ 28 | 00000000000000000000000000000000\ 29 | 00000000000000000000000000000000\ 30 | 00000000000000000000000000000000\ 31 | 00000000000000000000000000000000\ 32 | 00000000000000000000000000000000", 33 | ) 34 | .unwrap() 35 | } 36 | 37 | fn keccak256(input: &[u8]) -> [u8; 32] { 38 | let mut out = [0u8; 32]; 39 | let mut keccak256 = Keccak::v256(); 40 | keccak256.update(input); 41 | keccak256.finalize(&mut out); 42 | out 43 | } 44 | 45 | fn test_topic() -> Vec { 46 | hex!("02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").to_vec() 47 | } 48 | 49 | fn test_address() -> Vec { 50 | hex!("ef2d6d194084c2de36e0dabfce45d046b37d1106").to_vec() 51 | } 52 | 53 | fn test_dummy() -> Vec { 54 | b"123456".to_vec() 55 | } 56 | 57 | fn test_dummy2() -> Vec { 58 | b"654321".to_vec() 59 | } 60 | 61 | fn bench_accrue(c: &mut Criterion) { 62 | c.bench_function("accrue_raw", |b| { 63 | let mut bloom = Bloom::default(); 64 | let topic = test_topic(); 65 | let address = test_address(); 66 | b.iter(|| { 67 | bloom.accrue(Input::Raw(&topic)); 68 | bloom.accrue(Input::Raw(&address)); 69 | }) 70 | }); 71 | c.bench_function("accrue_hash", |b| { 72 | let mut bloom = Bloom::default(); 73 | let topic = keccak256(&test_topic()); 74 | let address = keccak256(&test_address()); 75 | b.iter(|| { 76 | bloom.accrue(Input::Hash(&topic)); 77 | bloom.accrue(Input::Hash(&address)); 78 | }) 79 | }); 80 | } 81 | 82 | fn bench_contains(c: &mut Criterion) { 83 | c.bench_function("contains_input_raw", |b| { 84 | let bloom = test_bloom(); 85 | let topic = test_topic(); 86 | let address = test_address(); 87 | b.iter(|| { 88 | assert!(bloom.contains_input(Input::Raw(&topic))); 89 | assert!(bloom.contains_input(Input::Raw(&address))); 90 | }) 91 | }); 92 | c.bench_function("contains_input_hash", |b| { 93 | let bloom = test_bloom(); 94 | let topic = keccak256(&test_topic()); 95 | let address = keccak256(&test_address()); 96 | b.iter(|| { 97 | assert!(bloom.contains_input(Input::Hash(&topic))); 98 | assert!(bloom.contains_input(Input::Hash(&address))); 99 | }) 100 | }); 101 | } 102 | 103 | fn bench_not_contains(c: &mut Criterion) { 104 | c.bench_function("does_not_contain_raw", |b| { 105 | let bloom = test_bloom(); 106 | let dummy = test_dummy(); 107 | let dummy2 = test_dummy2(); 108 | b.iter(|| { 109 | assert!(!bloom.contains_input(Input::Raw(&dummy))); 110 | assert!(!bloom.contains_input(Input::Raw(&dummy2))); 111 | }) 112 | }); 113 | c.bench_function("does_not_contain_hash", |b| { 114 | let bloom = test_bloom(); 115 | let dummy = keccak256(&test_dummy()); 116 | let dummy2 = keccak256(&test_dummy2()); 117 | b.iter(|| { 118 | assert!(!bloom.contains_input(Input::Hash(&dummy))); 119 | assert!(!bloom.contains_input(Input::Hash(&dummy2))); 120 | }) 121 | }); 122 | c.bench_function("does_not_contain_random_hash", |b| { 123 | let bloom = test_bloom(); 124 | let dummy: Vec<_> = (0..255u8).map(|i| keccak256(&[i])).collect(); 125 | b.iter(|| { 126 | for d in &dummy { 127 | assert!(!bloom.contains_input(Input::Hash(d))); 128 | } 129 | }) 130 | }); 131 | } 132 | 133 | criterion_group!(benches, bench_accrue, bench_contains, bench_not_contains); 134 | criterion_main!(benches); 135 | -------------------------------------------------------------------------------- /ethbloom/benches/unrolling.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use criterion::{criterion_group, criterion_main, Criterion}; 10 | use crunchy::unroll; 11 | use rand::RngCore; 12 | 13 | fn random_data() -> [u8; 256] { 14 | let mut res = [0u8; 256]; 15 | rand::thread_rng().fill_bytes(&mut res); 16 | res 17 | } 18 | 19 | fn bench_forwards(c: &mut Criterion) { 20 | c.bench_function("forwards_with_crunchy", |b| { 21 | let mut data = random_data(); 22 | b.iter(|| { 23 | let other_data = random_data(); 24 | unroll! { 25 | for i in 0..255 { 26 | data[i] |= other_data[i]; 27 | } 28 | } 29 | }); 30 | }); 31 | c.bench_function("forwards_without_crunchy", |b| { 32 | let mut data = random_data(); 33 | b.iter(|| { 34 | let other_data = random_data(); 35 | for i in 0..255 { 36 | data[i] |= other_data[i]; 37 | } 38 | }); 39 | }); 40 | } 41 | 42 | fn bench_backwards(c: &mut Criterion) { 43 | c.bench_function("backwards_with_crunchy", |b| { 44 | let mut data = random_data(); 45 | b.iter(|| { 46 | let other_data = random_data(); 47 | unroll! { 48 | for i in 0..255 { 49 | data[255-i] |= other_data[255-i]; 50 | } 51 | } 52 | }); 53 | }); 54 | c.bench_function("backwards_without_crunchy", |b| { 55 | let mut data = random_data(); 56 | b.iter(|| { 57 | let other_data = random_data(); 58 | for i in 0..255 { 59 | data[255 - i] |= other_data[255 - i]; 60 | } 61 | }); 62 | }); 63 | } 64 | 65 | criterion_group!(benches, bench_forwards, bench_backwards); 66 | criterion_main!(benches); 67 | -------------------------------------------------------------------------------- /ethereum-types/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.15.1] - 2024-09-12 10 | - Updated `uint` to 0.10. [#859](https://github.com/paritytech/parity-common/pull/859) 11 | 12 | ## [0.14.1] - 2022-11-29 13 | - Added `if_ethbloom` conditional macro. [#682](https://github.com/paritytech/parity-common/pull/682) 14 | 15 | ## [0.14.0] - 2022-09-20 16 | - Updated `fixed-hash` to 0.8. [#680](https://github.com/paritytech/parity-common/pull/680) 17 | - Updated `primitive-types` to 0.12. [#680](https://github.com/paritytech/parity-common/pull/680) 18 | - Updated `ethbloom` to 0.13. [#680](https://github.com/paritytech/parity-common/pull/680) 19 | - Made `ethbloom` optional. [#625](https://github.com/paritytech/parity-common/pull/625) 20 | 21 | ## [0.13.1] - 2022-02-07 22 | - Updated `scale-info` to ">=1.0, <3". [#627](https://github.com/paritytech/parity-common/pull/627) 23 | 24 | ## [0.13.0] - 2022-02-04 25 | ### Breaking 26 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 27 | - Updated `impl-codec` to 0.6. [#623](https://github.com/paritytech/parity-common/pull/623) 28 | - Updated `primitive-types` to 0.11. [#623](https://github.com/paritytech/parity-common/pull/623) 29 | - Updated `ethbloom` to 0.12. [#623](https://github.com/paritytech/parity-common/pull/623) 30 | 31 | ## [0.12.1] - 2021-09-30 32 | - Combined `scale-info` feature into `codec`. [#593](https://github.com/paritytech/parity-common/pull/593) 33 | 34 | ## [0.12.0] - 2021-07-02 35 | ### Breaking 36 | - Updated `primitive-types` to 0.10. [#556](https://github.com/paritytech/parity-common/pull/556) 37 | 38 | ## [0.11.0] - 2021-01-27 39 | ### Breaking 40 | - Updated `ethbloom` to 0.11. [#510](https://github.com/paritytech/parity-common/pull/510) 41 | - Updated `primitive-types` to 0.9. [#510](https://github.com/paritytech/parity-common/pull/510) 42 | - Updated `impl-codec` to 0.5. [#510](https://github.com/paritytech/parity-common/pull/510) 43 | 44 | ### Potentially-breaking 45 | - `serialize` feature no longer pulls `std`. [#503](https://github.com/paritytech/parity-common/pull/503) 46 | 47 | ## [0.10.0] - 2021-01-05 48 | ### Breaking 49 | - Updated `rlp` to 0.5. [#463](https://github.com/paritytech/parity-common/pull/463) 50 | - Updated `uint` to 0.9. [#486](https://github.com/paritytech/parity-common/pull/486) 51 | 52 | ## [0.9.2] - 2020-05-18 53 | - Added `codec` feature. [#393](https://github.com/paritytech/parity-common/pull/393) 54 | 55 | ## [0.9.1] - 2020-04-27 56 | - Added `arbitrary` feature. [#378](https://github.com/paritytech/parity-common/pull/378) 57 | 58 | ## [0.9.0] - 2020-03-16 59 | - License changed from MIT to dual MIT/Apache2. [#342](https://github.com/paritytech/parity-common/pull/342) 60 | - Updated dependencies. [#361](https://github.com/paritytech/parity-common/pull/361) 61 | 62 | ### Added 63 | - Uint error type is re-exported. [#244](https://github.com/paritytech/parity-common/pull/244) 64 | -------------------------------------------------------------------------------- /ethereum-types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ethereum-types" 3 | version = "0.15.1" 4 | description = "Ethereum types" 5 | rust-version = "1.60.0" 6 | authors.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | ethbloom = { workspace = true, optional = true } 14 | fixed-hash = { workspace = true, features = ["rustc-hex"] } 15 | uint-crate = { workspace = true } 16 | primitive-types = { workspace = true, features = ["rustc-hex"] } 17 | impl-serde = { workspace = true, optional = true } 18 | impl-rlp = { workspace = true, optional = true } 19 | impl-codec = { workspace = true, optional = true } 20 | scale-info = { workspace = true, features = ["derive"], optional = true } 21 | 22 | [dev-dependencies] 23 | serde_json = { workspace = true } 24 | 25 | [features] 26 | default = ["std", "ethbloom", "rlp", "serialize"] 27 | std = ["uint-crate/std", "fixed-hash/std", "ethbloom?/std", "primitive-types/std"] 28 | serialize = ["impl-serde", "primitive-types/serde_no_std", "ethbloom/serialize"] 29 | arbitrary = ["ethbloom/arbitrary", "fixed-hash/arbitrary", "uint-crate/arbitrary"] 30 | rlp = ["impl-rlp", "ethbloom/rlp", "primitive-types/rlp"] 31 | codec = ["impl-codec", "ethbloom/codec", "scale-info", "primitive-types/scale-info"] 32 | num-traits = ["primitive-types/num-traits"] 33 | rand = ["primitive-types/rand"] 34 | -------------------------------------------------------------------------------- /ethereum-types/src/hash.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use crate::{U128, U256, U512, U64}; 10 | use fixed_hash::*; 11 | #[cfg(feature = "codec")] 12 | use impl_codec::impl_fixed_hash_codec; 13 | #[cfg(feature = "rlp")] 14 | use impl_rlp::impl_fixed_hash_rlp; 15 | #[cfg(feature = "serialize")] 16 | use impl_serde::impl_fixed_hash_serde; 17 | 18 | pub trait BigEndianHash { 19 | type Uint; 20 | 21 | fn from_uint(val: &Self::Uint) -> Self; 22 | fn into_uint(&self) -> Self::Uint; 23 | } 24 | 25 | construct_fixed_hash! { pub struct H32(4); } 26 | #[cfg(feature = "rlp")] 27 | impl_fixed_hash_rlp!(H32, 4); 28 | #[cfg(feature = "serialize")] 29 | impl_fixed_hash_serde!(H32, 4); 30 | #[cfg(feature = "codec")] 31 | impl_fixed_hash_codec!(H32, 4); 32 | 33 | construct_fixed_hash! { 34 | #[cfg_attr(feature = "codec", derive(scale_info::TypeInfo))] 35 | pub struct H64(8); 36 | } 37 | #[cfg(feature = "rlp")] 38 | impl_fixed_hash_rlp!(H64, 8); 39 | #[cfg(feature = "serialize")] 40 | impl_fixed_hash_serde!(H64, 8); 41 | #[cfg(feature = "codec")] 42 | impl_fixed_hash_codec!(H64, 8); 43 | 44 | pub use primitive_types::{H128, H160, H256}; 45 | 46 | construct_fixed_hash! { 47 | #[cfg_attr(feature = "codec", derive(scale_info::TypeInfo))] 48 | pub struct H264(33); 49 | } 50 | #[cfg(feature = "rlp")] 51 | impl_fixed_hash_rlp!(H264, 33); 52 | #[cfg(feature = "serialize")] 53 | impl_fixed_hash_serde!(H264, 33); 54 | #[cfg(feature = "codec")] 55 | impl_fixed_hash_codec!(H264, 33); 56 | 57 | pub use primitive_types::H512; 58 | 59 | construct_fixed_hash! { 60 | #[cfg_attr(feature = "codec", derive(scale_info::TypeInfo))] 61 | pub struct H520(65); 62 | } 63 | #[cfg(feature = "rlp")] 64 | impl_fixed_hash_rlp!(H520, 65); 65 | #[cfg(feature = "serialize")] 66 | impl_fixed_hash_serde!(H520, 65); 67 | #[cfg(feature = "codec")] 68 | impl_fixed_hash_codec!(H520, 65); 69 | 70 | macro_rules! impl_uint_conversions { 71 | ($hash: ident, $uint: ident) => { 72 | impl BigEndianHash for $hash { 73 | type Uint = $uint; 74 | 75 | fn from_uint(value: &$uint) -> Self { 76 | let mut ret = $hash::zero(); 77 | value.write_as_big_endian(ret.as_bytes_mut()); 78 | ret 79 | } 80 | 81 | fn into_uint(&self) -> $uint { 82 | $uint::from_big_endian(self.as_ref() as &[u8]) 83 | } 84 | } 85 | }; 86 | } 87 | 88 | impl_uint_conversions!(H64, U64); 89 | impl_uint_conversions!(H128, U128); 90 | impl_uint_conversions!(H256, U256); 91 | impl_uint_conversions!(H512, U512); 92 | 93 | #[cfg(test)] 94 | mod tests { 95 | use super::{H160, H256}; 96 | use serde_json as ser; 97 | 98 | #[test] 99 | fn test_serialize_h160() { 100 | let tests = vec![ 101 | (H160::from_low_u64_be(0), "0x0000000000000000000000000000000000000000"), 102 | (H160::from_low_u64_be(2), "0x0000000000000000000000000000000000000002"), 103 | (H160::from_low_u64_be(15), "0x000000000000000000000000000000000000000f"), 104 | (H160::from_low_u64_be(16), "0x0000000000000000000000000000000000000010"), 105 | (H160::from_low_u64_be(1_000), "0x00000000000000000000000000000000000003e8"), 106 | (H160::from_low_u64_be(100_000), "0x00000000000000000000000000000000000186a0"), 107 | (H160::from_low_u64_be(u64::max_value()), "0x000000000000000000000000ffffffffffffffff"), 108 | ]; 109 | 110 | for (number, expected) in tests { 111 | assert_eq!(format!("{:?}", expected), ser::to_string_pretty(&number).unwrap()); 112 | assert_eq!(number, ser::from_str(&format!("{:?}", expected)).unwrap()); 113 | } 114 | } 115 | 116 | #[test] 117 | fn test_serialize_h256() { 118 | let tests = vec![ 119 | (H256::from_low_u64_be(0), "0x0000000000000000000000000000000000000000000000000000000000000000"), 120 | (H256::from_low_u64_be(2), "0x0000000000000000000000000000000000000000000000000000000000000002"), 121 | (H256::from_low_u64_be(15), "0x000000000000000000000000000000000000000000000000000000000000000f"), 122 | (H256::from_low_u64_be(16), "0x0000000000000000000000000000000000000000000000000000000000000010"), 123 | (H256::from_low_u64_be(1_000), "0x00000000000000000000000000000000000000000000000000000000000003e8"), 124 | (H256::from_low_u64_be(100_000), "0x00000000000000000000000000000000000000000000000000000000000186a0"), 125 | ( 126 | H256::from_low_u64_be(u64::max_value()), 127 | "0x000000000000000000000000000000000000000000000000ffffffffffffffff", 128 | ), 129 | ]; 130 | 131 | for (number, expected) in tests { 132 | assert_eq!(format!("{:?}", expected), ser::to_string_pretty(&number).unwrap()); 133 | assert_eq!(number, ser::from_str(&format!("{:?}", expected)).unwrap()); 134 | } 135 | } 136 | 137 | #[test] 138 | fn test_parse_0x() { 139 | assert!("0x0000000000000000000000000000000000000000000000000000000000000000" 140 | .parse::() 141 | .is_ok()) 142 | } 143 | 144 | #[test] 145 | fn test_serialize_invalid() { 146 | assert!(ser::from_str::("\"0x000000000000000000000000000000000000000000000000000000000000000\"") 147 | .unwrap_err() 148 | .is_data()); 149 | assert!(ser::from_str::("\"0x000000000000000000000000000000000000000000000000000000000000000g\"") 150 | .unwrap_err() 151 | .is_data()); 152 | assert!(ser::from_str::("\"0x00000000000000000000000000000000000000000000000000000000000000000\"") 153 | .unwrap_err() 154 | .is_data()); 155 | assert!(ser::from_str::("\"\"").unwrap_err().is_data()); 156 | assert!(ser::from_str::("\"0\"").unwrap_err().is_data()); 157 | assert!(ser::from_str::("\"10\"").unwrap_err().is_data()); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /ethereum-types/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | #![cfg_attr(not(feature = "std"), no_std)] 10 | 11 | mod hash; 12 | mod uint; 13 | 14 | #[cfg(feature = "ethbloom")] 15 | pub use ethbloom::{Bloom, BloomRef, Input as BloomInput}; 16 | pub use hash::{BigEndianHash, H128, H160, H256, H264, H32, H512, H520, H64}; 17 | pub use uint::{FromDecStrErr, FromStrRadixErr, FromStrRadixErrKind, U128, U256, U512, U64}; 18 | 19 | pub type Address = H160; 20 | pub type Secret = H256; 21 | pub type Public = H512; 22 | pub type Signature = H520; 23 | 24 | /// Conditional compilation depending on whether ethereum-types is built with ethbloom support. 25 | #[cfg(feature = "ethbloom")] 26 | #[macro_export] 27 | macro_rules! if_ethbloom { 28 | ($($tt:tt)*) => { 29 | $($tt)* 30 | }; 31 | } 32 | 33 | #[cfg(not(feature = "ethbloom"))] 34 | #[macro_export] 35 | #[doc(hidden)] 36 | macro_rules! if_ethbloom { 37 | ($($tt:tt)*) => {}; 38 | } 39 | -------------------------------------------------------------------------------- /ethereum-types/tests/serde.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use ethereum_types::{H160, H256, U256, U512}; 10 | use serde_json as ser; 11 | 12 | macro_rules! test { 13 | ($name: ident, $test_name: ident) => { 14 | #[test] 15 | fn $test_name() { 16 | let tests = vec![ 17 | ($name::from(0), "0x0"), 18 | ($name::from(1), "0x1"), 19 | ($name::from(2), "0x2"), 20 | ($name::from(10), "0xa"), 21 | ($name::from(15), "0xf"), 22 | ($name::from(15), "0xf"), 23 | ($name::from(16), "0x10"), 24 | ($name::from(1_000), "0x3e8"), 25 | ($name::from(100_000), "0x186a0"), 26 | ($name::from(u64::max_value()), "0xffffffffffffffff"), 27 | ($name::from(u64::max_value()) + $name::from(1u64), "0x10000000000000000"), 28 | ]; 29 | 30 | for (number, expected) in tests { 31 | assert_eq!(format!("{:?}", expected), ser::to_string_pretty(&number).unwrap()); 32 | assert_eq!(number, ser::from_str(&format!("{:?}", expected)).unwrap()); 33 | } 34 | 35 | let tests = vec![ 36 | ($name::from(0), "0"), 37 | ($name::from(1), "1"), 38 | ($name::from(2), "2"), 39 | ($name::from(10), "a"), 40 | ($name::from(15), "f"), 41 | ($name::from(15), "f"), 42 | ($name::from(16), "10"), 43 | ($name::from(1_000), "3e8"), 44 | ($name::from(100_000), "186a0"), 45 | ($name::from(u64::max_value()), "ffffffffffffffff"), 46 | ($name::from(u64::max_value()) + $name::from(1u64), "10000000000000000"), 47 | ]; 48 | 49 | for (number, expected) in tests { 50 | assert_eq!(format!("{:?}", "0x".to_string() + expected), ser::to_string_pretty(&number).unwrap()); 51 | assert_eq!(number, ser::from_str(&format!("{:?}", expected)).unwrap()); 52 | } 53 | 54 | // Invalid examples 55 | assert!(ser::from_str::<$name>("\"0x\"").unwrap_err().is_data()); 56 | assert!(ser::from_str::<$name>("\"0xg\"").unwrap_err().is_data()); 57 | assert!(ser::from_str::<$name>("\"\"").unwrap_err().is_data()); 58 | } 59 | }; 60 | } 61 | 62 | test!(U256, test_u256); 63 | test!(U512, test_u512); 64 | 65 | #[test] 66 | fn test_large_values() { 67 | assert_eq!( 68 | ser::to_string_pretty(&!U256::zero()).unwrap(), 69 | "\"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"" 70 | ); 71 | assert!(ser::from_str::("\"0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"") 72 | .unwrap_err() 73 | .is_data()); 74 | } 75 | 76 | #[test] 77 | fn test_h160() { 78 | let tests = vec![ 79 | (H160::from_low_u64_be(0), "0x0000000000000000000000000000000000000000"), 80 | (H160::from_low_u64_be(2), "0x0000000000000000000000000000000000000002"), 81 | (H160::from_low_u64_be(15), "0x000000000000000000000000000000000000000f"), 82 | (H160::from_low_u64_be(16), "0x0000000000000000000000000000000000000010"), 83 | (H160::from_low_u64_be(1_000), "0x00000000000000000000000000000000000003e8"), 84 | (H160::from_low_u64_be(100_000), "0x00000000000000000000000000000000000186a0"), 85 | (H160::from_low_u64_be(u64::max_value()), "0x000000000000000000000000ffffffffffffffff"), 86 | ]; 87 | 88 | for (number, expected) in tests { 89 | assert_eq!(format!("{:?}", expected), ser::to_string_pretty(&number).unwrap()); 90 | assert_eq!(number, ser::from_str(&format!("{:?}", expected)).unwrap()); 91 | } 92 | } 93 | 94 | #[test] 95 | fn test_h256() { 96 | let tests = vec![ 97 | (H256::from_low_u64_be(0), "0x0000000000000000000000000000000000000000000000000000000000000000"), 98 | (H256::from_low_u64_be(2), "0x0000000000000000000000000000000000000000000000000000000000000002"), 99 | (H256::from_low_u64_be(15), "0x000000000000000000000000000000000000000000000000000000000000000f"), 100 | (H256::from_low_u64_be(16), "0x0000000000000000000000000000000000000000000000000000000000000010"), 101 | (H256::from_low_u64_be(1_000), "0x00000000000000000000000000000000000000000000000000000000000003e8"), 102 | (H256::from_low_u64_be(100_000), "0x00000000000000000000000000000000000000000000000000000000000186a0"), 103 | (H256::from_low_u64_be(u64::max_value()), "0x000000000000000000000000000000000000000000000000ffffffffffffffff"), 104 | ]; 105 | 106 | for (number, expected) in tests { 107 | assert_eq!(format!("{:?}", expected), ser::to_string_pretty(&number).unwrap()); 108 | assert_eq!(number, ser::from_str(&format!("{:?}", expected)).unwrap()); 109 | } 110 | } 111 | 112 | #[test] 113 | fn test_invalid() { 114 | assert!(ser::from_str::("\"0x000000000000000000000000000000000000000000000000000000000000000\"") 115 | .unwrap_err() 116 | .is_data()); 117 | assert!(ser::from_str::("\"0x000000000000000000000000000000000000000000000000000000000000000g\"") 118 | .unwrap_err() 119 | .is_data()); 120 | assert!(ser::from_str::("\"0x00000000000000000000000000000000000000000000000000000000000000000\"") 121 | .unwrap_err() 122 | .is_data()); 123 | assert!(ser::from_str::("\"\"").unwrap_err().is_data()); 124 | assert!(ser::from_str::("\"0\"").unwrap_err().is_data()); 125 | assert!(ser::from_str::("\"10\"").unwrap_err().is_data()); 126 | } 127 | 128 | #[test] 129 | fn test_invalid_char_with_prefix() { 130 | const INVALID_STR: &str = "\"0x000000000000000000000000000000000000000000000000000000000000000g\""; 131 | const EXPECTED_MSG: &str = "invalid hex character: g, at 65 at line 1 column 68"; 132 | assert_eq!(ser::from_str::(INVALID_STR).unwrap_err().to_string(), EXPECTED_MSG); 133 | } 134 | 135 | #[test] 136 | fn test_invalid_char_without_prefix() { 137 | const INVALID_STR: &str = "\"000000000000000000000000000000000000000000000000000000000000000g\""; 138 | const EXPECTED_MSG: &str = "invalid hex character: g, at 63 at line 1 column 66"; 139 | assert_eq!(ser::from_str::(INVALID_STR).unwrap_err().to_string(), EXPECTED_MSG); 140 | } 141 | -------------------------------------------------------------------------------- /fixed-hash/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | ### Breaking 9 | - removed `byteorder` feature [#872](https://github.com/paritytech/parity-common/pull/872) 10 | 11 | ## [0.8.0] - 2022-09-20 12 | ### Breaking 13 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 14 | - Updated `arbitrary` to 1.0. [#530](https://github.com/paritytech/parity-common/pull/530) 15 | - Updated `quickcheck` to 1.0. [#674](https://github.com/paritytech/parity-common/pull/674) 16 | 17 | ## [0.7.0] - 2021-01-05 18 | ### Breaking 19 | - Updated `rand` to 0.8. [#488](https://github.com/paritytech/parity-common/pull/488) 20 | 21 | ## [0.6.1] - 2020-04-27 22 | - Added `arbitrary` feature. [#378](https://github.com/paritytech/parity-common/pull/378) 23 | 24 | ## [0.6.0] - 2020-03-16 25 | - Removed `libc` feature. [#317](https://github.com/paritytech/parity-common/pull/317) 26 | - License changed from MIT to dual MIT/Apache2. [#342](https://github.com/paritytech/parity-common/pull/342) 27 | 28 | ## [0.5.2] - 2019-12-19 29 | ### Fixed 30 | - Re-export `alloc` for both std and no-std to fix compilation. [#268](https://github.com/paritytech/parity-common/pull/268) 31 | 32 | ## [0.5.1] - 2019-10-24 33 | ### Dependencies 34 | - Updated dependencies. [#239](https://github.com/paritytech/parity-common/pull/239) 35 | -------------------------------------------------------------------------------- /fixed-hash/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fixed-hash" 3 | version = "0.8.0" 4 | description = "Macros to define custom fixed-size hash types" 5 | readme = "README.md" 6 | rust-version = "1.60" 7 | authors.workspace = true 8 | edition.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | 13 | [package.metadata.docs.rs] 14 | features = ["quickcheck", "api-dummy"] 15 | 16 | [dependencies] 17 | quickcheck = { workspace = true, optional = true } 18 | rand = { workspace = true, optional = true } 19 | rustc-hex = { workspace = true, optional = true } 20 | static_assertions = { workspace = true } 21 | arbitrary = { workspace = true, optional = true } 22 | 23 | [dev-dependencies] 24 | criterion = { workspace = true } 25 | rand = { workspace = true, default-features = false, features = ["std_rng"] } 26 | 27 | [features] 28 | default = ["std", "rand", "rustc-hex"] 29 | std = ["rustc-hex/std", "rand?/std"] 30 | 31 | api-dummy = [] # Feature used by docs.rs to display documentation of hash types 32 | 33 | [[bench]] 34 | name = "cmp" 35 | harness = false 36 | -------------------------------------------------------------------------------- /fixed-hash/README.md: -------------------------------------------------------------------------------- 1 | # Fixed Hash 2 | 3 | Provides macros to construct custom fixed-size hash types. 4 | 5 | ## Examples 6 | 7 | Simple 256 bit (32 bytes) hash type. 8 | 9 | ```rust 10 | use fixed_hash::construct_fixed_hash; 11 | 12 | construct_fixed_hash! { 13 | /// My 256 bit hash type. 14 | pub struct H256(32); 15 | } 16 | ``` 17 | 18 | Opt-in to add conversions between differently sized hashes. 19 | 20 | ```rust 21 | construct_fixed_hash!{ struct H256(32); } 22 | construct_fixed_hash!{ struct H160(20); } 23 | // auto-implement conversions between H256 and H160 24 | impl_fixed_hash_conversions!(H256, H160); 25 | // now use the generated conversions 26 | assert_eq!(H256::from(H160::zero()), H256::zero()); 27 | assert_eq!(H160::from(H256::zero()), H160::zero()); 28 | ``` 29 | 30 | It is possible to add attributes to your types, for example to make them serializable. 31 | 32 | ```rust 33 | construct_fixed_hash!{ 34 | /// My serializable hash type. 35 | #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] 36 | struct H160(20); 37 | } 38 | ``` 39 | 40 | ## Features 41 | 42 | By default this is an standard library depending crate. 43 | For a `#[no_std]` environment use it as follows: 44 | 45 | ``` 46 | fixed-hash = { version = "0.3", default-features = false } 47 | ``` 48 | 49 | ### Available Features 50 | 51 | - `std`: Use the standard library instead of the core library. 52 | - Using this feature enables the following features 53 | - `rustc-hex/std` 54 | - `rand/std` 55 | - Enabled by default. 56 | - `rand`: Provide API based on the `rand` crate. 57 | - Enabled by default. 58 | - `quickcheck`: Provide `quickcheck` implementation for hash types. 59 | - Disabled by default. 60 | - `arbitrary`: Allow for creation of a hash from random unstructured input. 61 | - Disabled by default. 62 | - `api-dummy`: Generate a dummy hash type for API documentation. 63 | - Enabled by default at `docs.rs` 64 | -------------------------------------------------------------------------------- /fixed-hash/benches/cmp.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Benchmarks for fixed-hash cmp implementation. 10 | 11 | use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; 12 | 13 | use fixed_hash::construct_fixed_hash; 14 | 15 | construct_fixed_hash! { pub struct H256(32); } 16 | 17 | criterion_group!(cmp, eq_equal, eq_nonequal, compare); 18 | criterion_main!(cmp); 19 | 20 | fn eq_equal(c: &mut Criterion) { 21 | let mut group = c.benchmark_group("eq_self"); 22 | for input in [ 23 | H256::zero(), 24 | H256::repeat_byte(0xAA), 25 | H256::from([ 26 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 0x84, 27 | 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, 28 | ]), 29 | H256([u8::MAX; 32]), 30 | ] { 31 | group.bench_with_input(BenchmarkId::from_parameter(input), &input, |b, x| { 32 | b.iter(|| black_box(x.eq(black_box(x)))) 33 | }); 34 | } 35 | group.finish(); 36 | } 37 | 38 | fn eq_nonequal(c: &mut Criterion) { 39 | let mut group = c.benchmark_group("eq_nonequal"); 40 | for input in [ 41 | ( 42 | H256::zero(), 43 | H256::from([ 44 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 45 | ]), 46 | ), 47 | (H256::repeat_byte(0xAA), H256::repeat_byte(0xA1)), 48 | ( 49 | H256::from([ 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 51 | 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, 52 | ]), 53 | H256::from([ 54 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 55 | 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, 56 | ]), 57 | ), 58 | ] { 59 | group.bench_with_input(BenchmarkId::from_parameter(input.0), &input, |b, (x, y)| { 60 | b.iter(|| black_box(x.eq(black_box(y)))) 61 | }); 62 | } 63 | group.finish(); 64 | } 65 | 66 | fn compare(c: &mut Criterion) { 67 | let mut group = c.benchmark_group("compare"); 68 | for input in [ 69 | ( 70 | H256::zero(), 71 | H256::from([ 72 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 73 | ]), 74 | ), 75 | (H256::zero(), H256::zero()), 76 | (H256::repeat_byte(0xAA), H256::repeat_byte(0xAA)), 77 | (H256::repeat_byte(0xAA), H256::repeat_byte(0xA1)), 78 | ( 79 | H256::from([ 80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 81 | 0x84, 0xC2, 0xDF, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, 82 | ]), 83 | H256::from([ 84 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 85 | 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, 86 | ]), 87 | ), 88 | ] { 89 | group.bench_with_input(BenchmarkId::from_parameter(input.1), &input, |b, (x, y)| { 90 | b.iter(|| black_box(x.cmp(black_box(y)))) 91 | }); 92 | } 93 | group.finish(); 94 | } 95 | -------------------------------------------------------------------------------- /fixed-hash/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | #![cfg_attr(not(feature = "std"), no_std)] 10 | 11 | // Re-export liballoc using an alias so that the macros can work without 12 | // requiring `extern crate alloc` downstream. 13 | #[doc(hidden)] 14 | pub extern crate alloc as alloc_; 15 | 16 | // Re-export libcore using an alias so that the macros can work without 17 | // requiring `use core` downstream. 18 | #[doc(hidden)] 19 | pub use core as core_; 20 | 21 | // This disables a warning for unused #[macro_use(..)] 22 | // which is incorrect since the compiler does not check 23 | // for all available configurations. 24 | #[allow(unused_imports)] 25 | #[doc(hidden)] 26 | pub use static_assertions; 27 | 28 | // Export `const_assert` macro so that users of this crate do not 29 | // have to import the `static_assertions` crate themselves. 30 | #[doc(hidden)] 31 | pub use static_assertions::const_assert; 32 | 33 | #[cfg(feature = "rustc-hex")] 34 | #[doc(hidden)] 35 | pub use rustc_hex; 36 | 37 | #[cfg(feature = "rand")] 38 | #[doc(hidden)] 39 | pub use rand; 40 | 41 | #[cfg(feature = "quickcheck")] 42 | #[doc(hidden)] 43 | pub use quickcheck; 44 | 45 | #[cfg(feature = "arbitrary")] 46 | #[doc(hidden)] 47 | pub use arbitrary; 48 | 49 | #[macro_use] 50 | mod hash; 51 | 52 | #[cfg(test)] 53 | mod tests; 54 | 55 | #[cfg(feature = "api-dummy")] 56 | construct_fixed_hash! { 57 | /// Go here for an overview of the hash type API. 58 | pub struct ApiDummy(32); 59 | } 60 | -------------------------------------------------------------------------------- /keccak-hash/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.11.0] - 2024-09-11 10 | - Updated `primitive-types` to 0.13. [#859](https://github.com/paritytech/parity-common/pull/859) 11 | 12 | ## [0.10.0] - 2022-09-20 13 | ### Breaking 14 | - Updated `parity-util-mem` to 0.12. [#680](https://github.com/paritytech/parity-common/pull/680) 15 | 16 | ## [0.9.0] - 2022-02-04 17 | ### Breaking 18 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 19 | - Updated `primitive-types` to 0.11. [#623](https://github.com/paritytech/parity-common/pull/623) 20 | 21 | ## [0.8.0] - 2021-07-02 22 | ### Breaking 23 | - Updated `primitive-types` to 0.10. [#556](https://github.com/paritytech/parity-common/pull/556) 24 | 25 | ## [0.7.0] - 2021-01-27 26 | ### Breaking 27 | - Updated `primitive-types` to 0.9. [#510](https://github.com/paritytech/parity-common/pull/510) 28 | 29 | ## [0.6.0] - 2021-01-05 30 | ### Breaking 31 | - Updated `primitive-types` to 0.8. [#463](https://github.com/paritytech/parity-common/pull/463) 32 | 33 | ## [0.5.1] - 2020-04-10 34 | - Added `keccak256_range` and `keccak512_range` functions. [#370](https://github.com/paritytech/parity-common/pull/370) 35 | 36 | ## [0.5.0] - 2020-03-16 37 | - License changed from GPL3 to dual MIT/Apache2. [#342](https://github.com/paritytech/parity-common/pull/342) 38 | - Updated dependencies. [#361](https://github.com/paritytech/parity-common/pull/361) 39 | - Updated tiny-keccak. [#260](https://github.com/paritytech/parity-common/pull/260) 40 | 41 | ## [0.4.1] - 2019-10-24 42 | ### Dependencies 43 | - Updated dependencies. [#239](https://github.com/paritytech/parity-common/pull/239) 44 | -------------------------------------------------------------------------------- /keccak-hash/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "keccak-hash" 3 | version = "0.11.0" 4 | description = "`keccak-hash` is a set of utility functions to facilitate working with Keccak hashes (256/512 bits long)." 5 | readme = "README.md" 6 | rust-version = "1.56.1" 7 | authors.workspace = true 8 | edition.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | tiny-keccak = { workspace = true, features = ["keccak"] } 15 | primitive-types = { workspace = true } 16 | 17 | [dev-dependencies] 18 | tempfile = { workspace = true } 19 | criterion = { workspace = true } 20 | 21 | [features] 22 | default = ["std"] 23 | std = [] 24 | 25 | [[bench]] 26 | name = "keccak_256" 27 | harness = false 28 | -------------------------------------------------------------------------------- /keccak-hash/README.md: -------------------------------------------------------------------------------- 1 | `keccak-hash` is a set of utility functions to facilitate working with Keccak hashes (256/512 bits long). -------------------------------------------------------------------------------- /keccak-hash/benches/keccak_256.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 10 | use keccak_hash::keccak; 11 | 12 | criterion_group!(keccak_256, keccak_256_with_empty_input, keccak_256_with_typical_input, keccak_256_with_large_input,); 13 | criterion_main!(keccak_256); 14 | 15 | pub fn keccak_256_with_empty_input(c: &mut Criterion) { 16 | let empty = [0u8; 0]; 17 | c.bench_function("keccak_256_with_empty_input", |b| { 18 | b.iter(|| { 19 | let _out = keccak(black_box(empty)); 20 | }) 21 | }); 22 | } 23 | 24 | pub fn keccak_256_with_typical_input(c: &mut Criterion) { 25 | let mut data: Vec = From::from("some medium length string with important information"); 26 | let len = data.len(); 27 | let mut group = c.benchmark_group("keccak_256_with_typical_input"); 28 | group.bench_function("regular", |b| { 29 | b.iter(|| { 30 | let _out = keccak(black_box(&data)); 31 | }) 32 | }); 33 | group.bench_function("inplace", |b| { 34 | b.iter(|| { 35 | keccak_hash::keccak256(black_box(&mut data[..])); 36 | }) 37 | }); 38 | group.bench_function("inplace_range", |b| { 39 | b.iter(|| { 40 | keccak_hash::keccak256_range(black_box(&mut data[..]), 0..len); 41 | }) 42 | }); 43 | 44 | group.finish(); 45 | } 46 | 47 | pub fn keccak_256_with_large_input(c: &mut Criterion) { 48 | // 4096 chars 49 | let data: Vec = From::from("IGxcKBr1Qp7tuqtpSVhAbvt7UgWLEi7mCA6Wa185seLSIJLFS8K1aAFO9AwtO9b3n9SM3Qg136JMmy9Mj9gZ84IaUm8XioPtloabFDU5ZR1wvauJT6jNTkvBVBpUigIsyU7C1u3s99vKP64LpXqvo1hwItZKtISxmUAgzzjv5q14V4G9bkKAnmc4M5xixgLsDGZmnj6HcOMY3XRkWtxN3RscSKwPA0bfpgtz27ZVHplbXwloYRgRLpjRhZJc7sqO8RFnTHKasVkxVRcUoDBvWNJK27TbLvQQcfxETI2Q1H6c2cBAchi8unSiuxqy5rIvVxcl9rsmmRY4IXLEG9qKntUGbiIRLjEffIP9ODoWog0GbWLmMtfvtf24hWVwXz6Ap5oUAR0kLgb7HYIYrOwKjvfV25iEF7GW8cjhl8yowXx1zcgW4t6NJNqJlGzRKx8MvRWQXvHz8h8JxcHl7S64i6PAkxI9eCLXLvs8cpbEQQHt05Zu6GKm6IInjc9mSh52WFuGhgjbno69XzfkBufJs6c9tZuBf6ErVPj4UxmT82ajCruDusk79Tlvb8oQMLjoplQc1alQaLQwSsMac9iVp9MiE3PeYnTTepJ1V10tp79fciDAnNPJgPcRfDYv0REcSFgR9Q7yWhbpPpyBjO7HwOykDQVGtV0ZbDFrFRygLAXagAIkOPc9HDfcBNID1Q2MGk8ijVWMyvmGz1wzbpNfFcQaSOm8olhwoLyHUGvkyXegh44iNsPBUvSicNxTTDowtMqO5azleuWEjzxCobYbASDopvl6JeJjRtEBBO5YCQJiHsYjlXh9QR5Q543GsqhzRLgcHNRSZYLMZqDmIABXZi8VRNJMZyWXDRKHOGDmcHWe55uZomW6FnyU0uSRKxxz66K0JWfxuFzzxAR0vR4ZZCTemgDRQuDwL1loC3KUMjDpU13jUgoPc4UJUVfwQ4f4BUY3X51Cfw9FLw4oX39KoFoiCP2Z6z27gZUY1IlE59WoXGLj4KjTp4C16ZihG080gfDIWlXnDEk3VwBuBFyKWARB63sGLrGnn27b1gHWMaop6sPvkQgWxkEKIqsxDIvXLZJg2s23V8Gqtt0FeA7R3RCvBysF4jNjQ7NiQTIQWQZ8G9gO4mEsftolSZv6FlSpNeBKIIwYWSO2R6vkgeiz06euE9bwwnenOjwPNGTGk8WHIOZBJ1hIP0ejVU2i2ca9ON0phSAnewqjo5W3PtZf2Q7mDvp9imuVWoy4t8XcZq8I2Un9jVjes9Xi0FLN2t71vLFWLWZmGDzwXxpqEgkARS1WjtJoYXCBmRnXEPj6jQfwMZWKPYSIrmOogxMVoWvA8wrof6utfJna9JezyTnrBJSCuGTSNmwwAXRLoFYxF1RITyN8mI2KmHSfvLXBrbE6kmAkjsm4XJb6kria7oUQQ1gzJuCyB7oNHjZTBFNhNa7VeQ1s1xLOwZXLOAjZ4MDTYKnF7giGJGyswb5KQxkOV9orbuAu6pJsjtql6h1UD3BcNUkG3oz8kJNepbuCN3vNCJcZOX1VrQi0PWkDwyvECrQ2E1CgbU6GpWatpg2sCTpo9W62pCcWBK2FKUFWqU3qo2T7T1Mk2ZtM6hE9I8op0M7xlGE91Mn7ea6aq93MWp7nvFlBvbaMIoeU4MpDx0BeOSkROY03ZBJ0x7K8nJrNUhAtvxp17c9oFk0VxLiuRbAAcwDUormOmpVXZNIcqnap4twEVYaSIowfcNojyUSrFL5nPc8ZG93WgNNl9rpUPZhssVml3DvXghI80A9SW3QauzohTQAX2bkWelFBHnuG2LKrsJ8en51N6CkjcS5b87y1DVMZELcZ1n5s8PCAA1wyn7OSZlgw00GRzch1YwMoHzBBgIUtMO9HrMyuhgqIPJP7KcKbQkKhtvBXKplX8SCfSlOwUkLwHNKm3HYVE0uVfJ91NAsUrGoCOjYiXYpoRT8bjAPWTm6fDlTq2sbPOyTMoc4xRasmiOJ7B0PT6UxPzCPImM4100sPFxp7Kofv4okKZWTPKTefeYiPefI3jRgfDtEIP9E6a35LZD75lBNMXYlAqL3qlnheUQD1WQimFTHiDsW6bmURptNvtkMjEXzXzpWbnyxBskUGTvP2YQjtSAhWliDXkv6t1x71cYav7TQbqvbIzMRQQsguSGYMbs8YIC4DC9ep5reWAfanlTxcxksbEhQ7FGzXOvcufeGnDl2C85gWfryVzwN7kOZiSEktFMOQ1ngRC23y1fCOiHQVQJ2nLnaW7GILb9wkN1mBTRuHsOefRJST0TnRxcn4bBq4MIibIitVyjPRy7G5XvPEcL4pFaW1HCPGm6pUOEEwTer32JObNGCyTFB1BI2cRLJu5BHPjgG3mmb0gGkGlIfh8D2b2amogpivqEn2r9Y1KOKQ8ufJvG2mYfkevco9DuEZ9Nmzkm6XkCTZaFMNHqbfQaKqsEYK7i2N1KfkBct1leW2H9MQ9QO7AHCqXHK47b1kWVIm6pSJA1yV4funzCqXnIJCEURQgHiKf38YpN7ylLhe1J4UvSG3KeesZNeFFIZOEP9HZUSFMpnN1MOrwejojK0D4qzwucYWtXrTQ8I7UP5QhlijIsCKckUa9C1Osjrq8cgSclYNGt19wpy0onUbX1rOQBUlAAUJs4CyXNU0wmVUjw7tG1LUC8my4s9KZDUj4R5UcPz3VaZRrx1RqYu6YxjroJW70I1LyG4WEiQbOkCoLmaiWo9WzbUS2cErlOo2RPymlkWHxbNnZawX2Bc872ivRHSWqNpRHyuR5QewXmcyghH3EhESBAxTel5E2xuQXfLCEVK0kEk0Mj22KPsckKKyH7sVYC1F4YItQh5hj9Titb7KflQb9vnXQ44UHxY3zBhTQT5PSYv1Kv8HxXCsnpmhZCiBru16iX9oEB33icBVB2KKcZZEEKnCGPVxJlM9RTlyNyQmjHf7z4GeTDuMAUrsMO31WvgZBnWcAOtn6ulBTUCAaqxJiWqzlMx2FSANAlyAjAxqzmQjzPLvQRjskUnBFN3woKB1m2bSo2c5thwA1fKiPvN5LW8tl1rnfNy3rJ0GJpK8nZjkzHMztYrKYAe56pX4SvplpTyibTIiRXLyEVsmuByTHCZhO3fvGoFsav3ZuRhe9eAAWeqAh13eKDTcA0ufME3ZnmJheXEZ3OwrxnFjSf3U0clkWYVont3neh77ODKHhYnX0bOmnJJlr4RqFoLBitskY0kcGMKcZlaej21SENjDcFgaka3CfHbAH5vIFqnoX1JZrZPkQ65PZqQWImP79U3gXWKvz96lElyJZAFqn0Mbltllqw4MhlI766AvHraOmMsJoNvjv1QR7pCSnC0iX6nbqW1eVPaUSZDuZRtRIxfLA8HC9VbxufT2KZV3qG0l7wrZna5Di2MNcBE9uthuVLZcqp8vCmEhINDhRRlipR7tC2iRBHecS5WtxBCpbEm1y1kgNG5o60UKgAswxxuJ3RQ9Y49mPIApBMmp4LFpuKRfcrZb4UJnCfR3pNbQ70nnZ6Be2M7tuJUCoFfHrhqHXNz5A0uWMgxUS50c60zLl6QAELxHaCGba4WCMOHIo5nSKcUuYtDyDoDlrezALW5mZR4PRPRxnjrXxbJI14qrpymRReC3QgFDJp6sT5TLwvSHaavPlEbt2Eu0Kh5SXklGHXP9YuF3glGuJzSob3NakW1RXF5786U1MHhtJby64LyGWvNn4QXie3VjeL3QQu4C9crEAxSSiOJOfnL3DYIVOY4ipUkKFlF7Rp2q6gZazDvcUCp1cbcr7T7B4s22rXzjN7mHYWOyWuZGwlImeorY3aVKi7BaXbhgOFw6BUmIc1HeGFELHIEnPE9MwOjZam3LOm0rhBHlvJJZkXvJKmDUJrGlyqC5GtC5lDWLfXewyDWDqq7PY0atVQily5GWqib6wub6u6LZ3HZDNP8gK64Nf4kC259AE4V2hCohDnSsXAIoOkehwXyp6CkDT42NJb6sXHUv2N6cm292MiKA22PKWrwUGsan599KI2V67YRDfcfiB4ZHRDiSe62MBE0fGLIgXLIWw1xTWYbPQ9YAj3xovBvmewbJ1De4k6uS"); 50 | c.bench_function("keccak_256_with_large_input", |b| { 51 | b.iter(|| { 52 | let _out = keccak(black_box(&data)); 53 | }) 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /keccak-hash/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | #![cfg_attr(not(feature = "std"), no_std)] 10 | 11 | #[cfg(feature = "std")] 12 | use std::io; 13 | 14 | pub use primitive_types::H256; 15 | use tiny_keccak::{Hasher, Keccak}; 16 | 17 | /// Get the KECCAK (i.e. Keccak) hash of the empty bytes string. 18 | pub const KECCAK_EMPTY: H256 = H256([ 19 | 0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0, 0xe5, 0x00, 0xb6, 20 | 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70, 21 | ]); 22 | 23 | /// The KECCAK of the RLP encoding of empty data. 24 | pub const KECCAK_NULL_RLP: H256 = H256([ 25 | 0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x55, 0xa6, 0xff, 0x83, 0x45, 0xe6, 0x92, 0xc0, 0xf8, 0x6e, 0x5b, 0x48, 0xe0, 26 | 0x1b, 0x99, 0x6c, 0xad, 0xc0, 0x01, 0x62, 0x2f, 0xb5, 0xe3, 0x63, 0xb4, 0x21, 27 | ]); 28 | 29 | /// The KECCAK of the RLP encoding of empty list. 30 | pub const KECCAK_EMPTY_LIST_RLP: H256 = H256([ 31 | 0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, 0x5d, 0x7a, 0xab, 0x85, 0xb5, 0x67, 0xb6, 0xcc, 0xd4, 0x1a, 0xd3, 0x12, 0x45, 32 | 0x1b, 0x94, 0x8a, 0x74, 0x13, 0xf0, 0xa1, 0x42, 0xfd, 0x40, 0xd4, 0x93, 0x47, 33 | ]); 34 | 35 | pub fn keccak>(s: T) -> H256 { 36 | let mut result = [0u8; 32]; 37 | write_keccak(s, &mut result); 38 | H256(result) 39 | } 40 | 41 | /// Computes in-place keccak256 hash of `data`. 42 | pub fn keccak256(data: &mut [u8]) { 43 | let mut keccak256 = Keccak::v256(); 44 | keccak256.update(data.as_ref()); 45 | keccak256.finalize(data); 46 | } 47 | 48 | /// Computes in-place keccak256 hash of `data[range]`. 49 | /// 50 | /// The `range` argument specifies a subslice of `data` in bytes to be hashed. 51 | /// The resulting hash will be written back to `data`. 52 | /// # Panics 53 | /// 54 | /// If `range` is out of bounds. 55 | /// 56 | /// # Example 57 | /// 58 | /// ``` 59 | /// let mut data = [1u8; 32]; 60 | /// // Hash the first 8 bytes of `data` and write the result, 32 bytes, to `data`. 61 | /// keccak_hash::keccak256_range(&mut data, 0..8); 62 | /// let expected = [ 63 | /// 0x54, 0x84, 0x4f, 0x69, 0xb4, 0xda, 0x4b, 0xb4, 0xa9, 0x9f, 0x24, 0x59, 0xb5, 0x11, 0xd4, 0x42, 64 | /// 0xcc, 0x5b, 0xd2, 0xfd, 0xf4, 0xc3, 0x54, 0xd2, 0x07, 0xbb, 0x13, 0x08, 0x94, 0x43, 0xaf, 0x68, 65 | /// ]; 66 | /// assert_eq!(&data, &expected); 67 | /// ``` 68 | pub fn keccak256_range(data: &mut [u8], range: core::ops::Range) { 69 | let mut keccak256 = Keccak::v256(); 70 | keccak256.update(&data[range]); 71 | keccak256.finalize(data); 72 | } 73 | 74 | /// Computes in-place keccak512 hash of `data`. 75 | pub fn keccak512(data: &mut [u8]) { 76 | let mut keccak512 = Keccak::v512(); 77 | keccak512.update(data.as_ref()); 78 | keccak512.finalize(data); 79 | } 80 | 81 | /// Computes in-place keccak512 hash of `data[range]`. 82 | /// 83 | /// The `range` argument specifies a subslice of `data` in bytes to be hashed. 84 | /// The resulting hash will be written back to `data`. 85 | /// # Panics 86 | /// 87 | /// If `range` is out of bounds. 88 | /// 89 | /// # Example 90 | /// 91 | /// ``` 92 | /// let mut data = [1u8; 64]; 93 | /// keccak_hash::keccak512_range(&mut data, 0..8); 94 | /// let expected = [ 95 | /// 0x90, 0x45, 0xc5, 0x9e, 0xd3, 0x0e, 0x1f, 0x42, 0xac, 0x35, 0xcc, 0xc9, 0x55, 0x7c, 0x77, 0x17, 96 | /// 0xc8, 0x89, 0x3a, 0x77, 0x6c, 0xea, 0x2e, 0xf3, 0x88, 0xea, 0xe5, 0xc0, 0xea, 0x40, 0x26, 0x64, 97 | /// ]; 98 | /// assert_eq!(&data[..32], &expected); 99 | /// ``` 100 | pub fn keccak512_range(data: &mut [u8], range: core::ops::Range) { 101 | let mut keccak512 = Keccak::v512(); 102 | keccak512.update(&data[range]); 103 | keccak512.finalize(data); 104 | } 105 | 106 | pub fn keccak_256(input: &[u8], output: &mut [u8]) { 107 | write_keccak(input, output); 108 | } 109 | 110 | pub fn keccak_512(input: &[u8], output: &mut [u8]) { 111 | let mut keccak512 = Keccak::v512(); 112 | keccak512.update(input); 113 | keccak512.finalize(output); 114 | } 115 | 116 | pub fn write_keccak>(s: T, dest: &mut [u8]) { 117 | let mut keccak256 = Keccak::v256(); 118 | keccak256.update(s.as_ref()); 119 | keccak256.finalize(dest); 120 | } 121 | 122 | #[cfg(feature = "std")] 123 | pub fn keccak_pipe(r: &mut dyn io::BufRead, w: &mut dyn io::Write) -> Result { 124 | let mut output = [0u8; 32]; 125 | let mut input = [0u8; 1024]; 126 | let mut keccak256 = Keccak::v256(); 127 | 128 | // read file 129 | loop { 130 | let some = r.read(&mut input)?; 131 | if some == 0 { 132 | break 133 | } 134 | keccak256.update(&input[0..some]); 135 | w.write_all(&input[0..some])?; 136 | } 137 | 138 | keccak256.finalize(&mut output); 139 | Ok(output.into()) 140 | } 141 | 142 | #[cfg(feature = "std")] 143 | pub fn keccak_buffer(r: &mut dyn io::BufRead) -> Result { 144 | keccak_pipe(r, &mut io::sink()) 145 | } 146 | 147 | #[cfg(test)] 148 | mod tests { 149 | #[cfg(not(feature = "std"))] 150 | extern crate alloc; 151 | #[cfg(not(feature = "std"))] 152 | use alloc::{vec, vec::Vec}; 153 | 154 | use super::*; 155 | 156 | #[test] 157 | fn keccak_empty() { 158 | assert_eq!(keccak([0u8; 0]), KECCAK_EMPTY); 159 | } 160 | 161 | #[test] 162 | fn keccak_as() { 163 | assert_eq!( 164 | keccak([0x41u8; 32]), 165 | H256([ 166 | 0x59, 0xca, 0xd5, 0x94, 0x86, 0x73, 0x62, 0x2c, 0x1d, 0x64, 0xe2, 0x32, 0x24, 0x88, 0xbf, 0x01, 0x61, 167 | 0x9f, 0x7f, 0xf4, 0x57, 0x89, 0x74, 0x1b, 0x15, 0xa9, 0xf7, 0x82, 0xce, 0x92, 0x90, 0xa8 168 | ]), 169 | ); 170 | } 171 | 172 | #[test] 173 | fn write_keccak_with_content() { 174 | let data: Vec = From::from("hello world"); 175 | let expected = vec![ 176 | 0x47, 0x17, 0x32, 0x85, 0xa8, 0xd7, 0x34, 0x1e, 0x5e, 0x97, 0x2f, 0xc6, 0x77, 0x28, 0x63, 0x84, 0xf8, 0x02, 177 | 0xf8, 0xef, 0x42, 0xa5, 0xec, 0x5f, 0x03, 0xbb, 0xfa, 0x25, 0x4c, 0xb0, 0x1f, 0xad, 178 | ]; 179 | let mut dest = [0u8; 32]; 180 | write_keccak(data, &mut dest); 181 | 182 | assert_eq!(dest, expected.as_ref()); 183 | } 184 | 185 | #[cfg(feature = "std")] 186 | #[test] 187 | fn should_keccak_a_file() { 188 | use std::{ 189 | fs, 190 | io::{BufReader, Write}, 191 | }; 192 | 193 | // given 194 | let tmpdir = tempfile::Builder::new().prefix("keccak").tempdir().unwrap(); 195 | let mut path = tmpdir.path().to_owned(); 196 | path.push("should_keccak_a_file"); 197 | // Prepare file 198 | { 199 | let mut file = fs::File::create(&path).unwrap(); 200 | file.write_all(b"something").unwrap(); 201 | } 202 | 203 | let mut file = BufReader::new(fs::File::open(&path).unwrap()); 204 | // when 205 | let hash = keccak_buffer(&mut file).unwrap(); 206 | 207 | // then 208 | assert_eq!(format!("{:x}", hash), "68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"); 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /kvdb-memorydb/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.13.0] - 2022-11-29 10 | - Removed `parity-util-mem` support. [#696](https://github.com/paritytech/parity-common/pull/696) 11 | 12 | ## [0.12.0] - 2022-09-20 13 | ### Breaking 14 | - Updated `kvdb` to 0.12. [662](https://github.com/paritytech/parity-common/pull/662) 15 | - Updated `parity-util-mem` to 0.12. [#680](https://github.com/paritytech/parity-common/pull/680) 16 | 17 | ## [0.11.0] - 2022-02-04 18 | ### Breaking 19 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 20 | - Updated `kvdb` to 0.11. [#623](https://github.com/paritytech/parity-common/pull/623) 21 | 22 | ## [0.10.0] - 2021-07-02 23 | ### Breaking 24 | - Updated `parity-util-mem` to 0.10. [#556](https://github.com/paritytech/parity-common/pull/556) 25 | - Updated `kvdb` to 0.10. [#556](https://github.com/paritytech/parity-common/pull/556) 26 | 27 | ## [0.9.0] - 2021-01-27 28 | ### Breaking 29 | - Updated `parity-util-mem` to 0.9. [#510](https://github.com/paritytech/parity-common/pull/510) 30 | - Updated `kvdb` to 0.9. [#510](https://github.com/paritytech/parity-common/pull/510) 31 | 32 | ## [0.8.0] - 2021-01-05 33 | ### Breaking 34 | - Updated dependencies. [#470](https://github.com/paritytech/parity-common/pull/470) 35 | 36 | ## [0.7.0] - 2020-06-24 37 | - Updated `kvdb` to 0.7. [#402](https://github.com/paritytech/parity-common/pull/402) 38 | 39 | ## [0.6.0] - 2020-05-05 40 | ### Breaking 41 | - Updated to the new `kvdb` interface. [#313](https://github.com/paritytech/parity-common/pull/313) 42 | 43 | ## [0.5.0] - 2020-03-16 44 | - License changed from GPL3 to dual MIT/Apache2. [#342](https://github.com/paritytech/parity-common/pull/342) 45 | - Updated dependencies. [#361](https://github.com/paritytech/parity-common/pull/361) 46 | 47 | ## [0.4.0] - 2019-02-05 48 | - Bump parking_lot to 0.10. [#332](https://github.com/paritytech/parity-common/pull/332) 49 | 50 | ## [0.3.1] - 2019-01-06 51 | - Updated features and feature dependencies. [#307](https://github.com/paritytech/parity-common/pull/307) 52 | 53 | ## [0.3.0] - 2019-01-03 54 | - InMemory key-value database now can report memory used (via `MallocSizeOf`). [#292](https://github.com/paritytech/parity-common/pull/292) 55 | 56 | ## [0.2.0] - 2019-12-19 57 | ### Fixed 58 | - `iter_from_prefix` behaviour synced with the `kvdb-rocksdb` 59 | ### Changed 60 | - Default column support removed from the API 61 | - Column argument type changed from `Option` to `u32` 62 | - Migration `None` -> unsupported, `Some(0)` -> `0`, `Some(1)` -> `1`, etc. 63 | -------------------------------------------------------------------------------- /kvdb-memorydb/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kvdb-memorydb" 3 | version = "0.13.0" 4 | description = "A key-value in-memory database that implements the `KeyValueDB` trait" 5 | rust-version = "1.56.1" 6 | authors.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | parking_lot = { workspace = true } 14 | kvdb = { workspace = true } 15 | 16 | [dev-dependencies] 17 | kvdb-shared-tests = { workspace = true } 18 | 19 | [features] 20 | default = [] 21 | -------------------------------------------------------------------------------- /kvdb-memorydb/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use kvdb::{DBKeyValue, DBOp, DBTransaction, DBValue, KeyValueDB}; 10 | use parking_lot::RwLock; 11 | use std::{ 12 | collections::{BTreeMap, HashMap}, 13 | io, 14 | }; 15 | 16 | /// A key-value database fulfilling the `KeyValueDB` trait, living in memory. 17 | /// This is generally intended for tests and is not particularly optimized. 18 | #[derive(Default)] 19 | pub struct InMemory { 20 | columns: RwLock, DBValue>>>, 21 | } 22 | 23 | /// Create an in-memory database with the given number of columns. 24 | /// Columns will be indexable by 0..`num_cols` 25 | pub fn create(num_cols: u32) -> InMemory { 26 | let mut cols = HashMap::new(); 27 | 28 | for idx in 0..num_cols { 29 | cols.insert(idx, BTreeMap::new()); 30 | } 31 | 32 | InMemory { columns: RwLock::new(cols) } 33 | } 34 | 35 | fn invalid_column(col: u32) -> io::Error { 36 | io::Error::new(io::ErrorKind::Other, format!("No such column family: {:?}", col)) 37 | } 38 | 39 | impl KeyValueDB for InMemory { 40 | fn get(&self, col: u32, key: &[u8]) -> io::Result> { 41 | let columns = self.columns.read(); 42 | match columns.get(&col) { 43 | None => Err(invalid_column(col)), 44 | Some(map) => Ok(map.get(key).cloned()), 45 | } 46 | } 47 | 48 | fn get_by_prefix(&self, col: u32, prefix: &[u8]) -> io::Result> { 49 | let columns = self.columns.read(); 50 | match columns.get(&col) { 51 | None => Err(invalid_column(col)), 52 | Some(map) => Ok(map.iter().find(|&(ref k, _)| k.starts_with(prefix)).map(|(_, v)| v.to_vec())), 53 | } 54 | } 55 | 56 | fn write(&self, transaction: DBTransaction) -> io::Result<()> { 57 | let mut columns = self.columns.write(); 58 | let ops = transaction.ops; 59 | for op in ops { 60 | match op { 61 | DBOp::Insert { col, key, value } => 62 | if let Some(col) = columns.get_mut(&col) { 63 | col.insert(key.into_vec(), value); 64 | }, 65 | DBOp::Delete { col, key } => 66 | if let Some(col) = columns.get_mut(&col) { 67 | col.remove(&*key); 68 | }, 69 | DBOp::DeletePrefix { col, prefix } => 70 | if let Some(col) = columns.get_mut(&col) { 71 | use std::ops::Bound; 72 | if prefix.is_empty() { 73 | col.clear(); 74 | } else { 75 | let start_range = Bound::Included(prefix.to_vec()); 76 | let keys: Vec<_> = if let Some(end_range) = kvdb::end_prefix(&prefix[..]) { 77 | col.range((start_range, Bound::Excluded(end_range))) 78 | .map(|(k, _)| k.clone()) 79 | .collect() 80 | } else { 81 | col.range((start_range, Bound::Unbounded)).map(|(k, _)| k.clone()).collect() 82 | }; 83 | for key in keys.into_iter() { 84 | col.remove(&key[..]); 85 | } 86 | } 87 | }, 88 | } 89 | } 90 | Ok(()) 91 | } 92 | 93 | fn iter<'a>(&'a self, col: u32) -> Box> + 'a> { 94 | match self.columns.read().get(&col) { 95 | Some(map) => Box::new( 96 | // TODO: worth optimizing at all? 97 | map.clone().into_iter().map(|(k, v)| Ok((k.into(), v))), 98 | ), 99 | None => Box::new(std::iter::once(Err(invalid_column(col)))), 100 | } 101 | } 102 | 103 | fn iter_with_prefix<'a>( 104 | &'a self, 105 | col: u32, 106 | prefix: &'a [u8], 107 | ) -> Box> + 'a> { 108 | match self.columns.read().get(&col) { 109 | Some(map) => Box::new( 110 | map.clone() 111 | .into_iter() 112 | .filter(move |&(ref k, _)| k.starts_with(prefix)) 113 | .map(|(k, v)| Ok((k.into(), v))), 114 | ), 115 | None => Box::new(std::iter::once(Err(invalid_column(col)))), 116 | } 117 | } 118 | } 119 | 120 | #[cfg(test)] 121 | mod tests { 122 | use super::create; 123 | use kvdb_shared_tests as st; 124 | use std::io; 125 | 126 | #[test] 127 | fn get_fails_with_non_existing_column() -> io::Result<()> { 128 | let db = create(1); 129 | st::test_get_fails_with_non_existing_column(&db) 130 | } 131 | 132 | #[test] 133 | fn put_and_get() -> io::Result<()> { 134 | let db = create(1); 135 | st::test_put_and_get(&db) 136 | } 137 | 138 | #[test] 139 | fn delete_and_get() -> io::Result<()> { 140 | let db = create(1); 141 | st::test_delete_and_get(&db) 142 | } 143 | 144 | #[test] 145 | fn delete_prefix() -> io::Result<()> { 146 | let db = create(st::DELETE_PREFIX_NUM_COLUMNS); 147 | st::test_delete_prefix(&db) 148 | } 149 | 150 | #[test] 151 | fn iter() -> io::Result<()> { 152 | let db = create(1); 153 | st::test_iter(&db) 154 | } 155 | 156 | #[test] 157 | fn iter_with_prefix() -> io::Result<()> { 158 | let db = create(1); 159 | st::test_iter_with_prefix(&db) 160 | } 161 | 162 | #[test] 163 | fn complex() -> io::Result<()> { 164 | let db = create(1); 165 | st::test_complex(&db) 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /kvdb-rocksdb/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.19.0] - 2023-05-10 10 | - Updated `rocksdb` to 0.21. [#750](https://github.com/paritytech/parity-common/pull/750) 11 | 12 | ## [0.18.0] - 2023-04-21 13 | - Updated `rocksdb` to 0.20.1. [#743](https://github.com/paritytech/parity-common/pull/743) 14 | 15 | ## [0.17.0] - 2022-11-29 16 | - Removed `parity-util-mem` support. [#696](https://github.com/paritytech/parity-common/pull/696) 17 | 18 | ## [0.16.0] - 2022-09-20 19 | - Removed `owning_ref` from dependencies :tada:. [#662](https://github.com/paritytech/parity-common/pull/662) 20 | - No longer attempt to repair on `open`. [#667](https://github.com/paritytech/parity-common/pull/667) 21 | ### Breaking 22 | - Updated `kvdb` to 0.12. [#662](https://github.com/paritytech/parity-common/pull/662) 23 | - `add_column` and `remove_last_column` now require `&mut self` 24 | 25 | ## [0.15.2] - 2022-03-20 26 | - Disable `jemalloc` feature for `rocksdb` where it is not working. [#633](https://github.com/paritytech/parity-common/pull/633) 27 | 28 | ## [0.15.1] - 2022-02-18 29 | - Updated `rocksdb` to 0.18 and enable `jemalloc` feature. [#629](https://github.com/paritytech/parity-common/pull/629) 30 | 31 | ## [0.15.0] - 2022-02-04 32 | ### Breaking 33 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 34 | - Bumped `kvdb` and `parity-util-mem`. [#623](https://github.com/paritytech/parity-common/pull/623) 35 | 36 | ## [0.14.0] - 2021-08-05 37 | ### Breaking 38 | - `Database` api uses now template argument `P: AsRef` instead of `&str` [#579](https://github.com/paritytech/parity-common/pull/579) 39 | 40 | ## [0.13.0] - 2021-08-04 41 | ### Breaking 42 | - `DatabaseConfig` is now `#[non_exhaustive]`. [#576](https://github.com/paritytech/parity-common/pull/576) 43 | - Added `create_if_missing` to `DatabaseConfig`. [#576](https://github.com/paritytech/parity-common/pull/576) 44 | 45 | ## [0.12.1] - 2021-07-30 46 | - Bumped `rocksdb` to 0.17. [#573](https://github.com/paritytech/parity-common/pull/573) 47 | 48 | ## [0.12.0] - 2021-07-02 49 | ### Breaking 50 | - Updated `kvdb` to 0.10. [#556](https://github.com/paritytech/parity-common/pull/556) 51 | - Updated `parity-util-mem` to 0.10. [#556](https://github.com/paritytech/parity-common/pull/556) 52 | 53 | ## [0.11.1] - 2021-05-03 54 | - Updated `rocksdb` to 0.16. [#537](https://github.com/paritytech/parity-common/pull/537) 55 | 56 | ## [0.11.0] - 2021-01-27 57 | ### Breaking 58 | - Updated `kvdb` to 0.9. [#510](https://github.com/paritytech/parity-common/pull/510) 59 | - Updated `parity-util-mem` to 0.9. [#510](https://github.com/paritytech/parity-common/pull/510) 60 | 61 | ## [0.10.0] - 2021-01-05 62 | ### Breaking 63 | - Updated dependencies. [#470](https://github.com/paritytech/parity-common/pull/470) 64 | 65 | ## [0.9.1] - 2020-08-26 66 | - Updated rocksdb to 0.15. [#424](https://github.com/paritytech/parity-common/pull/424) 67 | - Set `format_version` to 5. [#395](https://github.com/paritytech/parity-common/pull/395) 68 | 69 | ## [0.9.0] - 2020-06-24 70 | - Updated `kvdb` to 0.7. [#402](https://github.com/paritytech/parity-common/pull/402) 71 | 72 | ## [0.8.0] - 2020-05-05 73 | - Updated RocksDB to 6.7.3. [#379](https://github.com/paritytech/parity-common/pull/379) 74 | ### Breaking 75 | - Updated to the new `kvdb` interface. [#313](https://github.com/paritytech/parity-common/pull/313) 76 | - Rename and optimize prefix iteration. [#365](https://github.com/paritytech/parity-common/pull/365) 77 | - Added Secondary Instance API. [#384](https://github.com/paritytech/parity-common/pull/384) 78 | 79 | ## [0.7.0] - 2020-03-16 80 | - Updated dependencies. [#361](https://github.com/paritytech/parity-common/pull/361) 81 | 82 | ## [0.6.0] - 2020-02-28 83 | - License changed from GPL3 to dual MIT/Apache2. [#342](https://github.com/paritytech/parity-common/pull/342) 84 | - Added `get_statistics` method and `enable_statistics` config parameter. [#347](https://github.com/paritytech/parity-common/pull/347) 85 | 86 | ## [0.5.0] - 2019-02-05 87 | - Bump parking_lot to 0.10. [#332](https://github.com/paritytech/parity-common/pull/332) 88 | 89 | ## [0.4.2] - 2019-02-04 90 | ### Fixes 91 | - Fixed `iter_from_prefix` being slow. [#326](https://github.com/paritytech/parity-common/pull/326) 92 | 93 | ## [0.4.1] - 2019-01-06 94 | - Updated features and feature dependencies. [#307](https://github.com/paritytech/parity-common/pull/307) 95 | 96 | ## [0.4.0] - 2019-01-03 97 | - Add I/O statistics for RocksDB. [#294](https://github.com/paritytech/parity-common/pull/294) 98 | - Support querying memory footprint via `MallocSizeOf` trait. [#292](https://github.com/paritytech/parity-common/pull/292) 99 | 100 | ## [0.3.0] - 2019-12-19 101 | - Use `get_pinned` API to save one allocation for each call to `get()`. [#274](https://github.com/paritytech/parity-common/pull/274) 102 | - Rename `drop_column` to `remove_last_column`. [#274](https://github.com/paritytech/parity-common/pull/274) 103 | - Rename `get_cf` to `cf`. [#274](https://github.com/paritytech/parity-common/pull/274) 104 | - Default column support removed from the API. [#278](https://github.com/paritytech/parity-common/pull/278) 105 | - Column argument type changed from `Option` to `u32` 106 | - Migration 107 | - Column index `None` -> unsupported, `Some(0)` -> `0`, `Some(1)` -> `1`, etc. 108 | - Database must be opened with at least one column and existing DBs has to be opened with a number of columns increased by 1 to avoid having to migrate the data, e.g. before: `Some(9)`, after: `10`. 109 | - `DatabaseConfig::default()` defaults to 1 column 110 | - `Database::with_columns` still accepts `u32`, but panics if `0` is provided 111 | - `Database::open` panics if configuration with 0 columns is provided 112 | - Add `num_keys(col)` to get an estimate of the number of keys in a column. [#285](https://github.com/paritytech/parity-common/pull/285) 113 | - Remove `ElasticArray` and use the new `DBValue` (alias for `Vec`) and `DBKey` types from `kvdb`. [#282](https://github.com/paritytech/parity-common/pull/282) 114 | 115 | ## [0.2.0] - 2019-11-28 116 | - Switched away from using [parity-rocksdb](https://crates.io/crates/parity-rocksdb) in favour of upstream [rust-rocksdb](https://crates.io/crates/rocksdb). [#257](https://github.com/paritytech/parity-common/pull/257) 117 | - Revamped configuration handling, allowing per-column memory budgeting. [#256](https://github.com/paritytech/parity-common/pull/256) 118 | ### Dependencies 119 | - rust-rocksdb v0.13 120 | 121 | ## [0.1.6] - 2019-10-24 122 | - Updated to 2018 edition idioms. [#237](https://github.com/paritytech/parity-common/pull/237) 123 | ### Dependencies 124 | - Updated dependencies. [#239](https://github.com/paritytech/parity-common/pull/239) 125 | -------------------------------------------------------------------------------- /kvdb-rocksdb/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kvdb-rocksdb" 3 | version = "0.19.0" 4 | description = "kvdb implementation backed by RocksDB" 5 | rust-version = "1.71.1" 6 | authors.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | 12 | [[bench]] 13 | name = "bench_read_perf" 14 | harness = false 15 | 16 | [dependencies] 17 | kvdb = { workspace = true } 18 | num_cpus = { workspace = true } 19 | parking_lot = { workspace = true } 20 | regex = { workspace = true } 21 | 22 | # OpenBSD and MSVC are unteested and shouldn't enable jemalloc: 23 | # https://github.com/tikv/jemallocator/blob/52de4257fab3e770f73d5174c12a095b49572fba/jemalloc-sys/build.rs#L26-L27 24 | [target.'cfg(any(target_os = "openbsd", target_env = "msvc"))'.dependencies] 25 | rocksdb = { workspace = true, features = ["snappy"] } 26 | 27 | [target.'cfg(not(any(target_os = "openbsd", target_env = "msvc")))'.dependencies] 28 | rocksdb = { workspace = true, features = ["snappy", "jemalloc"] } 29 | 30 | [dev-dependencies] 31 | alloc_counter = { workspace = true } 32 | criterion = { workspace = true } 33 | ethereum-types = { workspace = true, features = ["rand"] } 34 | kvdb-shared-tests = { workspace = true } 35 | rand = { workspace = true, default-features = true } 36 | tempfile = { workspace = true } 37 | keccak-hash = { workspace = true } 38 | sysinfo = { workspace = true } 39 | ctrlc = { workspace = true } 40 | chrono = { workspace = true } 41 | -------------------------------------------------------------------------------- /kvdb-rocksdb/benches/.gitignore: -------------------------------------------------------------------------------- 1 | _rocksdb_bench_get 2 | -------------------------------------------------------------------------------- /kvdb-rocksdb/examples/memtest.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies (UK) Ltd. 2 | // This file is part of Parity Ethereum. 3 | 4 | // Parity Ethereum is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // Parity Ethereum is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with Parity Ethereum. If not, see . 16 | 17 | // This program starts writing random data to the database with 100 (COLUMN_COUNT) 18 | // columns and never stops until interrupted. 19 | 20 | use ethereum_types::H256; 21 | use keccak_hash::keccak; 22 | use kvdb_rocksdb::{Database, DatabaseConfig}; 23 | use std::sync::{ 24 | atomic::{AtomicBool, Ordering as AtomicOrdering}, 25 | Arc, 26 | }; 27 | use sysinfo::{get_current_pid, System}; 28 | 29 | const COLUMN_COUNT: u32 = 100; 30 | 31 | #[derive(Clone)] 32 | struct KeyValue { 33 | key: H256, 34 | val: H256, 35 | } 36 | 37 | fn next(seed: H256) -> H256 { 38 | let mut buf = [0u8; 33]; 39 | buf[0..32].copy_from_slice(&seed[..]); 40 | buf[32] = 1; 41 | 42 | keccak(&buf[..]) 43 | } 44 | 45 | impl KeyValue { 46 | fn with_seed(seed: H256) -> Self { 47 | KeyValue { key: next(seed), val: next(next(seed)) } 48 | } 49 | 50 | fn new() -> Self { 51 | Self::with_seed(H256::random()) 52 | } 53 | } 54 | 55 | impl Iterator for KeyValue { 56 | type Item = (H256, H256); 57 | 58 | fn next(&mut self) -> Option { 59 | let result = (self.key, self.val); 60 | self.key = next(self.val); 61 | self.val = next(self.key); 62 | 63 | Some(result) 64 | } 65 | } 66 | 67 | fn proc_memory_usage() -> u64 { 68 | let mut sys = System::new(); 69 | let self_pid = get_current_pid().ok(); 70 | let memory = if let Some(self_pid) = self_pid { 71 | if sys.refresh_process(self_pid) { 72 | let proc = sys 73 | .process(self_pid) 74 | .expect("Above refresh_process succeeds, this should be Some(), qed"); 75 | proc.memory() 76 | } else { 77 | 0 78 | } 79 | } else { 80 | 0 81 | }; 82 | 83 | memory 84 | } 85 | 86 | fn main() { 87 | let mb_per_col = std::env::args() 88 | .nth(1) 89 | .map(|arg| arg.parse().expect("Megabytes per col - should be integer or missing")) 90 | .unwrap_or(1); 91 | 92 | let exit = Arc::new(AtomicBool::new(false)); 93 | let ctrlc_exit = exit.clone(); 94 | 95 | ctrlc::set_handler(move || { 96 | println!("\nRemoving temp database...\n"); 97 | ctrlc_exit.store(true, AtomicOrdering::Relaxed); 98 | }) 99 | .expect("Error setting Ctrl-C handler"); 100 | 101 | let mut config = DatabaseConfig::with_columns(COLUMN_COUNT); 102 | 103 | for c in 0..=COLUMN_COUNT { 104 | config.memory_budget.insert(c, mb_per_col); 105 | } 106 | let dir = tempfile::Builder::new().prefix("rocksdb-example").tempdir().unwrap(); 107 | 108 | println!("Database is put in: {} (maybe check if it was deleted)", dir.path().to_string_lossy()); 109 | let db = Database::open(&config, &dir.path()).unwrap(); 110 | 111 | let mut step = 0; 112 | let mut keyvalues = KeyValue::new(); 113 | while !exit.load(AtomicOrdering::Relaxed) { 114 | let col = step % 100; 115 | 116 | let key_values: Vec<(H256, H256)> = keyvalues.clone().take(128).collect(); 117 | let mut transaction = db.transaction(); 118 | for (k, v) in key_values.iter() { 119 | transaction.put(col, k.as_ref(), v.as_ref()); 120 | } 121 | db.write(transaction).expect("writing failed"); 122 | 123 | let mut seed = H256::zero(); 124 | for (k, _) in key_values.iter() { 125 | let mut buf = [0u8; 64]; 126 | buf[0..32].copy_from_slice(seed.as_ref()); 127 | let val = db.get(col, k.as_ref()).expect("Db fail").expect("Was put above"); 128 | buf[32..64].copy_from_slice(val.as_ref()); 129 | 130 | seed = keccak(&buf[..]); 131 | } 132 | 133 | let mut transaction = db.transaction(); 134 | // delete all but one to avoid too much bloating 135 | for (k, _) in key_values.iter().take(127) { 136 | transaction.delete(col, k.as_ref()); 137 | } 138 | db.write(transaction).expect("delete failed"); 139 | 140 | keyvalues = KeyValue::with_seed(seed); 141 | 142 | if step % 10000 == 9999 { 143 | let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S"); 144 | 145 | println!("{}", timestamp); 146 | println!("\tData written: {} keys - {} Mb", step + 1, ((step + 1) * 64 * 128) / 1024 / 1024); 147 | println!("\tProcess memory used as seen by the OS: {} Mb", proc_memory_usage() / 1024); 148 | } 149 | 150 | step += 1; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /kvdb-rocksdb/src/iter.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! This module contains an implementation of a RocksDB iterator 10 | //! wrapped inside a `RwLock`. Since `RwLock` "owns" the inner data, 11 | //! we're using `owning_ref` to work around the borrowing rules of Rust. 12 | //! 13 | //! Note: this crate does not use "Prefix Seek" mode which means that the prefix iterator 14 | //! will return keys not starting with the given prefix as well (as long as `key >= prefix`). 15 | //! To work around this we set an upper bound to the prefix successor. 16 | //! See https://github.com/facebook/rocksdb/wiki/Prefix-Seek-API-Changes for details. 17 | 18 | use crate::{other_io_err, DBAndColumns, DBKeyValue}; 19 | use rocksdb::{DBIterator, Direction, IteratorMode, ReadOptions}; 20 | use std::io; 21 | 22 | /// Instantiate iterators yielding `io::Result`s. 23 | pub trait IterationHandler { 24 | type Iterator: Iterator>; 25 | 26 | /// Create an `Iterator` over a `ColumnFamily` corresponding to the passed index. Takes 27 | /// `ReadOptions` to allow configuration of the new iterator (see 28 | /// https://github.com/facebook/rocksdb/blob/master/include/rocksdb/options.h#L1169). 29 | fn iter(self, col: u32, read_opts: ReadOptions) -> Self::Iterator; 30 | /// Create an `Iterator` over a `ColumnFamily` corresponding to the passed index. Takes 31 | /// `ReadOptions` to allow configuration of the new iterator (see 32 | /// https://github.com/facebook/rocksdb/blob/master/include/rocksdb/options.h#L1169). 33 | /// The `Iterator` iterates over keys which start with the provided `prefix`. 34 | fn iter_with_prefix(self, col: u32, prefix: &[u8], read_opts: ReadOptions) -> Self::Iterator; 35 | } 36 | 37 | impl<'a> IterationHandler for &'a DBAndColumns { 38 | type Iterator = EitherIter>, std::iter::Once>>; 39 | 40 | fn iter(self, col: u32, read_opts: ReadOptions) -> Self::Iterator { 41 | match self.cf(col as usize) { 42 | Ok(cf) => EitherIter::A(KvdbAdapter(self.db.iterator_cf_opt(cf, read_opts, IteratorMode::Start))), 43 | Err(e) => EitherIter::B(std::iter::once(Err(e))), 44 | } 45 | } 46 | 47 | fn iter_with_prefix(self, col: u32, prefix: &[u8], read_opts: ReadOptions) -> Self::Iterator { 48 | match self.cf(col as usize) { 49 | Ok(cf) => EitherIter::A(KvdbAdapter(self.db.iterator_cf_opt( 50 | cf, 51 | read_opts, 52 | IteratorMode::From(prefix, Direction::Forward), 53 | ))), 54 | Err(e) => EitherIter::B(std::iter::once(Err(e))), 55 | } 56 | } 57 | } 58 | 59 | /// Small enum to avoid boxing iterators. 60 | pub enum EitherIter { 61 | A(A), 62 | B(B), 63 | } 64 | 65 | impl Iterator for EitherIter 66 | where 67 | A: Iterator, 68 | B: Iterator, 69 | { 70 | type Item = I; 71 | 72 | fn next(&mut self) -> Option { 73 | match self { 74 | Self::A(a) => a.next(), 75 | Self::B(b) => b.next(), 76 | } 77 | } 78 | } 79 | 80 | /// A simple wrapper that adheres to the `kvdb` interface. 81 | pub struct KvdbAdapter(T); 82 | 83 | impl Iterator for KvdbAdapter 84 | where 85 | T: Iterator, Box<[u8]>), rocksdb::Error>>, 86 | { 87 | type Item = io::Result; 88 | 89 | fn next(&mut self) -> Option { 90 | self.0 91 | .next() 92 | .map(|r| r.map_err(other_io_err).map(|(k, v)| (k.into_vec().into(), v.into()))) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /kvdb-rocksdb/src/stats.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use parking_lot::RwLock; 10 | use std::{ 11 | collections::HashMap, 12 | str::FromStr, 13 | sync::atomic::{AtomicU64, Ordering as AtomicOrdering}, 14 | time::Instant, 15 | }; 16 | 17 | #[derive(Default, Clone, Copy)] 18 | pub struct RawDbStats { 19 | pub reads: u64, 20 | pub writes: u64, 21 | pub bytes_written: u64, 22 | pub bytes_read: u64, 23 | pub transactions: u64, 24 | pub cache_hit_count: u64, 25 | } 26 | 27 | #[derive(Default, Debug, Clone, Copy)] 28 | pub struct RocksDbStatsTimeValue { 29 | /// 50% percentile 30 | pub p50: f64, 31 | /// 95% percentile 32 | pub p95: f64, 33 | /// 99% percentile 34 | pub p99: f64, 35 | /// 100% percentile 36 | pub p100: f64, 37 | pub sum: u64, 38 | } 39 | 40 | #[derive(Default, Debug, Clone, Copy)] 41 | pub struct RocksDbStatsValue { 42 | pub count: u64, 43 | pub times: Option, 44 | } 45 | 46 | pub fn parse_rocksdb_stats(stats: &str) -> HashMap { 47 | stats.lines().map(|line| parse_rocksdb_stats_row(line.splitn(2, ' '))).collect() 48 | } 49 | 50 | fn parse_rocksdb_stats_row<'a>(mut iter: impl Iterator) -> (String, RocksDbStatsValue) { 51 | const PROOF: &str = "rocksdb statistics format is valid and hasn't changed"; 52 | const SEPARATOR: &str = " : "; 53 | let key = iter.next().expect(PROOF).trim_start_matches("rocksdb.").to_owned(); 54 | let values = iter.next().expect(PROOF); 55 | let value = if values.starts_with("COUNT") { 56 | // rocksdb.row.cache.hit COUNT : 0 57 | RocksDbStatsValue { 58 | count: u64::from_str(values.rsplit(SEPARATOR).next().expect(PROOF)).expect(PROOF), 59 | times: None, 60 | } 61 | } else { 62 | // rocksdb.db.get.micros P50 : 0.000000 P95 : 0.000000 P99 : 0.000000 P100 : 0.000000 COUNT : 0 SUM : 0 63 | let values: Vec<&str> = values.split_whitespace().filter(|s| *s != ":").collect(); 64 | let times = RocksDbStatsTimeValue { 65 | p50: f64::from_str(values.get(1).expect(PROOF)).expect(PROOF), 66 | p95: f64::from_str(values.get(3).expect(PROOF)).expect(PROOF), 67 | p99: f64::from_str(values.get(5).expect(PROOF)).expect(PROOF), 68 | p100: f64::from_str(values.get(7).expect(PROOF)).expect(PROOF), 69 | sum: u64::from_str(values.get(11).expect(PROOF)).expect(PROOF), 70 | }; 71 | RocksDbStatsValue { count: u64::from_str(values.get(9).expect(PROOF)).expect(PROOF), times: Some(times) } 72 | }; 73 | (key, value) 74 | } 75 | 76 | impl RawDbStats { 77 | fn combine(&self, other: &RawDbStats) -> Self { 78 | RawDbStats { 79 | reads: self.reads + other.reads, 80 | writes: self.writes + other.writes, 81 | bytes_written: self.bytes_written + other.bytes_written, 82 | bytes_read: self.bytes_read + other.bytes_written, 83 | transactions: self.transactions + other.transactions, 84 | cache_hit_count: self.cache_hit_count + other.cache_hit_count, 85 | } 86 | } 87 | } 88 | 89 | struct OverallDbStats { 90 | stats: RawDbStats, 91 | last_taken: Instant, 92 | started: Instant, 93 | } 94 | 95 | impl OverallDbStats { 96 | fn new() -> Self { 97 | OverallDbStats { stats: RawDbStats::default(), last_taken: Instant::now(), started: Instant::now() } 98 | } 99 | } 100 | 101 | pub struct RunningDbStats { 102 | reads: AtomicU64, 103 | writes: AtomicU64, 104 | bytes_written: AtomicU64, 105 | bytes_read: AtomicU64, 106 | transactions: AtomicU64, 107 | cache_hit_count: AtomicU64, 108 | overall: RwLock, 109 | } 110 | 111 | pub struct TakenDbStats { 112 | pub raw: RawDbStats, 113 | pub started: Instant, 114 | } 115 | 116 | impl RunningDbStats { 117 | pub fn new() -> Self { 118 | Self { 119 | reads: 0.into(), 120 | bytes_read: 0.into(), 121 | writes: 0.into(), 122 | bytes_written: 0.into(), 123 | transactions: 0.into(), 124 | cache_hit_count: 0.into(), 125 | overall: OverallDbStats::new().into(), 126 | } 127 | } 128 | 129 | pub fn tally_reads(&self, val: u64) { 130 | self.reads.fetch_add(val, AtomicOrdering::Relaxed); 131 | } 132 | 133 | pub fn tally_bytes_read(&self, val: u64) { 134 | self.bytes_read.fetch_add(val, AtomicOrdering::Relaxed); 135 | } 136 | 137 | pub fn tally_writes(&self, val: u64) { 138 | self.writes.fetch_add(val, AtomicOrdering::Relaxed); 139 | } 140 | 141 | pub fn tally_bytes_written(&self, val: u64) { 142 | self.bytes_written.fetch_add(val, AtomicOrdering::Relaxed); 143 | } 144 | 145 | pub fn tally_transactions(&self, val: u64) { 146 | self.transactions.fetch_add(val, AtomicOrdering::Relaxed); 147 | } 148 | 149 | pub fn tally_cache_hit_count(&self, val: u64) { 150 | self.cache_hit_count.fetch_add(val, AtomicOrdering::Relaxed); 151 | } 152 | 153 | fn take_current(&self) -> RawDbStats { 154 | RawDbStats { 155 | reads: self.reads.swap(0, AtomicOrdering::Relaxed), 156 | writes: self.writes.swap(0, AtomicOrdering::Relaxed), 157 | bytes_written: self.bytes_written.swap(0, AtomicOrdering::Relaxed), 158 | bytes_read: self.bytes_read.swap(0, AtomicOrdering::Relaxed), 159 | transactions: self.transactions.swap(0, AtomicOrdering::Relaxed), 160 | cache_hit_count: self.cache_hit_count.swap(0, AtomicOrdering::Relaxed), 161 | } 162 | } 163 | 164 | fn peek_current(&self) -> RawDbStats { 165 | RawDbStats { 166 | reads: self.reads.load(AtomicOrdering::Relaxed), 167 | writes: self.writes.load(AtomicOrdering::Relaxed), 168 | bytes_written: self.bytes_written.load(AtomicOrdering::Relaxed), 169 | bytes_read: self.bytes_read.load(AtomicOrdering::Relaxed), 170 | transactions: self.transactions.load(AtomicOrdering::Relaxed), 171 | cache_hit_count: self.cache_hit_count.load(AtomicOrdering::Relaxed), 172 | } 173 | } 174 | 175 | pub fn since_previous(&self) -> TakenDbStats { 176 | let mut overall_lock = self.overall.write(); 177 | 178 | let current = self.take_current(); 179 | 180 | overall_lock.stats = overall_lock.stats.combine(¤t); 181 | 182 | let stats = TakenDbStats { raw: current, started: overall_lock.last_taken }; 183 | 184 | overall_lock.last_taken = Instant::now(); 185 | 186 | stats 187 | } 188 | 189 | pub fn overall(&self) -> TakenDbStats { 190 | let overall_lock = self.overall.read(); 191 | 192 | let current = self.peek_current(); 193 | 194 | TakenDbStats { raw: overall_lock.stats.combine(¤t), started: overall_lock.started } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /kvdb-shared-tests/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.11.0] - 2022-11-29 10 | - Removed `parity-util-mem` support. [#696](https://github.com/paritytech/parity-common/pull/696) 11 | 12 | ## [0.10.0] - 2022-09-20 13 | ### Breaking 14 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 15 | - Updated `kvdb` to 0.12. [#680](https://github.com/paritytech/parity-common/pull/680) 16 | 17 | ### Breaking 18 | - Updated `kvdb` to 0.10. [#556](https://github.com/paritytech/parity-common/pull/556) 19 | 20 | ## [0.7.0] - 2021-01-27 21 | ### Breaking 22 | - Updated `kvdb` to 0.9. [#510](https://github.com/paritytech/parity-common/pull/510) 23 | -------------------------------------------------------------------------------- /kvdb-shared-tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kvdb-shared-tests" 3 | version = "0.11.0" 4 | description = "Shared tests for kvdb functionality, to be executed against actual implementations" 5 | rust-version = "1.56.1" 6 | authors.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | kvdb = { workspace = true } 14 | -------------------------------------------------------------------------------- /kvdb/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | 9 | 10 | ## [0.13.0] - 2022-11-29 11 | - Removed `parity-util-mem` support. [#696](https://github.com/paritytech/parity-common/pull/696) 12 | 13 | ## [0.12.0] - 2022-09-20 14 | ### Breaking 15 | - Removed `fn restore` from `KeyValueDB` trait. [#662](https://github.com/paritytech/parity-common/pull/662) 16 | - Streamlined API. [#661](https://github.com/paritytech/parity-common/pull/661) 17 | - `fn get_by_prefix` return type changed to `io::Result>` 18 | - `fn has_prefix` return type changed to `io::Result` 19 | - Iterator item changed to `io::Result` 20 | - Updated `parity-util-mem` to 0.12. [#680](https://github.com/paritytech/parity-common/pull/680) 21 | 22 | ## [0.11.0] - 2022-02-04 23 | ### Breaking 24 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 25 | - Updated `parity-util-mem` to 0.11. [#623](https://github.com/paritytech/parity-common/pull/623) 26 | 27 | ## [0.10.0] - 2021-07-02 28 | ### Breaking 29 | - Updated `parity-util-mem` to 0.10. [#556](https://github.com/paritytech/parity-common/pull/556) 30 | 31 | ## [0.9.0] - 2021-01-27 32 | ### Breaking 33 | - Updated `parity-util-mem` to 0.9. [#510](https://github.com/paritytech/parity-common/pull/510) 34 | 35 | ## [0.8.0] - 2021-01-05 36 | ### Breaking 37 | - Updated `parity-util-mem` to 0.8. [#470](https://github.com/paritytech/parity-common/pull/470) 38 | 39 | ## [0.7.0] - 2020-06-24 40 | - Updated `parity-util-mem` to 0.7. [#402](https://github.com/paritytech/parity-common/pull/402) 41 | 42 | ## [0.6.0] - 2020-05-05 43 | ### Breaking 44 | - Removed `write_buffered` and `flush` methods. [#313](https://github.com/paritytech/parity-common/pull/313) 45 | - Introduced a new `DeletePrefix` database operation. [#360](https://github.com/paritytech/parity-common/pull/360) 46 | - Renamed prefix iteration to `iter_with_prefix`. [#365](https://github.com/paritytech/parity-common/pull/365) 47 | 48 | ## [0.5.0] - 2020-03-16 49 | - License changed from GPL3 to dual MIT/Apache2. [#342](https://github.com/paritytech/parity-common/pull/342) 50 | - Remove dependency on parity-bytes. [#351](https://github.com/paritytech/parity-common/pull/351) 51 | - Updated dependencies. [#361](https://github.com/paritytech/parity-common/pull/361) 52 | 53 | ## [0.4.0] - 2019-01-06 54 | - Bump parking_lot to 0.10. [#332](https://github.com/paritytech/parity-common/pull/332) 55 | 56 | ## [0.3.1] - 2019-01-06 57 | - Updated features and feature dependencies. [#307](https://github.com/paritytech/parity-common/pull/307) 58 | 59 | ## [0.3.0] - 2020-01-03 60 | - I/O statistics API. [#294](https://github.com/paritytech/parity-common/pull/294) 61 | - Removed `KeyValueDBHandler` trait. [#304](https://github.com/paritytech/parity-common/pull/304) 62 | 63 | ## [0.2.0] - 2019-12-19 64 | ### Changed 65 | - Default column support removed from the API 66 | - Column argument type changed from `Option` to `u32` 67 | - Migration `None` -> unsupported, `Some(0)` -> `0`, `Some(1)` -> `1`, etc. 68 | - Remove `ElasticArray` and change `DBValue` to be a type alias for `Vec` and add a `DBKey` backed by a `SmallVec`. [#282](https://github.com/paritytech/parity-common/pull/282) 69 | 70 | ## [0.1.1] - 2019-10-24 71 | ### Dependencies 72 | - Updated dependencies. [#239](https://github.com/paritytech/parity-common/pull/239) 73 | ### Changed 74 | - Migrated to 2018 edition. [#205](https://github.com/paritytech/parity-common/pull/205) 75 | -------------------------------------------------------------------------------- /kvdb/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kvdb" 3 | version = "0.13.0" 4 | description = "Generic key-value trait" 5 | rust-version = "1.56.1" 6 | authors.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | smallvec = { workspace = true } 14 | -------------------------------------------------------------------------------- /kvdb/src/io_stats.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Generic statistics for key-value databases 10 | 11 | /// Statistic kind to query. 12 | pub enum Kind { 13 | /// Overall statistics since start. 14 | Overall, 15 | /// Statistics since previous query. 16 | SincePrevious, 17 | } 18 | 19 | /// Statistic for the `span` period 20 | #[derive(Debug, Clone)] 21 | pub struct IoStats { 22 | /// Number of transaction. 23 | pub transactions: u64, 24 | /// Number of read operations. 25 | pub reads: u64, 26 | /// Number of reads resulted in a read from cache. 27 | pub cache_reads: u64, 28 | /// Number of write operations. 29 | pub writes: u64, 30 | /// Number of bytes read 31 | pub bytes_read: u64, 32 | /// Number of bytes read from cache 33 | pub cache_read_bytes: u64, 34 | /// Number of bytes write 35 | pub bytes_written: u64, 36 | /// Start of the statistic period. 37 | pub started: std::time::Instant, 38 | /// Total duration of the statistic period. 39 | pub span: std::time::Duration, 40 | } 41 | 42 | impl IoStats { 43 | /// Empty statistic report. 44 | pub fn empty() -> Self { 45 | Self { 46 | transactions: 0, 47 | reads: 0, 48 | cache_reads: 0, 49 | writes: 0, 50 | bytes_read: 0, 51 | cache_read_bytes: 0, 52 | bytes_written: 0, 53 | started: std::time::Instant::now(), 54 | span: std::time::Duration::default(), 55 | } 56 | } 57 | 58 | /// Average batch (transaction) size (writes per transaction) 59 | pub fn avg_batch_size(&self) -> f64 { 60 | if self.writes == 0 { 61 | return 0.0 62 | } 63 | self.transactions as f64 / self.writes as f64 64 | } 65 | 66 | /// Read operations per second. 67 | pub fn reads_per_sec(&self) -> f64 { 68 | if self.span.as_secs_f64() == 0.0 { 69 | return 0.0 70 | } 71 | 72 | self.reads as f64 / self.span.as_secs_f64() 73 | } 74 | 75 | pub fn byte_reads_per_sec(&self) -> f64 { 76 | if self.span.as_secs_f64() == 0.0 { 77 | return 0.0 78 | } 79 | 80 | self.bytes_read as f64 / self.span.as_secs_f64() 81 | } 82 | 83 | /// Write operations per second. 84 | pub fn writes_per_sec(&self) -> f64 { 85 | if self.span.as_secs_f64() == 0.0 { 86 | return 0.0 87 | } 88 | 89 | self.writes as f64 / self.span.as_secs_f64() 90 | } 91 | 92 | pub fn byte_writes_per_sec(&self) -> f64 { 93 | if self.span.as_secs_f64() == 0.0 { 94 | return 0.0 95 | } 96 | 97 | self.bytes_written as f64 / self.span.as_secs_f64() 98 | } 99 | 100 | /// Total number of operations per second. 101 | pub fn ops_per_sec(&self) -> f64 { 102 | if self.span.as_secs_f64() == 0.0 { 103 | return 0.0 104 | } 105 | 106 | (self.writes as f64 + self.reads as f64) / self.span.as_secs_f64() 107 | } 108 | 109 | /// Transactions per second. 110 | pub fn transactions_per_sec(&self) -> f64 { 111 | if self.span.as_secs_f64() == 0.0 { 112 | return 0.0 113 | } 114 | 115 | (self.transactions as f64) / self.span.as_secs_f64() 116 | } 117 | 118 | pub fn avg_transaction_size(&self) -> f64 { 119 | if self.transactions == 0 { 120 | return 0.0 121 | } 122 | 123 | self.bytes_written as f64 / self.transactions as f64 124 | } 125 | 126 | pub fn cache_hit_ratio(&self) -> f64 { 127 | if self.reads == 0 { 128 | return 0.0 129 | } 130 | 131 | self.cache_reads as f64 / self.reads as f64 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /kvdb/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Key-Value store abstraction. 10 | 11 | use smallvec::SmallVec; 12 | use std::io; 13 | 14 | mod io_stats; 15 | 16 | /// Required length of prefixes. 17 | pub const PREFIX_LEN: usize = 12; 18 | 19 | /// Database value. 20 | pub type DBValue = Vec; 21 | /// Database keys. 22 | pub type DBKey = SmallVec<[u8; 32]>; 23 | /// A tuple holding key and value data, used in the iterator item type. 24 | pub type DBKeyValue = (DBKey, DBValue); 25 | 26 | pub use io_stats::{IoStats, Kind as IoStatsKind}; 27 | 28 | /// Write transaction. Batches a sequence of put/delete operations for efficiency. 29 | #[derive(Default, Clone, PartialEq)] 30 | pub struct DBTransaction { 31 | /// Database operations. 32 | pub ops: Vec, 33 | } 34 | 35 | /// Database operation. 36 | #[derive(Clone, PartialEq)] 37 | pub enum DBOp { 38 | Insert { col: u32, key: DBKey, value: DBValue }, 39 | Delete { col: u32, key: DBKey }, 40 | DeletePrefix { col: u32, prefix: DBKey }, 41 | } 42 | 43 | impl DBOp { 44 | /// Returns the key associated with this operation. 45 | pub fn key(&self) -> &[u8] { 46 | match *self { 47 | DBOp::Insert { ref key, .. } => key, 48 | DBOp::Delete { ref key, .. } => key, 49 | DBOp::DeletePrefix { ref prefix, .. } => prefix, 50 | } 51 | } 52 | 53 | /// Returns the column associated with this operation. 54 | pub fn col(&self) -> u32 { 55 | match *self { 56 | DBOp::Insert { col, .. } => col, 57 | DBOp::Delete { col, .. } => col, 58 | DBOp::DeletePrefix { col, .. } => col, 59 | } 60 | } 61 | } 62 | 63 | impl DBTransaction { 64 | /// Create new transaction. 65 | pub fn new() -> DBTransaction { 66 | DBTransaction::with_capacity(256) 67 | } 68 | 69 | /// Create new transaction with capacity. 70 | pub fn with_capacity(cap: usize) -> DBTransaction { 71 | DBTransaction { ops: Vec::with_capacity(cap) } 72 | } 73 | 74 | /// Insert a key-value pair in the transaction. Any existing value will be overwritten upon write. 75 | pub fn put(&mut self, col: u32, key: &[u8], value: &[u8]) { 76 | self.ops 77 | .push(DBOp::Insert { col, key: DBKey::from_slice(key), value: value.to_vec() }) 78 | } 79 | 80 | /// Insert a key-value pair in the transaction. Any existing value will be overwritten upon write. 81 | pub fn put_vec(&mut self, col: u32, key: &[u8], value: Vec) { 82 | self.ops.push(DBOp::Insert { col, key: DBKey::from_slice(key), value }); 83 | } 84 | 85 | /// Delete value by key. 86 | pub fn delete(&mut self, col: u32, key: &[u8]) { 87 | self.ops.push(DBOp::Delete { col, key: DBKey::from_slice(key) }); 88 | } 89 | 90 | /// Delete all values with the given key prefix. 91 | /// Using an empty prefix here will remove all keys 92 | /// (all keys start with the empty prefix). 93 | pub fn delete_prefix(&mut self, col: u32, prefix: &[u8]) { 94 | self.ops.push(DBOp::DeletePrefix { col, prefix: DBKey::from_slice(prefix) }); 95 | } 96 | } 97 | 98 | /// Generic key-value database. 99 | /// 100 | /// The `KeyValueDB` deals with "column families", which can be thought of as distinct 101 | /// stores within a database. Keys written in one column family will not be accessible from 102 | /// any other. The number of column families must be specified at initialization, with a 103 | /// differing interface for each database. 104 | /// 105 | /// The API laid out here, along with the `Sync` bound implies interior synchronization for 106 | /// implementation. 107 | pub trait KeyValueDB: Sync + Send { 108 | /// Helper to create a new transaction. 109 | fn transaction(&self) -> DBTransaction { 110 | DBTransaction::new() 111 | } 112 | 113 | /// Get a value by key. 114 | fn get(&self, col: u32, key: &[u8]) -> io::Result>; 115 | 116 | /// Get the first value matching the given prefix. 117 | fn get_by_prefix(&self, col: u32, prefix: &[u8]) -> io::Result>; 118 | 119 | /// Write a transaction of changes to the backing store. 120 | fn write(&self, transaction: DBTransaction) -> io::Result<()>; 121 | 122 | /// Iterate over the data for a given column. 123 | fn iter<'a>(&'a self, col: u32) -> Box> + 'a>; 124 | 125 | /// Iterate over the data for a given column, returning all key/value pairs 126 | /// where the key starts with the given prefix. 127 | fn iter_with_prefix<'a>( 128 | &'a self, 129 | col: u32, 130 | prefix: &'a [u8], 131 | ) -> Box> + 'a>; 132 | 133 | /// Query statistics. 134 | /// 135 | /// Not all kvdb implementations are able or expected to implement this, so by 136 | /// default, empty statistics is returned. Also, not all kvdb implementations 137 | /// can return every statistic or configured to do so (some statistics gathering 138 | /// may impede the performance and might be off by default). 139 | fn io_stats(&self, _kind: IoStatsKind) -> IoStats { 140 | IoStats::empty() 141 | } 142 | 143 | /// Check for the existence of a value by key. 144 | fn has_key(&self, col: u32, key: &[u8]) -> io::Result { 145 | self.get(col, key).map(|opt| opt.is_some()) 146 | } 147 | 148 | /// Check for the existence of a value by prefix. 149 | fn has_prefix(&self, col: u32, prefix: &[u8]) -> io::Result { 150 | self.get_by_prefix(col, prefix).map(|opt| opt.is_some()) 151 | } 152 | } 153 | 154 | /// For a given start prefix (inclusive), returns the correct end prefix (non-inclusive). 155 | /// This assumes the key bytes are ordered in lexicographical order. 156 | /// Since key length is not limited, for some case we return `None` because there is 157 | /// no bounded limit (every keys in the serie `[]`, `[255]`, `[255, 255]` ...). 158 | pub fn end_prefix(prefix: &[u8]) -> Option> { 159 | let mut end_range = prefix.to_vec(); 160 | while let Some(0xff) = end_range.last() { 161 | end_range.pop(); 162 | } 163 | if let Some(byte) = end_range.last_mut() { 164 | *byte += 1; 165 | Some(end_range) 166 | } else { 167 | None 168 | } 169 | } 170 | 171 | #[cfg(test)] 172 | mod test { 173 | use super::end_prefix; 174 | 175 | #[test] 176 | fn end_prefix_test() { 177 | assert_eq!(end_prefix(&[5, 6, 7]), Some(vec![5, 6, 8])); 178 | assert_eq!(end_prefix(&[5, 6, 255]), Some(vec![5, 7])); 179 | // This is not equal as the result is before start. 180 | assert_ne!(end_prefix(&[5, 255, 255]), Some(vec![5, 255])); 181 | // This is equal ([5, 255] will not be deleted because 182 | // it is before start). 183 | assert_eq!(end_prefix(&[5, 255, 255]), Some(vec![6])); 184 | assert_eq!(end_prefix(&[255, 255, 255]), None); 185 | 186 | assert_eq!(end_prefix(&[0x00, 0xff]), Some(vec![0x01])); 187 | assert_eq!(end_prefix(&[0xff]), None); 188 | assert_eq!(end_prefix(&[]), None); 189 | assert_eq!(end_prefix(b"0"), Some(b"1".to_vec())); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /license-header: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | -------------------------------------------------------------------------------- /parity-bytes/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 9 | 10 | ## [0.1.2] - 2020-03-16 11 | - License changed from GPL3 to dual MIT/Apache2. [#342](https://github.com/paritytech/parity-common/pull/342) 12 | 13 | ## [0.1.1] - 2019-10-24 14 | ### Dependencies 15 | - Updated dependencies. [#239](https://github.com/paritytech/parity-common/pull/239) 16 | ### Added 17 | - Added no-std support. [#154](https://github.com/paritytech/parity-common/pull/154) 18 | -------------------------------------------------------------------------------- /parity-bytes/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parity-bytes" 3 | version = "0.1.2" 4 | description = "byte utilities for Parity" 5 | readme = "README.md" 6 | rust-version = "1.56.1" 7 | authors.workspace = true 8 | edition.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | 13 | [features] 14 | default = ["std"] 15 | std = [] 16 | -------------------------------------------------------------------------------- /parity-bytes/README.md: -------------------------------------------------------------------------------- 1 | ## `no_std` support 2 | 3 | This crate has a feature, `std`, that is enabled by default. To use this crate 4 | in a `no_std` context, add the following to your `Cargo.toml` (still requires allocator though): 5 | 6 | ```toml 7 | [dependencies] 8 | parity-bytes = { version = "0.1", default-features = false } 9 | ``` 10 | 11 | Until allocator api is stabilized, this type of use is limited to nightly Rust. 12 | -------------------------------------------------------------------------------- /parity-bytes/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! General bytes-related utilities. 10 | //! 11 | //! Includes a pretty-printer for bytes, in the form of `ToPretty` and `PrettySlice` 12 | //! as 13 | 14 | #![cfg_attr(not(feature = "std"), no_std)] 15 | 16 | #[cfg(not(feature = "std"))] 17 | extern crate alloc; 18 | 19 | #[cfg(not(feature = "std"))] 20 | use alloc::{format, string::String, vec::Vec}; 21 | use core::{cmp::min, fmt, ops}; 22 | 23 | /// Slice pretty print helper 24 | pub struct PrettySlice<'a>(&'a [u8]); 25 | 26 | impl<'a> fmt::Debug for PrettySlice<'a> { 27 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 28 | for i in 0..self.0.len() { 29 | if i > 0 { 30 | write!(f, "·{:02x}", self.0[i])?; 31 | } else { 32 | write!(f, "{:02x}", self.0[i])?; 33 | } 34 | } 35 | Ok(()) 36 | } 37 | } 38 | 39 | impl<'a> fmt::Display for PrettySlice<'a> { 40 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 41 | for i in 0..self.0.len() { 42 | write!(f, "{:02x}", self.0[i])?; 43 | } 44 | Ok(()) 45 | } 46 | } 47 | 48 | /// Trait to allow a type to be pretty-printed in `format!`, where unoverridable 49 | /// defaults cannot otherwise be avoided. 50 | pub trait ToPretty { 51 | /// Convert a type into a derivative form in order to make `format!` print it prettily. 52 | fn pretty(&self) -> PrettySlice<'_>; 53 | /// Express the object as a hex string. 54 | fn to_hex(&self) -> String { 55 | format!("{}", self.pretty()) 56 | } 57 | } 58 | 59 | impl> ToPretty for T { 60 | fn pretty(&self) -> PrettySlice<'_> { 61 | PrettySlice(self.as_ref()) 62 | } 63 | } 64 | 65 | /// A byte collection reference that can either be a slice or a vector 66 | pub enum BytesRef<'a> { 67 | /// This is a reference to a vector 68 | Flexible(&'a mut Bytes), 69 | /// This is a reference to a slice 70 | Fixed(&'a mut [u8]), 71 | } 72 | 73 | impl<'a> BytesRef<'a> { 74 | /// Writes given `input` to this `BytesRef` starting at `offset`. 75 | /// Returns number of bytes written to the ref. 76 | /// NOTE can return number greater then `input.len()` in case flexible vector had to be extended. 77 | pub fn write(&mut self, offset: usize, input: &[u8]) -> usize { 78 | match *self { 79 | BytesRef::Flexible(ref mut data) => { 80 | let data_len = data.len(); 81 | let wrote = input.len() + if data_len > offset { 0 } else { offset - data_len }; 82 | 83 | data.resize(offset, 0); 84 | data.extend_from_slice(input); 85 | wrote 86 | }, 87 | BytesRef::Fixed(ref mut data) if offset < data.len() => { 88 | let max = min(data.len() - offset, input.len()); 89 | data[offset..(max + offset)].copy_from_slice(&input[..max]); 90 | max 91 | }, 92 | _ => 0, 93 | } 94 | } 95 | } 96 | 97 | impl<'a> ops::Deref for BytesRef<'a> { 98 | type Target = [u8]; 99 | 100 | fn deref(&self) -> &[u8] { 101 | match *self { 102 | BytesRef::Flexible(ref bytes) => bytes, 103 | BytesRef::Fixed(ref bytes) => bytes, 104 | } 105 | } 106 | } 107 | 108 | impl<'a> ops::DerefMut for BytesRef<'a> { 109 | fn deref_mut(&mut self) -> &mut [u8] { 110 | match *self { 111 | BytesRef::Flexible(ref mut bytes) => bytes, 112 | BytesRef::Fixed(ref mut bytes) => bytes, 113 | } 114 | } 115 | } 116 | 117 | /// Vector of bytes. 118 | pub type Bytes = Vec; 119 | 120 | #[cfg(test)] 121 | mod tests { 122 | use super::BytesRef; 123 | #[cfg(not(feature = "std"))] 124 | use alloc::vec; 125 | 126 | #[test] 127 | fn should_write_bytes_to_fixed_bytesref() { 128 | // given 129 | let mut data1 = vec![0, 0, 0]; 130 | let mut data2 = vec![0, 0, 0]; 131 | let (res1, res2) = { 132 | let mut bytes1 = BytesRef::Fixed(&mut data1[..]); 133 | let mut bytes2 = BytesRef::Fixed(&mut data2[1..2]); 134 | 135 | // when 136 | let res1 = bytes1.write(1, &[1, 1, 1]); 137 | let res2 = bytes2.write(3, &[1, 1, 1]); 138 | (res1, res2) 139 | }; 140 | 141 | // then 142 | assert_eq!(&data1, &[0, 1, 1]); 143 | assert_eq!(res1, 2); 144 | 145 | assert_eq!(&data2, &[0, 0, 0]); 146 | assert_eq!(res2, 0); 147 | } 148 | 149 | #[test] 150 | fn should_write_bytes_to_flexible_bytesref() { 151 | // given 152 | let mut data1 = vec![0, 0, 0]; 153 | let mut data2 = vec![0, 0, 0]; 154 | let mut data3 = vec![0, 0, 0]; 155 | let (res1, res2, res3) = { 156 | let mut bytes1 = BytesRef::Flexible(&mut data1); 157 | let mut bytes2 = BytesRef::Flexible(&mut data2); 158 | let mut bytes3 = BytesRef::Flexible(&mut data3); 159 | 160 | // when 161 | let res1 = bytes1.write(1, &[1, 1, 1]); 162 | let res2 = bytes2.write(3, &[1, 1, 1]); 163 | let res3 = bytes3.write(5, &[1, 1, 1]); 164 | (res1, res2, res3) 165 | }; 166 | 167 | // then 168 | assert_eq!(&data1, &[0, 1, 1, 1]); 169 | assert_eq!(res1, 3); 170 | 171 | assert_eq!(&data2, &[0, 0, 0, 1, 1, 1]); 172 | assert_eq!(res2, 3); 173 | 174 | assert_eq!(&data3, &[0, 0, 0, 0, 0, 1, 1, 1]); 175 | assert_eq!(res3, 5); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /primitive-types/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | ### Breaking 9 | - removed `byteorder` feature [#872](https://github.com/paritytech/parity-common/pull/872) 10 | 11 | ## [0.13.1] - 2024-09-12 12 | - Updated `uint` to 0.10. [#859](https://github.com/paritytech/parity-common/pull/859) 13 | 14 | ## [0.12.2] - 2023-10-10 15 | - Added `schemars` support via `json-schema` feature. [#785](https://github.com/paritytech/parity-common/pull/785) 16 | 17 | ## [0.12.1] - 2022-10-27 18 | - Added `H384` and `H768` types. [#684](https://github.com/paritytech/parity-common/pull/684) 19 | 20 | ## [0.12.0] - 2022-09-20 21 | ### Breaking 22 | - Updated `fixed-hash` to 0.8. [#680](https://github.com/paritytech/parity-common/pull/680) 23 | - Uses weak-dependency feature of cargo. [#664](https://github.com/paritytech/parity-common/pull/664) 24 | 25 | ## [0.11.1] - 2022-02-07 26 | - Updated `scale-info` to ">=0.9, <3". [#627](https://github.com/paritytech/parity-common/pull/627) 27 | 28 | ## [0.11.0] - 2022-02-04 29 | ### Breaking 30 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 31 | - Updated `impl-codec` to 0.6. [#623](https://github.com/paritytech/parity-common/pull/623) 32 | 33 | ## [0.10.1] - 2021-07-02 34 | ### Added 35 | - Implemented `parity_scale_codec::MaxEncodedLen` trait for `{U128, U256, U512}` and `{H128, H160, H256, H512}` types. 36 | 37 | ## [0.10.0] - 2021-07-02 38 | ### Added 39 | - Added `U128::full_mul` method. [#546](https://github.com/paritytech/parity-common/pull/546) 40 | ### Breaking 41 | - Updated `scale-info` to 0.9. [#556](https://github.com/paritytech/parity-common/pull/556) 42 | ### Removed 43 | - Removed `parity-scale-codec` direct dependency. [#556](https://github.com/paritytech/parity-common/pull/556) 44 | 45 | ## [0.9.0] - 2021-01-27 46 | ### Breaking 47 | - Updated `impl-codec` to 0.5. [#510](https://github.com/paritytech/parity-common/pull/510) 48 | - Updated `scale-info` to 0.5. [#510](https://github.com/paritytech/parity-common/pull/510) 49 | 50 | ## [0.8.0] - 2021-01-05 51 | - Added `num-traits` feature. [#480](https://github.com/paritytech/parity-common/pull/480) 52 | ### Breaking 53 | - Updated `impl-rlp` to `rlp` 0.5. [#463](https://github.com/paritytech/parity-common/pull/463) 54 | - Updated `uint` to 0.9. [#486](https://github.com/paritytech/parity-common/pull/486) 55 | 56 | ## [0.7.3] - 2020-11-12 57 | - Added `scale_info` support. [#312](https://github.com/paritytech/parity-common/pull/312) 58 | - Added `H128` type. [#434](https://github.com/paritytech/parity-common/pull/434) 59 | - Added `fp-conversion` feature: `U256` <-> `f64`. [#436](https://github.com/paritytech/parity-common/pull/436) 60 | 61 | ## [0.7.2] - 2020-05-05 62 | - Added `serde_no_std` feature. [#385](https://github.com/paritytech/parity-common/pull/385) 63 | 64 | ## [0.7.1] - 2020-04-27 65 | - Added `arbitrary` feature. [#378](https://github.com/paritytech/parity-common/pull/378) 66 | 67 | ## [0.7.0] - 2020-03-16 68 | - Removed `libc` feature. [#317](https://github.com/paritytech/parity-common/pull/317) 69 | 70 | ## [0.6.2] - 2019-01-03 71 | - Expose to_hex and from_hex from impl-serde. [#302](https://github.com/paritytech/parity-common/pull/302) 72 | 73 | ## [0.6.1] - 2019-10-24 74 | ### Dependencies 75 | - Updated dependencies. [#239](https://github.com/paritytech/parity-common/pull/239) 76 | -------------------------------------------------------------------------------- /primitive-types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "primitive-types" 3 | version = "0.13.1" 4 | description = "Primitive types shared by Ethereum and Substrate" 5 | rust-version = "1.79.0" 6 | authors.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | fixed-hash = { workspace = true } 14 | uint = { workspace = true } 15 | impl-serde = { workspace = true, optional = true } 16 | impl-codec = { workspace = true, optional = true } 17 | impl-num-traits = { workspace = true, optional = true } 18 | impl-rlp = { workspace = true, optional = true } 19 | scale-info = { workspace = true, features = ["derive"], optional = true } 20 | schemars = { workspace = true, optional = true } 21 | 22 | [dev-dependencies] 23 | num-traits = { workspace = true } 24 | serde_json = { workspace = true } 25 | jsonschema = { workspace = true } 26 | 27 | [features] 28 | default = ["std", "rand"] 29 | std = ["uint/std", "fixed-hash/std", "impl-codec?/std"] 30 | rand = ["fixed-hash/rand"] 31 | rustc-hex = ["fixed-hash/rustc-hex"] 32 | serde = ["std", "impl-serde", "impl-serde/std"] 33 | json-schema = ["dep:schemars"] 34 | serde_no_std = ["impl-serde"] 35 | codec = ["impl-codec"] 36 | scale-info = ["codec", "dep:scale-info"] 37 | rlp = ["impl-rlp"] 38 | arbitrary = ["fixed-hash/arbitrary", "uint/arbitrary"] 39 | fp-conversion = ["std"] 40 | num-traits = ["impl-num-traits"] 41 | 42 | [[test]] 43 | name = "scale_info" 44 | required-features = ["scale-info"] 45 | 46 | [[test]] 47 | name = "fp_conversion" 48 | required-features = ["fp-conversion"] 49 | 50 | [[test]] 51 | name = "num_traits" 52 | required-features = ["num-traits"] 53 | -------------------------------------------------------------------------------- /primitive-types/impls/codec/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.7.1] - 2025-02-11 10 | - Implement `DecodeWithMemTracking` for some structs [#897](https://github.com/paritytech/parity-common/pull/897) 11 | 12 | ## [0.7.0] - 2024-09-12 13 | ### Breaking 14 | - Updated to `uint` 0.10. [#860](https://github.com/paritytech/parity-common/pull/860) 15 | 16 | ## [0.6.0] - 2022-02-04 17 | ### Breaking 18 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 19 | - Updated `parity-scale-codec` to 3.0. [#622](https://github.com/paritytech/parity-common/pull/622) 20 | 21 | ## [0.5.1] - 2021-07-02 22 | ### Dependencies 23 | - Updated `parity-scale-codec` to 2.2. [#552](https://github.com/paritytech/parity-common/pull/552) 24 | 25 | ## [0.5.0] - 2021-01-27 26 | ### Breaking 27 | - Updated `parity-scale-codec` to 2.0. [#510](https://github.com/paritytech/parity-common/pull/510) 28 | -------------------------------------------------------------------------------- /primitive-types/impls/codec/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "impl-codec" 3 | version = "0.7.1" 4 | description = "Parity Codec serialization support for uint and fixed hash." 5 | rust-version = "1.56.1" 6 | authors.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | scale-codec = { workspace = true, features = ["max-encoded-len"] } 14 | 15 | [features] 16 | default = ["std"] 17 | std = ["scale-codec/std"] 18 | -------------------------------------------------------------------------------- /primitive-types/impls/codec/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Parity Codec serialization support for uint and fixed hash. 10 | 11 | #![cfg_attr(not(feature = "std"), no_std)] 12 | 13 | #[doc(hidden)] 14 | pub use scale_codec as codec; 15 | 16 | /// Add Parity Codec serialization support to an integer created by `construct_uint!`. 17 | #[macro_export] 18 | macro_rules! impl_uint_codec { 19 | ($name: ident, $len: expr) => { 20 | impl $crate::codec::Encode for $name { 21 | fn using_encoded R>(&self, f: F) -> R { 22 | let bytes = self.to_little_endian(); 23 | bytes.using_encoded(f) 24 | } 25 | } 26 | 27 | impl $crate::codec::EncodeLike for $name {} 28 | 29 | impl $crate::codec::Decode for $name { 30 | fn decode(input: &mut I) -> core::result::Result { 31 | <[u8; $len * 8] as $crate::codec::Decode>::decode(input).map(|b| $name::from_little_endian(&b)) 32 | } 33 | } 34 | 35 | impl $crate::codec::DecodeWithMemTracking for $name {} 36 | 37 | impl $crate::codec::MaxEncodedLen for $name { 38 | fn max_encoded_len() -> usize { 39 | ::core::mem::size_of::<$name>() 40 | } 41 | } 42 | }; 43 | } 44 | 45 | /// Add Parity Codec serialization support to a fixed-sized hash type created by `construct_fixed_hash!`. 46 | #[macro_export] 47 | macro_rules! impl_fixed_hash_codec { 48 | ($name: ident, $len: expr) => { 49 | impl $crate::codec::Encode for $name { 50 | fn using_encoded R>(&self, f: F) -> R { 51 | self.0.using_encoded(f) 52 | } 53 | } 54 | 55 | impl $crate::codec::EncodeLike for $name {} 56 | 57 | impl $crate::codec::Decode for $name { 58 | fn decode(input: &mut I) -> core::result::Result { 59 | <[u8; $len] as $crate::codec::Decode>::decode(input).map($name) 60 | } 61 | } 62 | 63 | impl $crate::codec::DecodeWithMemTracking for $name {} 64 | 65 | impl $crate::codec::MaxEncodedLen for $name { 66 | fn max_encoded_len() -> usize { 67 | ::core::mem::size_of::<$name>() 68 | } 69 | } 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /primitive-types/impls/num-traits/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | - Added missing num-traits impls for uint types. [#898](https://github.com/paritytech/parity-common/pull/898) 9 | 10 | ## [0.2.0] - 2024-09-11 11 | - Updated `uint` to 0.10. [#859](https://github.com/paritytech/parity-common/pull/859) 12 | 13 | ## [0.1.2] - 2023-02-01 14 | - Added `checked_*` trait impls. [#716](https://github.com/paritytech/parity-common/pull/716) 15 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 16 | 17 | ## [0.1.1] - 2021-06-30 18 | - Added `integer-sqrt` trait support. [#554](https://github.com/paritytech/parity-common/pull/554) 19 | -------------------------------------------------------------------------------- /primitive-types/impls/num-traits/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "impl-num-traits" 3 | version = "0.2.0" 4 | description = "num-traits implementation for uint." 5 | rust-version = "1.56.1" 6 | authors.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | num-traits = { workspace = true } 14 | integer-sqrt = { workspace = true } 15 | uint = { workspace = true } 16 | -------------------------------------------------------------------------------- /primitive-types/impls/num-traits/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! num-traits support for uint. 10 | 11 | #![no_std] 12 | 13 | #[doc(hidden)] 14 | pub use num_traits; 15 | 16 | #[doc(hidden)] 17 | pub use integer_sqrt; 18 | 19 | #[doc(hidden)] 20 | pub use uint; 21 | 22 | /// Add num-traits support to an integer created by `construct_uint!`. 23 | #[macro_export] 24 | macro_rules! impl_uint_num_traits { 25 | ($name: ident, $len: expr) => { 26 | impl $crate::num_traits::bounds::Bounded for $name { 27 | #[inline] 28 | fn min_value() -> Self { 29 | Self::zero() 30 | } 31 | 32 | #[inline] 33 | fn max_value() -> Self { 34 | Self::max_value() 35 | } 36 | } 37 | 38 | impl $crate::num_traits::sign::Unsigned for $name {} 39 | 40 | impl $crate::num_traits::identities::ConstZero for $name { 41 | const ZERO: Self = Self::zero(); 42 | } 43 | 44 | impl $crate::num_traits::identities::ConstOne for $name { 45 | const ONE: Self = Self::one(); 46 | } 47 | 48 | impl $crate::num_traits::identities::Zero for $name { 49 | #[inline] 50 | fn zero() -> Self { 51 | Self::zero() 52 | } 53 | 54 | #[inline] 55 | fn is_zero(&self) -> bool { 56 | self.is_zero() 57 | } 58 | } 59 | 60 | impl $crate::num_traits::identities::One for $name { 61 | #[inline] 62 | fn one() -> Self { 63 | Self::one() 64 | } 65 | } 66 | 67 | impl $crate::num_traits::Num for $name { 68 | type FromStrRadixErr = $crate::uint::FromStrRadixErr; 69 | 70 | fn from_str_radix(txt: &str, radix: u32) -> Result { 71 | Self::from_str_radix(txt, radix) 72 | } 73 | } 74 | 75 | impl $crate::integer_sqrt::IntegerSquareRoot for $name { 76 | fn integer_sqrt_checked(&self) -> Option { 77 | Some(self.integer_sqrt()) 78 | } 79 | } 80 | 81 | impl $crate::num_traits::ops::bytes::FromBytes for $name { 82 | type Bytes = [u8; $len * 8]; 83 | 84 | fn from_be_bytes(bytes: &Self::Bytes) -> Self { 85 | Self::from_big_endian(&bytes[..]) 86 | } 87 | 88 | fn from_le_bytes(bytes: &Self::Bytes) -> Self { 89 | Self::from_little_endian(&bytes[..]) 90 | } 91 | } 92 | 93 | impl $crate::num_traits::ops::bytes::ToBytes for $name { 94 | type Bytes = [u8; $len * 8]; 95 | 96 | fn to_be_bytes(&self) -> Self::Bytes { 97 | self.to_big_endian() 98 | } 99 | 100 | fn to_le_bytes(&self) -> Self::Bytes { 101 | self.to_little_endian() 102 | } 103 | } 104 | 105 | impl $crate::num_traits::ops::checked::CheckedAdd for $name { 106 | #[inline] 107 | fn checked_add(&self, v: &Self) -> Option { 108 | $name::checked_add(*self, *v) 109 | } 110 | } 111 | 112 | impl $crate::num_traits::ops::checked::CheckedSub for $name { 113 | #[inline] 114 | fn checked_sub(&self, v: &Self) -> Option { 115 | $name::checked_sub(*self, *v) 116 | } 117 | } 118 | 119 | impl $crate::num_traits::ops::checked::CheckedDiv for $name { 120 | #[inline] 121 | fn checked_div(&self, v: &Self) -> Option { 122 | $name::checked_div(*self, *v) 123 | } 124 | } 125 | 126 | impl $crate::num_traits::ops::checked::CheckedMul for $name { 127 | #[inline] 128 | fn checked_mul(&self, v: &Self) -> Option { 129 | $name::checked_mul(*self, *v) 130 | } 131 | } 132 | 133 | impl $crate::num_traits::ops::checked::CheckedNeg for $name { 134 | #[inline] 135 | fn checked_neg(&self) -> Option { 136 | Self::checked_neg(*self) 137 | } 138 | } 139 | 140 | impl $crate::num_traits::ops::checked::CheckedRem for $name { 141 | #[inline] 142 | fn checked_rem(&self, v: &Self) -> Option { 143 | Self::checked_rem(*self, *v) 144 | } 145 | } 146 | 147 | impl $crate::num_traits::ops::saturating::Saturating for $name { 148 | #[inline] 149 | fn saturating_add(self, v: Self) -> Self { 150 | Self::saturating_add(self, v) 151 | } 152 | 153 | #[inline] 154 | fn saturating_sub(self, v: Self) -> Self { 155 | Self::saturating_sub(self, v) 156 | } 157 | } 158 | 159 | impl $crate::num_traits::ops::saturating::SaturatingAdd for $name { 160 | #[inline] 161 | fn saturating_add(&self, v: &Self) -> Self { 162 | Self::saturating_add(*self, *v) 163 | } 164 | } 165 | 166 | impl $crate::num_traits::ops::saturating::SaturatingMul for $name { 167 | #[inline] 168 | fn saturating_mul(&self, v: &Self) -> Self { 169 | Self::saturating_mul(*self, *v) 170 | } 171 | } 172 | 173 | impl $crate::num_traits::ops::saturating::SaturatingSub for $name { 174 | #[inline] 175 | fn saturating_sub(&self, v: &Self) -> Self { 176 | Self::saturating_sub(*self, *v) 177 | } 178 | } 179 | 180 | impl $crate::num_traits::pow::Pow for $name { 181 | type Output = Self; 182 | 183 | fn pow(self, rhs: Self) -> Self { 184 | Self::pow(self, rhs) 185 | } 186 | } 187 | }; 188 | } 189 | -------------------------------------------------------------------------------- /primitive-types/impls/rlp/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [0.4.0] - 2024-09-11 8 | - Updated `rlp` to 0.6. [#859](https://github.com/paritytech/parity-common/pull/859) 9 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 10 | 11 | ## [0.3.0] - 2021-01-05 12 | ### Breaking 13 | - Updated `rlp` to 0.5. [#463](https://github.com/paritytech/parity-common/pull/463) 14 | -------------------------------------------------------------------------------- /primitive-types/impls/rlp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "impl-rlp" 3 | version = "0.4.0" 4 | description = "RLP serialization support for uint and fixed hash." 5 | rust-version = "1.56.1" 6 | authors.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | rlp = { workspace = true } 14 | 15 | [features] 16 | default = ["std"] 17 | std = ["rlp/std"] 18 | -------------------------------------------------------------------------------- /primitive-types/impls/rlp/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! RLP serialization support for uint and fixed hash. 10 | 11 | #![cfg_attr(not(feature = "std"), no_std)] 12 | 13 | #[doc(hidden)] 14 | pub use rlp; 15 | 16 | #[doc(hidden)] 17 | pub use core as core_; 18 | 19 | /// Add RLP serialization support to an integer created by `construct_uint!`. 20 | #[macro_export] 21 | macro_rules! impl_uint_rlp { 22 | ($name: ident, $size: expr) => { 23 | impl $crate::rlp::Encodable for $name { 24 | fn rlp_append(&self, s: &mut $crate::rlp::RlpStream) { 25 | let leading_empty_bytes = $size * 8 - (self.bits() + 7) / 8; 26 | let buffer = self.to_big_endian(); 27 | s.encoder().encode_value(&buffer[leading_empty_bytes..]); 28 | } 29 | } 30 | 31 | impl $crate::rlp::Decodable for $name { 32 | fn decode(rlp: &$crate::rlp::Rlp) -> Result { 33 | rlp.decoder().decode_value(|bytes| { 34 | if !bytes.is_empty() && bytes[0] == 0 { 35 | Err($crate::rlp::DecoderError::RlpInvalidIndirection) 36 | } else if bytes.len() <= $size * 8 { 37 | Ok($name::from_big_endian(bytes)) 38 | } else { 39 | Err($crate::rlp::DecoderError::RlpIsTooBig) 40 | } 41 | }) 42 | } 43 | } 44 | }; 45 | } 46 | 47 | /// Add RLP serialization support to a fixed-sized hash type created by `construct_fixed_hash!`. 48 | #[macro_export] 49 | macro_rules! impl_fixed_hash_rlp { 50 | ($name: ident, $size: expr) => { 51 | impl $crate::rlp::Encodable for $name { 52 | fn rlp_append(&self, s: &mut $crate::rlp::RlpStream) { 53 | s.encoder().encode_value(self.as_ref()); 54 | } 55 | } 56 | 57 | impl $crate::rlp::Decodable for $name { 58 | fn decode(rlp: &$crate::rlp::Rlp) -> Result { 59 | rlp.decoder().decode_value(|bytes| match bytes.len().cmp(&$size) { 60 | $crate::core_::cmp::Ordering::Less => Err($crate::rlp::DecoderError::RlpIsTooShort), 61 | $crate::core_::cmp::Ordering::Greater => Err($crate::rlp::DecoderError::RlpIsTooBig), 62 | $crate::core_::cmp::Ordering::Equal => { 63 | let mut t = [0u8; $size]; 64 | t.copy_from_slice(bytes); 65 | Ok($name(t)) 66 | }, 67 | }) 68 | } 69 | } 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /primitive-types/impls/serde/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.5.0] - 2024-09-11 10 | - Updated `uint` to 0.10. [#859](https://github.com/paritytech/parity-common/pull/859) 11 | 12 | ## [0.4.0] - 2022-09-02 13 | - Support deserializing H256 et al from bytes or sequences of bytes, too. [#668](https://github.com/paritytech/parity-common/pull/668) 14 | - Support deserializing H256 et al from newtype structs containing anything compatible, too. [#672](https://github.com/paritytech/parity-common/pull/672) 15 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 16 | 17 | ## [0.3.2] - 2021-11-10 18 | - Supported decoding of hex strings without `0x` prefix. [#598](https://github.com/paritytech/parity-common/pull/598) 19 | 20 | ## [0.3.1] - 2020-05-05 21 | - Added `no_std` support. [#385](https://github.com/paritytech/parity-common/pull/385) 22 | 23 | ## [0.2.3] - 2019-10-29 24 | ### Fixed 25 | - Fixed a bug in empty slice serialization. [#253](https://github.com/paritytech/parity-common/pull/253) 26 | -------------------------------------------------------------------------------- /primitive-types/impls/serde/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "impl-serde" 3 | version = "0.5.0" 4 | description = "Serde serialization support for uint and fixed hash." 5 | rust-version = "1.56.1" 6 | authors.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | serde = { workspace = true, features = ["alloc"] } 14 | 15 | [dev-dependencies] 16 | criterion = { workspace = true } 17 | serde_derive = { workspace = true } 18 | serde_json = { workspace = true } 19 | uint = { workspace = true, default-features = true } 20 | 21 | [features] 22 | default = ["std"] 23 | std = ["serde/std"] 24 | 25 | [[bench]] 26 | name = "impl_serde" 27 | harness = false 28 | -------------------------------------------------------------------------------- /primitive-types/impls/serde/benches/impl_serde.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! benchmarking for impl_serde 10 | //! should be started with: 11 | //! ```bash 12 | //! cargo bench 13 | //! ``` 14 | 15 | use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; 16 | use impl_serde::impl_uint_serde; 17 | use serde_derive::{Deserialize, Serialize}; 18 | use uint::*; 19 | 20 | mod input; 21 | 22 | construct_uint! { 23 | pub struct U256(4); 24 | } 25 | 26 | impl_uint_serde!(U256, 4); 27 | 28 | #[derive(Debug, Deserialize, Serialize)] 29 | struct Bytes(#[serde(with = "impl_serde::serialize")] Vec); 30 | 31 | criterion_group!(impl_serde, u256_to_hex, hex_to_u256, bytes_to_hex, hex_to_bytes,); 32 | criterion_main!(impl_serde); 33 | 34 | fn u256_to_hex(c: &mut Criterion) { 35 | let mut group = c.benchmark_group("u256_to_hex"); 36 | for input in [ 37 | U256::from(0), 38 | U256::from(100), 39 | U256::from(u32::max_value()), 40 | U256::from(u64::max_value()), 41 | U256::from(u128::max_value()), 42 | U256([1, 2, 3, 4]), 43 | ] { 44 | group.bench_with_input(BenchmarkId::from_parameter(input), &input, |b, x| { 45 | b.iter(|| black_box(serde_json::to_string(&x))) 46 | }); 47 | } 48 | group.finish(); 49 | } 50 | 51 | fn hex_to_u256(c: &mut Criterion) { 52 | let mut group = c.benchmark_group("hex_to_u256"); 53 | for input in [ 54 | "\"0x0\"", 55 | "\"0x1\"", 56 | "\"0x10\"", 57 | "\"0x100\"", 58 | "\"0x1000000000000000000000000000000000000000000000000000000000000100\"", 59 | ] { 60 | group.bench_with_input(BenchmarkId::from_parameter(input), &input, |b, x| { 61 | b.iter(|| black_box(serde_json::from_str::(&x))) 62 | }); 63 | } 64 | group.finish(); 65 | } 66 | 67 | fn bytes_to_hex(c: &mut Criterion) { 68 | let mut group = c.benchmark_group("bytes_to_hex"); 69 | let params = [ 70 | input::HEX_64_CHARS, 71 | input::HEX_256_CHARS, 72 | input::HEX_1024_CHARS, 73 | input::HEX_4096_CHARS, 74 | input::HEX_16384_CHARS, 75 | input::HEX_65536_CHARS, 76 | ]; 77 | for param in params { 78 | let input = serde_json::from_str::(¶m).unwrap(); 79 | group.bench_with_input(BenchmarkId::from_parameter(param.len()), &input, |b, x| { 80 | b.iter(|| black_box(serde_json::to_string(&x))) 81 | }); 82 | } 83 | group.finish(); 84 | } 85 | 86 | fn hex_to_bytes(c: &mut Criterion) { 87 | let mut group = c.benchmark_group("hex_to_bytes"); 88 | for input in [ 89 | input::HEX_64_CHARS, 90 | input::HEX_256_CHARS, 91 | input::HEX_1024_CHARS, 92 | input::HEX_4096_CHARS, 93 | input::HEX_16384_CHARS, 94 | input::HEX_65536_CHARS, 95 | ] { 96 | group.bench_with_input(BenchmarkId::from_parameter(input.len()), &input, |b, x| { 97 | b.iter(|| black_box(serde_json::from_str::(&x))) 98 | }); 99 | } 100 | group.finish(); 101 | } 102 | -------------------------------------------------------------------------------- /primitive-types/impls/serde/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Serde serialization support for uint and fixed hash. 10 | 11 | #![no_std] 12 | 13 | #[macro_use] 14 | extern crate alloc; 15 | 16 | #[cfg(feature = "std")] 17 | extern crate std; 18 | 19 | #[doc(hidden)] 20 | pub use serde; 21 | 22 | #[doc(hidden)] 23 | pub mod serialize; 24 | 25 | /// Add Serde serialization support to an integer created by `construct_uint!`. 26 | #[macro_export] 27 | macro_rules! impl_uint_serde { 28 | ($name: ident, $len: expr) => { 29 | impl $crate::serde::Serialize for $name { 30 | fn serialize(&self, serializer: S) -> Result 31 | where 32 | S: $crate::serde::Serializer, 33 | { 34 | let mut slice = [0u8; 2 + 2 * $len * 8]; 35 | let bytes = self.to_big_endian(); 36 | $crate::serialize::serialize_uint(&mut slice, &bytes, serializer) 37 | } 38 | } 39 | 40 | impl<'de> $crate::serde::Deserialize<'de> for $name { 41 | fn deserialize(deserializer: D) -> Result 42 | where 43 | D: $crate::serde::Deserializer<'de>, 44 | { 45 | let mut bytes = [0u8; $len * 8]; 46 | let wrote = $crate::serialize::deserialize_check_len( 47 | deserializer, 48 | $crate::serialize::ExpectedLen::Between(0, &mut bytes), 49 | )?; 50 | Ok(Self::from_big_endian(&bytes[0..wrote])) 51 | } 52 | } 53 | }; 54 | } 55 | 56 | /// Add Serde serialization support to a fixed-sized hash type created by `construct_fixed_hash!`. 57 | #[macro_export] 58 | macro_rules! impl_fixed_hash_serde { 59 | ($name: ident, $len: expr) => { 60 | impl $crate::serde::Serialize for $name { 61 | fn serialize(&self, serializer: S) -> Result 62 | where 63 | S: $crate::serde::Serializer, 64 | { 65 | let mut slice = [0u8; 2 + 2 * $len]; 66 | $crate::serialize::serialize_raw(&mut slice, &self.0, serializer) 67 | } 68 | } 69 | 70 | impl<'de> $crate::serde::Deserialize<'de> for $name { 71 | fn deserialize(deserializer: D) -> Result 72 | where 73 | D: $crate::serde::Deserializer<'de>, 74 | { 75 | let mut bytes = [0u8; $len]; 76 | $crate::serialize::deserialize_check_len( 77 | deserializer, 78 | $crate::serialize::ExpectedLen::Exact(&mut bytes), 79 | )?; 80 | Ok($name(bytes)) 81 | } 82 | } 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /primitive-types/src/fp_conversion.rs: -------------------------------------------------------------------------------- 1 | use super::U256; 2 | 3 | impl U256 { 4 | /// Lossy saturating conversion from a `f64` to a `U256`. Like for floating point to 5 | /// primitive integer type conversions, this truncates fractional parts. 6 | /// 7 | /// The conversion follows the same rules as converting `f64` to other 8 | /// primitive integer types. Namely, the conversion of `value: f64` behaves as 9 | /// follows: 10 | /// - `NaN` => `0` 11 | /// - `(-∞, 0]` => `0` 12 | /// - `(0, u256::MAX]` => `value as u256` 13 | /// - `(u256::MAX, +∞)` => `u256::MAX` 14 | pub fn from_f64_lossy(value: f64) -> U256 { 15 | if value >= 1.0 { 16 | let bits = value.to_bits(); 17 | // NOTE: Don't consider the sign or check that the subtraction will 18 | // underflow since we already checked that the value is greater 19 | // than 1.0. 20 | let exponent = ((bits >> 52) & 0x7ff) - 1023; 21 | let mantissa = (bits & 0x0f_ffff_ffff_ffff) | 0x10_0000_0000_0000; 22 | if exponent <= 52 { 23 | U256::from(mantissa >> (52 - exponent)) 24 | } else if exponent >= 256 { 25 | U256::MAX 26 | } else { 27 | U256::from(mantissa) << U256::from(exponent - 52) 28 | } 29 | } else { 30 | 0.into() 31 | } 32 | } 33 | 34 | /// Lossy conversion of `U256` to `f64`. 35 | pub fn to_f64_lossy(self) -> f64 { 36 | // Reference: https://blog.m-ou.se/floats/ 37 | // Step 1: Get leading zeroes 38 | let leading_zeroes = self.leading_zeros(); 39 | // Step 2: Get msb to be farthest left bit 40 | let left_aligned = self << leading_zeroes; 41 | // Step 3: Shift msb to fit in lower 53 bits of the first u64 (64-53=11) 42 | let quarter_aligned = left_aligned >> 11; 43 | let mantissa = quarter_aligned.0[3]; 44 | // Step 4: For the dropped bits (all bits beyond the 53 most significant 45 | // We want to know only 2 things. If the msb of the dropped bits is 1 or 0, 46 | // and if any of the other bits are 1. (See blog for explanation) 47 | // So we take care to preserve the msb bit, while jumbling the rest of the bits 48 | // together so that any 1s will survive. If all 0s, then the result will also be 0. 49 | let dropped_bits = quarter_aligned.0[1] | quarter_aligned.0[0] | (left_aligned.0[0] & 0xFFFF_FFFF); 50 | let dropped_bits = (dropped_bits & 0x7FFF_FFFF_FFFF_FFFF) | (dropped_bits >> 63); 51 | let dropped_bits = quarter_aligned.0[2] | dropped_bits; 52 | // Step 5: dropped_bits contains the msb of the original bits and an OR-mixed 63 bits. 53 | // If msb of dropped bits is 0, it is mantissa + 0 54 | // If msb of dropped bits is 1, it is mantissa + 0 only if mantissa lowest bit is 0 55 | // and other bits of the dropped bits are all 0 (which both can be tested with the below all at once) 56 | let mantissa = mantissa + ((dropped_bits - (dropped_bits >> 63 & !mantissa)) >> 63); 57 | // Step 6: Calculate the exponent 58 | // If self is 0, exponent should be 0 (special meaning) and mantissa will end up 0 too 59 | // Otherwise, (255 - n) + 1022 so it simplifies to 1277 - n 60 | // 1023 and 1022 are the cutoffs for the exponent having the msb next to the decimal point 61 | let exponent = if self.is_zero() { 0 } else { 1277 - leading_zeroes as u64 }; 62 | // Step 7: sign bit is always 0, exponent is shifted into place 63 | // Use addition instead of bitwise OR to saturate the exponent if mantissa overflows 64 | f64::from_bits((exponent << 52) + mantissa) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /primitive-types/src/json_schema.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | #[cfg(not(feature = "std"))] 3 | use alloc::{ 4 | borrow::ToOwned, 5 | string::{String, ToString}, 6 | }; 7 | 8 | use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema}; 9 | 10 | impl JsonSchema for H160 { 11 | fn schema_name() -> String { 12 | "HexEncoded20Bytes".to_owned() 13 | } 14 | 15 | fn json_schema(gen: &mut SchemaGenerator) -> Schema { 16 | let mut schema = gen.subschema_for::().into_object(); 17 | schema.metadata().description = Some("Hex encoded 20 bytes".to_string()); 18 | schema.string().pattern = Some("^0(x|X)[a-fA-F0-9]{40}$".to_string()); 19 | schema.into() 20 | } 21 | } 22 | 23 | impl JsonSchema for U256 { 24 | fn schema_name() -> String { 25 | "U256String".to_string() 26 | } 27 | 28 | fn json_schema(gen: &mut SchemaGenerator) -> Schema { 29 | let mut schema = gen.subschema_for::().into_object(); 30 | schema.metadata().description = Some("256-bit Unsigned Integer".to_string()); 31 | schema.string().pattern = Some("^(0|[1-9][0-9]{0,77})$".to_string()); 32 | schema.into() 33 | } 34 | } 35 | 36 | #[cfg(test)] 37 | #[cfg(any(feature = "serde", feature = "serde_no_std"))] 38 | mod tests { 39 | use crate::{H160, U256}; 40 | #[cfg(not(feature = "std"))] 41 | use alloc::string::String; 42 | use jsonschema::Draft; 43 | use schemars::JsonSchema; 44 | 45 | #[test] 46 | fn hex_encoded_20_bytes() { 47 | let schema = H160::json_schema(&mut schemars::gen::SchemaGenerator::default()); 48 | let schema_json = serde_json::to_value(&schema).unwrap(); 49 | let schema = jsonschema::Validator::options() 50 | .with_draft(Draft::Draft7) 51 | .build(&schema_json) 52 | .unwrap(); 53 | let value = serde_json::to_value("0x55086adeca661185c437d92b9818e6eda6d0d047").unwrap(); 54 | assert!(schema.validate(&value).is_ok()); 55 | let value = serde_json::to_value("0X0E9C8DA9FD4BDD3281879D9E328D8D74D02558CC").unwrap(); 56 | assert!(schema.validate(&value).is_ok()); 57 | 58 | let value = serde_json::to_value("42").unwrap(); 59 | assert!(schema.validate(&value).is_err()); 60 | } 61 | 62 | #[test] 63 | fn u256() { 64 | let schema = U256::json_schema(&mut schemars::gen::SchemaGenerator::default()); 65 | let schema_json = serde_json::to_value(&schema).unwrap(); 66 | let schema = jsonschema::Validator::options() 67 | .with_draft(Draft::Draft7) 68 | .build(&schema_json) 69 | .unwrap(); 70 | let addr = serde_json::to_value("42").unwrap(); 71 | assert!(schema.validate(&addr).is_ok()); 72 | let addr = serde_json::to_value(['1'; 79].into_iter().collect::()).unwrap(); 73 | assert!(schema.validate(&addr).is_err()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /primitive-types/tests/fp_conversion.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Testing to and from f64 lossy for U256 primitive type. 10 | 11 | use primitive_types::U256; 12 | 13 | #[test] 14 | #[allow(clippy::float_cmp)] 15 | fn convert_u256_to_f64() { 16 | assert_eq!(U256::from(0).to_f64_lossy(), 0.0); 17 | assert_eq!(U256::from(42).to_f64_lossy(), 42.0); 18 | assert_eq!(U256::from(1_000_000_000_000_000_000u128).to_f64_lossy(), 1_000_000_000_000_000_000.0,); 19 | } 20 | 21 | #[test] 22 | #[allow(clippy::excessive_precision, clippy::float_cmp, clippy::unreadable_literal)] 23 | #[cfg(feature = "std")] 24 | fn convert_u256_to_f64_precision_loss() { 25 | assert_eq!(U256::from(u64::max_value()).to_f64_lossy(), u64::max_value() as f64,); 26 | assert_eq!( 27 | U256::MAX.to_f64_lossy(), 28 | 115792089237316195423570985008687907853269984665640564039457584007913129639935.0, 29 | ); 30 | assert_eq!( 31 | U256::MAX.to_f64_lossy(), 32 | 115792089237316200000000000000000000000000000000000000000000000000000000000000.0, 33 | ); 34 | } 35 | 36 | #[test] 37 | fn convert_f64_to_u256() { 38 | assert_eq!(U256::from_f64_lossy(0.0), 0.into()); 39 | assert_eq!(U256::from_f64_lossy(13.37), 13.into()); 40 | assert_eq!(U256::from_f64_lossy(42.0), 42.into()); 41 | assert_eq!(U256::from_f64_lossy(999.999), 999.into()); 42 | assert_eq!(U256::from_f64_lossy(1_000_000_000_000_000_000.0), 1_000_000_000_000_000_000u128.into(),); 43 | } 44 | 45 | #[test] 46 | fn convert_f64_to_u256_large() { 47 | let value = U256::from(1) << U256::from(255); 48 | assert_eq!(U256::from_f64_lossy(format!("{}", value).parse::().expect("unexpected error parsing f64")), value); 49 | } 50 | 51 | #[test] 52 | #[allow(clippy::unreadable_literal)] 53 | fn convert_f64_to_u256_overflow() { 54 | assert_eq!( 55 | U256::from_f64_lossy(115792089237316200000000000000000000000000000000000000000000000000000000000000.0), 56 | U256::MAX, 57 | ); 58 | assert_eq!( 59 | U256::from_f64_lossy(999999999999999999999999999999999999999999999999999999999999999999999999999999.0), 60 | U256::MAX, 61 | ); 62 | } 63 | 64 | #[test] 65 | fn convert_f64_to_u256_non_normal() { 66 | assert_eq!(U256::from_f64_lossy(f64::EPSILON), 0.into()); 67 | assert_eq!(U256::from_f64_lossy(f64::from_bits(0)), 0.into()); 68 | assert_eq!(U256::from_f64_lossy(f64::NAN), 0.into()); 69 | assert_eq!(U256::from_f64_lossy(f64::NEG_INFINITY), 0.into()); 70 | assert_eq!(U256::from_f64_lossy(f64::INFINITY), U256::MAX); 71 | } 72 | 73 | #[test] 74 | fn f64_to_u256_truncation() { 75 | assert_eq!(U256::from_f64_lossy(10.5), 10.into()); 76 | } 77 | -------------------------------------------------------------------------------- /primitive-types/tests/num_traits.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use impl_num_traits::integer_sqrt::IntegerSquareRoot; 10 | use num_traits::ops::checked::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub}; 11 | use primitive_types::U256; 12 | 13 | #[test] 14 | fn u256_isqrt() { 15 | let x = U256::MAX; 16 | let s = x.integer_sqrt_checked().unwrap(); 17 | assert_eq!(x.integer_sqrt(), s); 18 | } 19 | 20 | #[test] 21 | fn u256_checked_traits_supported() { 22 | const ZERO: &U256 = &U256::zero(); 23 | const ONE: &U256 = &U256::one(); 24 | const MAX: &U256 = &U256::MAX; 25 | 26 | assert_eq!(::checked_add(MAX, ONE), None); 27 | assert_eq!(::checked_add(ZERO, ONE), Some(*ONE)); 28 | 29 | assert_eq!(::checked_sub(ZERO, ONE), None); 30 | assert_eq!(::checked_sub(ONE, ZERO), Some(*ONE)); 31 | 32 | assert_eq!(::checked_div(MAX, ZERO), None); 33 | assert_eq!(::checked_div(MAX, ONE), Some(*MAX)); 34 | 35 | assert_eq!(::checked_mul(MAX, MAX), None); 36 | assert_eq!(::checked_mul(MAX, ZERO), Some(*ZERO)); 37 | } 38 | -------------------------------------------------------------------------------- /primitive-types/tests/scale_info.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Tests for scale-info feature of primitive-types. 10 | 11 | use primitive_types::{H256, U256}; 12 | use scale_info::{build::Fields, Path, Type, TypeInfo}; 13 | 14 | #[test] 15 | fn u256_scale_info() { 16 | let r#type = Type::builder() 17 | .path(Path::new("U256", "primitive_types")) 18 | .composite(Fields::unnamed().field(|f| f.ty::<[u64; 4]>().type_name("[u64; 4]"))); 19 | 20 | assert_eq!(U256::type_info(), r#type.into()); 21 | } 22 | 23 | #[test] 24 | fn h256_scale_info() { 25 | let r#type = Type::builder() 26 | .path(Path::new("H256", "primitive_types")) 27 | .composite(Fields::unnamed().field(|f| f.ty::<[u8; 32]>().type_name("[u8; 32]"))); 28 | 29 | assert_eq!(H256::type_info(), r#type.into()); 30 | } 31 | -------------------------------------------------------------------------------- /rlp-derive/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [0.2.0] - 2024-09-11 8 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 9 | 10 | ## [0.1.0] - 2020-02-13 11 | - Extracted from parity-ethereum repo. [#343](https://github.com/paritytech/parity-common/pull/343) 12 | -------------------------------------------------------------------------------- /rlp-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rlp-derive" 3 | version = "0.2.0" 4 | description = "Derive macro for #[derive(RlpEncodable, RlpDecodable)]" 5 | rust-version = "1.56.1" 6 | authors.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | 12 | [lib] 13 | proc-macro = true 14 | 15 | [dependencies] 16 | syn = { workspace = true } 17 | quote = { workspace = true } 18 | proc-macro2 = { workspace = true } 19 | 20 | [dev-dependencies] 21 | rlp = { workspace = true } 22 | -------------------------------------------------------------------------------- /rlp-derive/src/de.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use proc_macro2::TokenStream; 10 | use quote::quote; 11 | 12 | struct ParseQuotes { 13 | single: TokenStream, 14 | list: TokenStream, 15 | takes_index: bool, 16 | } 17 | 18 | fn decodable_parse_quotes() -> ParseQuotes { 19 | ParseQuotes { single: quote! { rlp.val_at }, list: quote! { rlp.list_at }, takes_index: true } 20 | } 21 | 22 | fn decodable_wrapper_parse_quotes() -> ParseQuotes { 23 | ParseQuotes { single: quote! { rlp.as_val }, list: quote! { rlp.as_list }, takes_index: false } 24 | } 25 | 26 | pub fn impl_decodable(ast: &syn::DeriveInput) -> TokenStream { 27 | let body = if let syn::Data::Struct(s) = &ast.data { 28 | s 29 | } else { 30 | panic!("#[derive(RlpDecodable)] is only defined for structs."); 31 | }; 32 | 33 | let mut default_attribute_encountered = false; 34 | let stmts: Vec<_> = body 35 | .fields 36 | .iter() 37 | .enumerate() 38 | .map(|(i, field)| decodable_field(i, field, decodable_parse_quotes(), &mut default_attribute_encountered)) 39 | .collect(); 40 | let name = &ast.ident; 41 | 42 | let impl_block = quote! { 43 | impl rlp::Decodable for #name { 44 | fn decode(rlp: &rlp::Rlp) -> Result { 45 | let result = #name { 46 | #(#stmts)* 47 | }; 48 | 49 | Ok(result) 50 | } 51 | } 52 | }; 53 | 54 | quote! { 55 | const _: () = { 56 | extern crate rlp; 57 | #impl_block 58 | }; 59 | } 60 | } 61 | 62 | pub fn impl_decodable_wrapper(ast: &syn::DeriveInput) -> TokenStream { 63 | let body = if let syn::Data::Struct(s) = &ast.data { 64 | s 65 | } else { 66 | panic!("#[derive(RlpDecodableWrapper)] is only defined for structs."); 67 | }; 68 | 69 | let stmt = { 70 | let fields: Vec<_> = body.fields.iter().collect(); 71 | if fields.len() == 1 { 72 | let field = fields.first().expect("fields.len() == 1; qed"); 73 | let mut default_attribute_encountered = false; 74 | decodable_field(0, field, decodable_wrapper_parse_quotes(), &mut default_attribute_encountered) 75 | } else { 76 | panic!("#[derive(RlpEncodableWrapper)] is only defined for structs with one field.") 77 | } 78 | }; 79 | 80 | let name = &ast.ident; 81 | 82 | let impl_block = quote! { 83 | impl rlp::Decodable for #name { 84 | fn decode(rlp: &rlp::Rlp) -> Result { 85 | let result = #name { 86 | #stmt 87 | }; 88 | 89 | Ok(result) 90 | } 91 | } 92 | }; 93 | 94 | quote! { 95 | const _: () = { 96 | extern crate rlp; 97 | #impl_block 98 | }; 99 | } 100 | } 101 | 102 | fn decodable_field( 103 | mut index: usize, 104 | field: &syn::Field, 105 | quotes: ParseQuotes, 106 | default_attribute_encountered: &mut bool, 107 | ) -> TokenStream { 108 | let id = if let Some(ident) = &field.ident { 109 | quote! { #ident } 110 | } else { 111 | let index = syn::Index::from(index); 112 | quote! { #index } 113 | }; 114 | 115 | if *default_attribute_encountered { 116 | index -= 1; 117 | } 118 | let index = quote! { #index }; 119 | 120 | let single = quotes.single; 121 | let list = quotes.list; 122 | 123 | let attributes = &field.attrs; 124 | let default = if let Some(attr) = attributes.iter().find(|attr| attr.path().is_ident("rlp")) { 125 | if *default_attribute_encountered { 126 | panic!("only 1 #[rlp(default)] attribute is allowed in a struct") 127 | } 128 | match attr.parse_args() { 129 | Ok(proc_macro2::TokenTree::Ident(ident)) if ident == "default" => {}, 130 | _ => panic!("only #[rlp(default)] attribute is supported"), 131 | } 132 | *default_attribute_encountered = true; 133 | true 134 | } else { 135 | false 136 | }; 137 | 138 | if let syn::Type::Path(path) = &field.ty { 139 | let ident = &path.path.segments.first().expect("there must be at least 1 segment").ident; 140 | let ident_type = ident.to_string(); 141 | if ident_type == "Vec" { 142 | if quotes.takes_index { 143 | if default { 144 | quote! { #id: #list(#index).unwrap_or_default(), } 145 | } else { 146 | quote! { #id: #list(#index)?, } 147 | } 148 | } else { 149 | quote! { #id: #list()?, } 150 | } 151 | } else if quotes.takes_index { 152 | if default { 153 | quote! { #id: #single(#index).unwrap_or_default(), } 154 | } else { 155 | quote! { #id: #single(#index)?, } 156 | } 157 | } else { 158 | quote! { #id: #single()?, } 159 | } 160 | } else { 161 | panic!("rlp_derive not supported"); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /rlp-derive/src/en.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use proc_macro2::TokenStream; 10 | use quote::quote; 11 | 12 | pub fn impl_encodable(ast: &syn::DeriveInput) -> TokenStream { 13 | let body = if let syn::Data::Struct(s) = &ast.data { 14 | s 15 | } else { 16 | panic!("#[derive(RlpEncodable)] is only defined for structs."); 17 | }; 18 | 19 | let stmts: Vec<_> = body 20 | .fields 21 | .iter() 22 | .enumerate() 23 | .map(|(i, field)| encodable_field(i, field)) 24 | .collect(); 25 | let name = &ast.ident; 26 | 27 | let stmts_len = stmts.len(); 28 | let stmts_len = quote! { #stmts_len }; 29 | let impl_block = quote! { 30 | impl rlp::Encodable for #name { 31 | fn rlp_append(&self, stream: &mut rlp::RlpStream) { 32 | stream.begin_list(#stmts_len); 33 | #(#stmts)* 34 | } 35 | } 36 | }; 37 | 38 | quote! { 39 | const _: () = { 40 | extern crate rlp; 41 | #impl_block 42 | }; 43 | } 44 | } 45 | 46 | pub fn impl_encodable_wrapper(ast: &syn::DeriveInput) -> TokenStream { 47 | let body = if let syn::Data::Struct(s) = &ast.data { 48 | s 49 | } else { 50 | panic!("#[derive(RlpEncodableWrapper)] is only defined for structs."); 51 | }; 52 | 53 | let stmt = { 54 | let fields: Vec<_> = body.fields.iter().collect(); 55 | if fields.len() == 1 { 56 | let field = fields.first().expect("fields.len() == 1; qed"); 57 | encodable_field(0, field) 58 | } else { 59 | panic!("#[derive(RlpEncodableWrapper)] is only defined for structs with one field.") 60 | } 61 | }; 62 | 63 | let name = &ast.ident; 64 | 65 | let impl_block = quote! { 66 | impl rlp::Encodable for #name { 67 | fn rlp_append(&self, stream: &mut rlp::RlpStream) { 68 | #stmt 69 | } 70 | } 71 | }; 72 | 73 | quote! { 74 | const _: () = { 75 | extern crate rlp; 76 | #impl_block 77 | }; 78 | } 79 | } 80 | 81 | fn encodable_field(index: usize, field: &syn::Field) -> TokenStream { 82 | let ident = if let Some(ident) = &field.ident { 83 | quote! { #ident } 84 | } else { 85 | let index = syn::Index::from(index); 86 | quote! { #index } 87 | }; 88 | 89 | let id = quote! { self.#ident }; 90 | 91 | if let syn::Type::Path(path) = &field.ty { 92 | let top_segment = path.path.segments.first().expect("there must be at least 1 segment"); 93 | let ident = &top_segment.ident; 94 | if ident == "Vec" { 95 | let inner_ident = { 96 | if let syn::PathArguments::AngleBracketed(angle) = &top_segment.arguments { 97 | if let syn::GenericArgument::Type(syn::Type::Path(path)) = 98 | angle.args.first().expect("Vec has only one angle bracketed type; qed") 99 | { 100 | &path.path.segments.first().expect("there must be at least 1 segment").ident 101 | } else { 102 | panic!("rlp_derive not supported"); 103 | } 104 | } else { 105 | unreachable!("Vec has only one angle bracketed type; qed") 106 | } 107 | }; 108 | quote! { stream.append_list::<#inner_ident, _>(&#id); } 109 | } else { 110 | quote! { stream.append(&#id); } 111 | } 112 | } else { 113 | panic!("rlp_derive not supported"); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /rlp-derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Derive macro for `#[derive(RlpEncodable, RlpDecodable)]`. 10 | //! 11 | //! For example of usage see `./tests/rlp.rs`. 12 | //! 13 | //! This library also supports up to 1 `#[rlp(default)]` in a struct, 14 | //! which is similar to [`#[serde(default)]`](https://serde.rs/field-attrs.html#default) 15 | //! with the caveat that we use the `Default` value if 16 | //! the field deserialization fails, as we don't serialize field 17 | //! names and there is no way to tell if it is present or not. 18 | 19 | #![warn(clippy::all, clippy::pedantic, clippy::nursery)] 20 | 21 | extern crate proc_macro; 22 | 23 | mod de; 24 | mod en; 25 | 26 | use de::{impl_decodable, impl_decodable_wrapper}; 27 | use en::{impl_encodable, impl_encodable_wrapper}; 28 | use proc_macro::TokenStream; 29 | 30 | #[proc_macro_derive(RlpEncodable, attributes(rlp))] 31 | pub fn encodable(input: TokenStream) -> TokenStream { 32 | let ast = syn::parse(input).unwrap(); 33 | let gen = impl_encodable(&ast); 34 | gen.into() 35 | } 36 | 37 | #[proc_macro_derive(RlpEncodableWrapper)] 38 | pub fn encodable_wrapper(input: TokenStream) -> TokenStream { 39 | let ast = syn::parse(input).unwrap(); 40 | let gen = impl_encodable_wrapper(&ast); 41 | gen.into() 42 | } 43 | 44 | #[proc_macro_derive(RlpDecodable, attributes(rlp))] 45 | pub fn decodable(input: TokenStream) -> TokenStream { 46 | let ast = syn::parse(input).unwrap(); 47 | let gen = impl_decodable(&ast); 48 | gen.into() 49 | } 50 | 51 | #[proc_macro_derive(RlpDecodableWrapper)] 52 | pub fn decodable_wrapper(input: TokenStream) -> TokenStream { 53 | let ast = syn::parse(input).unwrap(); 54 | let gen = impl_decodable_wrapper(&ast); 55 | gen.into() 56 | } 57 | -------------------------------------------------------------------------------- /rlp-derive/tests/rlp.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use rlp::{decode, encode}; 10 | use rlp_derive::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper}; 11 | 12 | #[derive(Debug, PartialEq, RlpEncodable, RlpDecodable)] 13 | struct Item { 14 | a: String, 15 | } 16 | 17 | #[derive(Debug, PartialEq, RlpEncodableWrapper, RlpDecodableWrapper)] 18 | struct ItemWrapper { 19 | a: String, 20 | } 21 | 22 | #[test] 23 | fn test_encode_item() { 24 | let item = Item { a: "cat".into() }; 25 | 26 | let expected = vec![0xc4, 0x83, b'c', b'a', b't']; 27 | let out = encode(&item); 28 | assert_eq!(out, expected); 29 | 30 | let decoded = decode(&expected).expect("decode failure"); 31 | assert_eq!(item, decoded); 32 | } 33 | 34 | #[test] 35 | fn test_encode_item_wrapper() { 36 | let item = ItemWrapper { a: "cat".into() }; 37 | 38 | let expected = vec![0x83, b'c', b'a', b't']; 39 | let out = encode(&item); 40 | assert_eq!(out, expected); 41 | 42 | let decoded = decode(&expected).expect("decode failure"); 43 | assert_eq!(item, decoded); 44 | } 45 | 46 | #[test] 47 | fn test_encode_item_default() { 48 | #[derive(Debug, PartialEq, RlpEncodable, RlpDecodable)] 49 | struct ItemDefault { 50 | a: String, 51 | /// It works with other attributes. 52 | #[rlp(default)] 53 | b: Option>, 54 | } 55 | 56 | let attack_of = "clones"; 57 | let item = Item { a: attack_of.into() }; 58 | 59 | let expected = vec![0xc7, 0x86, b'c', b'l', b'o', b'n', b'e', b's']; 60 | let out = encode(&item); 61 | assert_eq!(out, expected); 62 | 63 | let item_default = ItemDefault { a: attack_of.into(), b: None }; 64 | 65 | let decoded = decode(&expected).expect("default failure"); 66 | assert_eq!(item_default, decoded); 67 | 68 | let item_some = ItemDefault { a: attack_of.into(), b: Some(vec![1, 2, 3]) }; 69 | let out = encode(&item_some); 70 | assert_eq!(decode(&out), Ok(item_some)); 71 | } 72 | -------------------------------------------------------------------------------- /rlp/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [0.6.1] - 2024-09-11 8 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 9 | - Updated `rlp-derive` to 0.2.0. [#860](https://github.com/paritytech/parity-common/pull/860) 10 | 11 | ## [0.5.2] - 2022-10-21 12 | - Add optional `derive` feature. [#613](https://github.com/paritytech/parity-common/pull/613) 13 | 14 | ## [0.5.1] - 2021-07-30 15 | - Fix rlp encoding/decoding for bool. [#572](https://github.com/paritytech/parity-common/pull/572) 16 | 17 | ## [0.5.0] - 2021-01-05 18 | ### Breaking 19 | - Use BytesMut for `RlpStream`'s backing buffer. [#453](https://github.com/paritytech/parity-common/pull/453) 20 | 21 | ## [0.4.6] - 2020-09-29 22 | - Implement Encodable, Decodable for boxed types. [#427](https://github.com/paritytech/parity-common/pull/427) 23 | 24 | ## [0.4.5] - 2020-03-16 25 | ### Dependencies 26 | - Updated dependencies. [#361](https://github.com/paritytech/parity-common/pull/361) 27 | 28 | ## [0.4.4] - 2019-11-20 29 | ### Added 30 | - Method `Rlp::at_with_offset`. [#269](https://github.com/paritytech/parity-common/pull/269) 31 | 32 | ## [0.4.3] - 2019-10-24 33 | ### Dependencies 34 | - Updated dependencies. [#239](https://github.com/paritytech/parity-common/pull/239) 35 | ### Fixed 36 | - Fixed nested unbounded lists. [#203](https://github.com/paritytech/parity-common/pull/203) 37 | ### Added 38 | - Added no-std support. [#206](https://github.com/paritytech/parity-common/pull/206) 39 | -------------------------------------------------------------------------------- /rlp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rlp" 3 | version = "0.6.1" 4 | description = "Recursive-length prefix encoding, decoding, and compression" 5 | readme = "README.md" 6 | rust-version = "1.56.1" 7 | authors.workspace = true 8 | edition.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | bytes = { workspace = true } 15 | rustc-hex = { workspace = true } 16 | rlp-derive = { workspace = true, optional = true } 17 | 18 | [dev-dependencies] 19 | criterion = { workspace = true } 20 | hex-literal = { workspace = true } 21 | primitive-types = { workspace = true, default-features = true, features = ["impl-rlp"] } 22 | 23 | [features] 24 | default = ["std"] 25 | std = ["bytes/std", "rustc-hex/std"] 26 | derive = ["rlp-derive"] 27 | 28 | [[bench]] 29 | name = "rlp" 30 | path = "benches/rlp.rs" 31 | harness = false 32 | -------------------------------------------------------------------------------- /rlp/README.md: -------------------------------------------------------------------------------- 1 | # RLP 2 | 3 | Recursive-length-prefix encoding, decoding, and compression in Rust. 4 | 5 | ## License 6 | 7 | Unlike most parts of Parity, which fall under the GPLv3, this package is dual-licensed under MIT/Apache2 at the user's choice. 8 | Find the associated license files in this directory as `LICENSE-MIT` and `LICENSE-APACHE2` respectively. 9 | -------------------------------------------------------------------------------- /rlp/benches/rlp.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! benchmarking for rlp 10 | 11 | use criterion::{criterion_group, criterion_main, Criterion}; 12 | 13 | fn bench_encode(c: &mut Criterion) { 14 | c.bench_function("encode_u64", |b| { 15 | b.iter(|| { 16 | let mut stream = rlp::RlpStream::new(); 17 | stream.append(&0x1023_4567_89ab_cdefu64); 18 | let _ = stream.out(); 19 | }) 20 | }); 21 | c.bench_function("encode_u256", |b| { 22 | b.iter(|| { 23 | let mut stream = rlp::RlpStream::new(); 24 | let uint: primitive_types::U256 = "8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0".into(); 25 | stream.append(&uint); 26 | let _ = stream.out(); 27 | }) 28 | }); 29 | c.bench_function("encode_1000_u64", |b| { 30 | b.iter(|| { 31 | let mut stream = rlp::RlpStream::new_list(1000); 32 | for i in 0..1000u64 { 33 | stream.append(&i); 34 | } 35 | let _ = stream.out(); 36 | }) 37 | }); 38 | c.bench_function("encode_nested_empty_lists", |b| { 39 | b.iter(|| { 40 | // [ [], [[]], [ [], [[]] ] ] 41 | let mut stream = rlp::RlpStream::new_list(3); 42 | stream.begin_list(0); 43 | stream.begin_list(1).begin_list(0); 44 | stream.begin_list(2).begin_list(0).begin_list(1).begin_list(0); 45 | let _ = stream.out(); 46 | }) 47 | }); 48 | c.bench_function("encode_1000_empty_lists", |b| { 49 | b.iter(|| { 50 | let mut stream = rlp::RlpStream::new_list(1000); 51 | for _ in 0..1000 { 52 | stream.begin_list(0); 53 | } 54 | let _ = stream.out(); 55 | }) 56 | }); 57 | } 58 | 59 | fn bench_decode(c: &mut Criterion) { 60 | c.bench_function("decode_u64", |b| { 61 | b.iter(|| { 62 | let data = vec![0x88, 0x10, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; 63 | let rlp = rlp::Rlp::new(&data); 64 | let _: u64 = rlp.as_val().unwrap(); 65 | }) 66 | }); 67 | c.bench_function("decode_u256", |b| { 68 | b.iter(|| { 69 | let data = vec![ 70 | 0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0, 72 | ]; 73 | let rlp = rlp::Rlp::new(&data); 74 | let _: primitive_types::U256 = rlp.as_val().unwrap(); 75 | }) 76 | }); 77 | c.bench_function("decode_1000_u64", |b| { 78 | let mut stream = rlp::RlpStream::new_list(1000); 79 | for i in 0..1000u64 { 80 | stream.append(&i); 81 | } 82 | let data = stream.out(); 83 | b.iter(|| { 84 | let rlp = rlp::Rlp::new(&data); 85 | for i in 0..1000 { 86 | let _: u64 = rlp.val_at(i).unwrap(); 87 | } 88 | }); 89 | }); 90 | c.bench_function("decode_nested_empty_lists", |b| { 91 | b.iter(|| { 92 | // [ [], [[]], [ [], [[]] ] ] 93 | let data = vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]; 94 | let rlp = rlp::Rlp::new(&data); 95 | let _v0: Vec = rlp.at(0).unwrap().as_list().unwrap(); 96 | let _v1: Vec = rlp.at(1).unwrap().at(0).unwrap().as_list().unwrap(); 97 | let nested_rlp = rlp.at(2).unwrap(); 98 | let _v2a: Vec = nested_rlp.at(0).unwrap().as_list().unwrap(); 99 | let _v2b: Vec = nested_rlp.at(1).unwrap().at(0).unwrap().as_list().unwrap(); 100 | }) 101 | }); 102 | c.bench_function("decode_1000_empty_lists", |b| { 103 | let mut stream = rlp::RlpStream::new_list(1000); 104 | for _ in 0..1000 { 105 | stream.begin_list(0); 106 | } 107 | let data = stream.out(); 108 | b.iter(|| { 109 | let rlp = rlp::Rlp::new(&data); 110 | for i in 0..1000 { 111 | let _: Vec = rlp.at(i).unwrap().as_list().unwrap(); 112 | } 113 | }); 114 | }); 115 | } 116 | 117 | criterion_group!(benches, bench_encode, bench_decode); 118 | criterion_main!(benches); 119 | -------------------------------------------------------------------------------- /rlp/src/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use core::fmt; 10 | #[cfg(feature = "std")] 11 | use std::error::Error as StdError; 12 | 13 | #[derive(Debug, PartialEq, Eq, Clone)] 14 | /// Error concerning the RLP decoder. 15 | pub enum DecoderError { 16 | /// Data has additional bytes at the end of the valid RLP fragment. 17 | RlpIsTooBig, 18 | /// Data has too few bytes for valid RLP. 19 | RlpIsTooShort, 20 | /// Expect an encoded list, RLP was something else. 21 | RlpExpectedToBeList, 22 | /// Expect encoded data, RLP was something else. 23 | RlpExpectedToBeData, 24 | /// Expected a different size list. 25 | RlpIncorrectListLen, 26 | /// Data length number has a prefixed zero byte, invalid for numbers. 27 | RlpDataLenWithZeroPrefix, 28 | /// List length number has a prefixed zero byte, invalid for numbers. 29 | RlpListLenWithZeroPrefix, 30 | /// Non-canonical (longer than necessary) representation used for data or list. 31 | RlpInvalidIndirection, 32 | /// Declared length is inconsistent with data specified after. 33 | RlpInconsistentLengthAndData, 34 | /// Declared length is invalid and results in overflow 35 | RlpInvalidLength, 36 | /// Custom rlp decoding error. 37 | Custom(&'static str), 38 | } 39 | 40 | #[cfg(feature = "std")] 41 | impl StdError for DecoderError { 42 | fn description(&self) -> &str { 43 | "builder error" 44 | } 45 | } 46 | 47 | impl fmt::Display for DecoderError { 48 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 49 | fmt::Debug::fmt(&self, f) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /rlp/src/impls.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | #[cfg(not(feature = "std"))] 10 | use alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec}; 11 | use bytes::{Bytes, BytesMut}; 12 | use core::{ 13 | iter::{empty, once}, 14 | mem, str, 15 | }; 16 | 17 | use crate::{ 18 | error::DecoderError, 19 | rlpin::Rlp, 20 | stream::RlpStream, 21 | traits::{Decodable, Encodable}, 22 | }; 23 | 24 | pub fn decode_usize(bytes: &[u8]) -> Result { 25 | match bytes.len() { 26 | l if l <= mem::size_of::() => { 27 | if bytes[0] == 0 { 28 | return Err(DecoderError::RlpInvalidIndirection) 29 | } 30 | let mut res = 0usize; 31 | for (i, byte) in bytes.iter().enumerate().take(l) { 32 | let shift = (l - 1 - i) * 8; 33 | res += (*byte as usize) << shift; 34 | } 35 | Ok(res) 36 | }, 37 | _ => Err(DecoderError::RlpIsTooBig), 38 | } 39 | } 40 | 41 | impl Encodable for Box { 42 | fn rlp_append(&self, s: &mut RlpStream) { 43 | Encodable::rlp_append(&**self, s) 44 | } 45 | } 46 | 47 | impl Decodable for Box { 48 | fn decode(rlp: &Rlp) -> Result { 49 | T::decode(rlp).map(Box::new) 50 | } 51 | } 52 | 53 | impl Encodable for bool { 54 | fn rlp_append(&self, s: &mut RlpStream) { 55 | let as_uint = u8::from(*self); 56 | Encodable::rlp_append(&as_uint, s); 57 | } 58 | } 59 | 60 | impl Decodable for bool { 61 | fn decode(rlp: &Rlp) -> Result { 62 | let as_uint = ::decode(rlp)?; 63 | match as_uint { 64 | 0 => Ok(false), 65 | 1 => Ok(true), 66 | _ => Err(DecoderError::Custom("invalid boolean value")), 67 | } 68 | } 69 | } 70 | 71 | impl<'a> Encodable for &'a [u8] { 72 | fn rlp_append(&self, s: &mut RlpStream) { 73 | s.encoder().encode_value(self); 74 | } 75 | } 76 | 77 | impl Encodable for Vec { 78 | fn rlp_append(&self, s: &mut RlpStream) { 79 | s.encoder().encode_value(self); 80 | } 81 | } 82 | 83 | impl Decodable for Vec { 84 | fn decode(rlp: &Rlp) -> Result { 85 | rlp.decoder().decode_value(|bytes| Ok(bytes.to_vec())) 86 | } 87 | } 88 | 89 | impl Encodable for Bytes { 90 | fn rlp_append(&self, s: &mut RlpStream) { 91 | s.encoder().encode_value(self); 92 | } 93 | } 94 | 95 | impl Decodable for Bytes { 96 | fn decode(rlp: &Rlp) -> Result { 97 | rlp.decoder().decode_value(|bytes| Ok(Bytes::copy_from_slice(bytes))) 98 | } 99 | } 100 | 101 | impl Encodable for BytesMut { 102 | fn rlp_append(&self, s: &mut RlpStream) { 103 | s.encoder().encode_value(self); 104 | } 105 | } 106 | 107 | impl Decodable for BytesMut { 108 | fn decode(rlp: &Rlp) -> Result { 109 | rlp.decoder().decode_value(|bytes| Ok(bytes.into())) 110 | } 111 | } 112 | 113 | impl Encodable for Option 114 | where 115 | T: Encodable, 116 | { 117 | fn rlp_append(&self, s: &mut RlpStream) { 118 | match *self { 119 | None => { 120 | s.begin_list(0); 121 | }, 122 | Some(ref value) => { 123 | s.begin_list(1); 124 | s.append(value); 125 | }, 126 | } 127 | } 128 | } 129 | 130 | impl Decodable for Option 131 | where 132 | T: Decodable, 133 | { 134 | fn decode(rlp: &Rlp) -> Result { 135 | let items = rlp.item_count()?; 136 | match items { 137 | 1 => rlp.val_at(0).map(Some), 138 | 0 => Ok(None), 139 | _ => Err(DecoderError::RlpIncorrectListLen), 140 | } 141 | } 142 | } 143 | 144 | impl Encodable for u8 { 145 | fn rlp_append(&self, s: &mut RlpStream) { 146 | if *self != 0 { 147 | s.encoder().encode_iter(once(*self)); 148 | } else { 149 | s.encoder().encode_iter(empty()); 150 | } 151 | } 152 | } 153 | 154 | impl Decodable for u8 { 155 | fn decode(rlp: &Rlp) -> Result { 156 | rlp.decoder().decode_value(|bytes| match bytes.len() { 157 | 1 if bytes[0] != 0 => Ok(bytes[0]), 158 | 0 => Ok(0), 159 | 1 => Err(DecoderError::RlpInvalidIndirection), 160 | _ => Err(DecoderError::RlpIsTooBig), 161 | }) 162 | } 163 | } 164 | 165 | macro_rules! impl_encodable_for_u { 166 | ($name: ident) => { 167 | impl Encodable for $name { 168 | fn rlp_append(&self, s: &mut RlpStream) { 169 | let leading_empty_bytes = self.leading_zeros() as usize / 8; 170 | let buffer = self.to_be_bytes(); 171 | s.encoder().encode_value(&buffer[leading_empty_bytes..]); 172 | } 173 | } 174 | }; 175 | } 176 | 177 | macro_rules! impl_decodable_for_u { 178 | ($name: ident) => { 179 | impl Decodable for $name { 180 | fn decode(rlp: &Rlp) -> Result { 181 | rlp.decoder().decode_value(|bytes| match bytes.len() { 182 | 0 | 1 => u8::decode(rlp).map(|v| v as $name), 183 | l if l <= mem::size_of::<$name>() => { 184 | if bytes[0] == 0 { 185 | return Err(DecoderError::RlpInvalidIndirection) 186 | } 187 | let mut res = 0 as $name; 188 | for (i, byte) in bytes.iter().enumerate().take(l) { 189 | let shift = (l - 1 - i) * 8; 190 | res += (*byte as $name) << shift; 191 | } 192 | Ok(res) 193 | }, 194 | _ => Err(DecoderError::RlpIsTooBig), 195 | }) 196 | } 197 | } 198 | }; 199 | } 200 | 201 | impl_encodable_for_u!(u16); 202 | impl_encodable_for_u!(u32); 203 | impl_encodable_for_u!(u64); 204 | impl_encodable_for_u!(u128); 205 | 206 | impl_decodable_for_u!(u16); 207 | impl_decodable_for_u!(u32); 208 | impl_decodable_for_u!(u64); 209 | impl_decodable_for_u!(u128); 210 | 211 | impl Encodable for usize { 212 | fn rlp_append(&self, s: &mut RlpStream) { 213 | (*self as u64).rlp_append(s); 214 | } 215 | } 216 | 217 | impl Decodable for usize { 218 | fn decode(rlp: &Rlp) -> Result { 219 | u64::decode(rlp).map(|value| value as usize) 220 | } 221 | } 222 | 223 | impl<'a> Encodable for &'a str { 224 | fn rlp_append(&self, s: &mut RlpStream) { 225 | s.encoder().encode_value(self.as_bytes()); 226 | } 227 | } 228 | 229 | impl Encodable for String { 230 | fn rlp_append(&self, s: &mut RlpStream) { 231 | s.encoder().encode_value(self.as_bytes()); 232 | } 233 | } 234 | 235 | impl Decodable for String { 236 | fn decode(rlp: &Rlp) -> Result { 237 | rlp.decoder().decode_value(|bytes| { 238 | match str::from_utf8(bytes) { 239 | Ok(s) => Ok(s.to_owned()), 240 | // consider better error type here 241 | Err(_err) => Err(DecoderError::RlpExpectedToBeData), 242 | } 243 | }) 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /rlp/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Recursive Length Prefix serialization crate. 10 | //! 11 | //! Allows encoding, decoding, and view onto rlp-slice 12 | //! 13 | //! # What should you use when? 14 | //! 15 | //! ### Use `encode` function when: 16 | //! * You want to encode something inline. 17 | //! * You do not work on big set of data. 18 | //! * You want to encode whole data structure at once. 19 | //! 20 | //! ### Use `decode` function when: 21 | //! * You want to decode something inline. 22 | //! * You do not work on big set of data. 23 | //! * You want to decode whole rlp at once. 24 | //! 25 | //! ### Use `RlpStream` when: 26 | //! * You want to encode something in portions. 27 | //! * You encode a big set of data. 28 | //! 29 | //! ### Use `Rlp` when: 30 | //! * You need to handle data corruption errors. 31 | //! * You are working on input data. 32 | //! * You want to get view onto rlp-slice. 33 | //! * You don't want to decode whole rlp at once. 34 | 35 | #![cfg_attr(not(feature = "std"), no_std)] 36 | 37 | #[cfg(not(feature = "std"))] 38 | extern crate alloc; 39 | 40 | mod error; 41 | mod impls; 42 | mod rlpin; 43 | mod stream; 44 | mod traits; 45 | 46 | #[cfg(not(feature = "std"))] 47 | use alloc::vec::Vec; 48 | use bytes::BytesMut; 49 | use core::borrow::Borrow; 50 | 51 | #[cfg(feature = "derive")] 52 | pub use rlp_derive::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper}; 53 | 54 | pub use self::{ 55 | error::DecoderError, 56 | rlpin::{PayloadInfo, Prototype, Rlp, RlpIterator}, 57 | stream::RlpStream, 58 | traits::{Decodable, Encodable}, 59 | }; 60 | 61 | /// The RLP encoded empty data (used to mean "null value"). 62 | pub const NULL_RLP: [u8; 1] = [0x80; 1]; 63 | /// The RLP encoded empty list. 64 | pub const EMPTY_LIST_RLP: [u8; 1] = [0xC0; 1]; 65 | 66 | /// Shortcut function to decode trusted rlp 67 | /// 68 | /// ``` 69 | /// let data = vec![0x83, b'c', b'a', b't']; 70 | /// let animal: String = rlp::decode(&data).expect("could not decode"); 71 | /// assert_eq!(animal, "cat".to_owned()); 72 | /// ``` 73 | pub fn decode(bytes: &[u8]) -> Result 74 | where 75 | T: Decodable, 76 | { 77 | let rlp = Rlp::new(bytes); 78 | rlp.as_val() 79 | } 80 | 81 | pub fn decode_list(bytes: &[u8]) -> Vec 82 | where 83 | T: Decodable, 84 | { 85 | let rlp = Rlp::new(bytes); 86 | rlp.as_list().expect("trusted rlp should be valid") 87 | } 88 | 89 | /// Shortcut function to encode structure into rlp. 90 | /// 91 | /// ``` 92 | /// let animal = "cat"; 93 | /// let out = rlp::encode(&animal); 94 | /// assert_eq!(out, vec![0x83, b'c', b'a', b't']); 95 | /// ``` 96 | pub fn encode(object: &E) -> BytesMut 97 | where 98 | E: Encodable, 99 | { 100 | let mut stream = RlpStream::new(); 101 | stream.append(object); 102 | stream.out() 103 | } 104 | 105 | pub fn encode_list(object: &[K]) -> BytesMut 106 | where 107 | E: Encodable, 108 | K: Borrow, 109 | { 110 | let mut stream = RlpStream::new(); 111 | stream.append_list(object); 112 | stream.out() 113 | } 114 | -------------------------------------------------------------------------------- /rlp/src/traits.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Common RLP traits 10 | use bytes::BytesMut; 11 | 12 | use crate::{error::DecoderError, rlpin::Rlp, stream::RlpStream}; 13 | 14 | /// RLP decodable trait 15 | pub trait Decodable: Sized { 16 | /// Decode a value from RLP bytes 17 | fn decode(rlp: &Rlp) -> Result; 18 | } 19 | 20 | /// Structure encodable to RLP 21 | pub trait Encodable { 22 | /// Append a value to the stream 23 | fn rlp_append(&self, s: &mut RlpStream); 24 | 25 | /// Get rlp-encoded bytes for this instance 26 | fn rlp_bytes(&self) -> BytesMut { 27 | let mut s = RlpStream::new(); 28 | self.rlp_append(&mut s); 29 | s.out() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # https://github.com/paritytech/substrate/blob/master/rustfmt.toml 2 | # Basic 3 | hard_tabs = true 4 | max_width = 120 5 | use_small_heuristics = "Max" 6 | # Imports 7 | imports_granularity = "Crate" 8 | reorder_imports = true 9 | # Consistency 10 | newline_style = "Unix" 11 | normalize_comments = true 12 | normalize_doc_attributes = true 13 | # Misc 14 | chain_width = 80 15 | spaces_around_ranges = false 16 | binop_separator = "Back" 17 | reorder_impl_items = false 18 | match_arm_leading_pipes = "Preserve" 19 | match_arm_blocks = false 20 | match_block_trailing_comma = true 21 | trailing_comma = "Vertical" 22 | trailing_semicolon = false 23 | use_field_init_shorthand = true 24 | -------------------------------------------------------------------------------- /uint/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.10.0] - 2024-09-11 10 | - Removed From<[u8; n]> conversions, renamed `to_big_endian` / `to_little_endian` to write_as_*, and made them return byte arrays. [#859](https://github.com/paritytech/parity-common/pull/859) 11 | 12 | ## [0.9.5] - 2022-11-29 13 | - Implemented bitwise assign traits. [#690](https://github.com/paritytech/parity-common/pull/690) 14 | 15 | ## [0.9.4] - 2022-09-20 16 | - Made `one` const. [#650](https://github.com/paritytech/parity-common/pull/650) 17 | - Made `max_value` const. [#652](https://github.com/paritytech/parity-common/pull/652) 18 | - Made `is_zero` const. [#639](https://github.com/paritytech/parity-common/pull/639) 19 | - Added `abs_diff`. [#665](https://github.com/paritytech/parity-common/pull/665) 20 | 21 | ## [0.9.3] - 2022-02-04 22 | - Simplified and faster `div_mod`. [#478](https://github.com/paritytech/parity-common/pull/478) 23 | - Fixed `overflowing_neg`. [#611](https://github.com/paritytech/parity-common/pull/611) 24 | 25 | ## [0.9.2] - 2022-01-28 26 | - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) 27 | - Display formatting support. [#603](https://github.com/paritytech/parity-common/pull/603) 28 | 29 | ## [0.9.1] - 2021-06-30 30 | - Added `integer_sqrt` method. [#554](https://github.com/paritytech/parity-common/pull/554) 31 | 32 | ## [0.9.0] - 2021-01-05 33 | - Allow `0x` prefix in `from_str`. [#487](https://github.com/paritytech/parity-common/pull/487) 34 | ### Breaking 35 | - Optimized FromStr, made it no_std-compatible. [#468](https://github.com/paritytech/parity-common/pull/468) 36 | 37 | ## [0.8.5] - 2020-08-12 38 | - Make const matching work again. [#421](https://github.com/paritytech/parity-common/pull/421) 39 | 40 | ## [0.8.4] - 2020-08-03 41 | - Added a manual impl of `Eq` and `Hash`. [#390](https://github.com/paritytech/parity-common/pull/390) 42 | - Removed some unsafe code and added big-endian support. [#407](https://github.com/paritytech/parity-common/pull/407) 43 | - Added `checked_pow`. [#417](https://github.com/paritytech/parity-common/pull/417) 44 | 45 | ## [0.8.3] - 2020-04-27 46 | - Added `arbitrary` feature. [#378](https://github.com/paritytech/parity-common/pull/378) 47 | - Fixed UB in `from_big_endian`. [#381](https://github.com/paritytech/parity-common/pull/381) 48 | 49 | ## [0.8.2] - 2019-10-24 50 | ### Fixed 51 | - Fixed 2018 edition imports. [#237](https://github.com/paritytech/parity-common/pull/237) 52 | - Removed `uninitialized` usage. [#238](https://github.com/paritytech/parity-common/pull/238) 53 | ### Dependencies 54 | - Updated dependencies. [#239](https://github.com/paritytech/parity-common/pull/239) 55 | ### Changed 56 | - Modified AsRef impl. [#196](https://github.com/paritytech/parity-common/pull/196) 57 | -------------------------------------------------------------------------------- /uint/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "uint" 3 | version = "0.10.0" 4 | description = "Large fixed-size integer arithmetic" 5 | readme = "README.md" 6 | rust-version = "1.56.1" 7 | authors.workspace = true 8 | edition.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | byteorder = { workspace = true } 15 | crunchy = { workspace = true } 16 | quickcheck = { workspace = true, optional = true } 17 | hex = { workspace = true } 18 | static_assertions = { workspace = true } 19 | arbitrary = { workspace = true, optional = true } 20 | 21 | [dev-dependencies] 22 | criterion = { workspace = true } 23 | num-bigint = { workspace = true } 24 | 25 | [target.'cfg(all(unix, target_arch = "x86_64"))'.dev-dependencies] 26 | rug = { workspace = true, features = ["integer", "std"] } 27 | 28 | [features] 29 | default = ["std"] 30 | std = ["byteorder/std", "crunchy/std", "hex/std"] 31 | 32 | [[example]] 33 | name = "modular" 34 | 35 | [[test]] 36 | name = "uint_tests" 37 | required-features = ["std"] 38 | 39 | [[bench]] 40 | name = "bigint" 41 | harness = false 42 | -------------------------------------------------------------------------------- /uint/README.md: -------------------------------------------------------------------------------- 1 | # Uint 2 | 3 | ## Description 4 | 5 | Provides facilities to construct big unsigned integer types which use no allocations (stack-based, fixed bit length). 6 | If you want to use a predefined `U128`, `U256` or `U512` type, take a look at the [`primitive-types`](https://github.com/paritytech/parity-common/tree/master/primitive-types) or [`ethereum-types`](https://github.com/paritytech/parity-common/tree/master/ethereum-types) crate. 7 | 8 | The focus on the provided big unsigned integer types is performance and cross-platform availability. 9 | Support a very similar API as the built-in primitive integer types. 10 | 11 | ## Usage 12 | 13 | In your `Cargo.toml` paste 14 | 15 | ``` 16 | uint = "0.8" 17 | ``` 18 | 19 | Import the macro 20 | 21 | ``` 22 | use uint::construct_uint; 23 | ``` 24 | 25 | If you're using pre-edition Rust in your main file 26 | 27 | ``` 28 | #[macro_use] 29 | extern crate uint; 30 | ``` 31 | 32 | Construct your own big unsigned integer type as follows. 33 | 34 | ``` 35 | // U1024 with 1024 bits consisting of 16 x 64-bit words 36 | construct_uint! { 37 | pub struct U1024(16); 38 | } 39 | ``` 40 | 41 | ## Tests 42 | 43 | ### Basic tests 44 | 45 | ``` 46 | cargo test --release 47 | ``` 48 | 49 | ### Basic tests + property tests 50 | 51 | ``` 52 | cargo test --release --features=quickcheck 53 | ``` 54 | 55 | ### Benchmark tests 56 | 57 | ``` 58 | cargo bench 59 | ``` 60 | 61 | ### Fuzz tests 62 | 63 | see fuzz [README.md](fuzz/README.md) 64 | 65 | ## Crate Features 66 | 67 | - `std`: Use Rust's standard library. 68 | - Enables `byteorder/std`, `rustc-hex/std` 69 | - Enabled by default. 70 | - `quickcheck`: Enable quickcheck-style property testing 71 | - Use with `cargo test --release --features=quickcheck`. 72 | - `arbitrary`: Allow for creation of an `uint` object from random unstructured input for use with fuzzers that use the `arbitrary` crate. 73 | - Disabled by default. 74 | -------------------------------------------------------------------------------- /uint/examples/modular.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | #[macro_use] 10 | extern crate uint; 11 | 12 | construct_uint! { 13 | pub struct U256(4); 14 | } 15 | 16 | fn main() { 17 | // Example modular arithmetic using bigint U256 primitives 18 | 19 | // imagine the field 0..p 20 | // where the p is defined below 21 | // (it's a prime!) 22 | let p = U256::from_dec_str("38873241744847760218045702002058062581688990428170398542849190507947196700873") 23 | .expect("p to be a good number in the example"); 24 | 25 | // then, on this field, 26 | // (p-1) + (p+1) = 0 27 | 28 | // (p - 1) mod p 29 | let p_minus_1 = (p - 1) % p; 30 | // (p + 1) mod p 31 | let p_plus_1 = (p + 1) % p; 32 | // ((p - 1) mod p + (p + 1) mod p) mod p 33 | let sum = (p_minus_1 + p_plus_1) % p; 34 | assert_eq!(sum, 0.into()); 35 | 36 | // on this field, 37 | // (p-1) + (p-1) = p-2 38 | let p_minus_1 = (p - 1) % p; 39 | let sum = (p_minus_1 + p_minus_1) % p; 40 | assert_eq!(sum, p - 2); 41 | 42 | // on this field, 43 | // (p-1) * 3 = p-3 44 | let p_minus_1 = (p - 1) % p; 45 | 46 | // multiplication is a series of additions 47 | let multiplicator = 3; 48 | let mul = { 49 | let mut result = p_minus_1; 50 | for _ in 0..multiplicator - 1 { 51 | result = (p_minus_1 + result) % p; 52 | } 53 | result 54 | }; 55 | 56 | assert_eq!(mul, p - 3); 57 | } 58 | -------------------------------------------------------------------------------- /uint/fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target 3 | corpus 4 | artifacts 5 | -------------------------------------------------------------------------------- /uint/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "uint-fuzz" 3 | description = "Fuzzers for uint algorithms" 4 | publish = false 5 | version = "0.1.0" 6 | authors = ["Parity Technologies "] 7 | edition = "2021" 8 | rust-version = "1.56.1" 9 | 10 | [package.metadata] 11 | cargo-fuzz = true 12 | 13 | [dependencies] 14 | uint = { path = ".." } 15 | libfuzzer-sys = { git = "https://github.com/rust-fuzz/libfuzzer-sys.git" } 16 | rug = { version = "1.4", default-features = false, features = ["integer"] } 17 | 18 | [workspace] 19 | members = ["."] 20 | 21 | [[bin]] 22 | name = "div_mod" 23 | path = "fuzz_targets/div_mod.rs" 24 | 25 | [[bin]] 26 | name = "div_mod_word" 27 | path = "fuzz_targets/div_mod_word.rs" 28 | 29 | [[bin]] 30 | name = "isqrt" 31 | path = "fuzz_targets/isqrt.rs" 32 | -------------------------------------------------------------------------------- /uint/fuzz/README.md: -------------------------------------------------------------------------------- 1 | ### Install cargo-fuzz 2 | 3 | `cargo install cargo-fuzz` 4 | 5 | ### Run 6 | 7 | * `cargo +nightly fuzz run div_mod` 8 | * `cargo +nightly fuzz run div_mod_word` 9 | -------------------------------------------------------------------------------- /uint/fuzz/fuzz_targets/div_mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | #![no_main] 10 | 11 | use libfuzzer_sys::fuzz_target; 12 | use uint::*; 13 | use rug::{Integer, integer::Order}; 14 | 15 | 16 | construct_uint! { 17 | pub struct U512(8); 18 | } 19 | 20 | fn from_gmp(x: Integer) -> U512 { 21 | let digits = x.to_digits(Order::LsfLe); 22 | U512::from_little_endian(&digits) 23 | } 24 | 25 | fuzz_target!(|data: &[u8]| { 26 | if data.len() == 128 { 27 | let x = U512::from_little_endian(&data[..64]); 28 | let y = U512::from_little_endian(&data[64..]); 29 | let x_gmp = Integer::from_digits(&data[..64], Order::LsfLe); 30 | let y_gmp = Integer::from_digits(&data[64..], Order::LsfLe); 31 | if !y.is_zero() { 32 | let (a, b) = x_gmp.div_rem(y_gmp); 33 | assert_eq!((from_gmp(a), from_gmp(b)), x.div_mod(y)); 34 | } 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /uint/fuzz/fuzz_targets/div_mod_word.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | #![no_main] 10 | 11 | use libfuzzer_sys::fuzz_target; 12 | 13 | fn split(a: u64) -> (u64, u64) { 14 | (a >> 32, a & 0xFFFF_FFFF) 15 | } 16 | 17 | fn div_mod_word_u128(hi: u64, lo: u64, d: u64) -> (u64, u64) { 18 | let x = (u128::from(hi) << 64) + u128::from(lo); 19 | let d = u128::from(d); 20 | ((x / d) as u64, (x % d) as u64) 21 | } 22 | 23 | fn div_mod_word(hi: u64, lo: u64, y: u64) -> (u64, u64) { 24 | debug_assert!(hi < y); 25 | const TWO32: u64 = 1 << 32; 26 | let s = y.leading_zeros(); 27 | let y = y << s; 28 | let (yn1, yn0) = split(y); 29 | let un32 = (hi << s) | lo.checked_shr(64 - s).unwrap_or(0); 30 | let un10 = lo << s; 31 | let (un1, un0) = split(un10); 32 | let mut q1 = un32 / yn1; 33 | let mut rhat = un32 - q1 * yn1; 34 | 35 | while q1 >= TWO32 || q1 * yn0 > TWO32 * rhat + un1 { 36 | q1 -= 1; 37 | rhat += yn1; 38 | if rhat >= TWO32 { 39 | break; 40 | } 41 | } 42 | 43 | let un21 = un32.wrapping_mul(TWO32).wrapping_add(un1).wrapping_sub(q1.wrapping_mul(y)); 44 | let mut q0 = un21 / yn1; 45 | rhat = un21.wrapping_sub(q0.wrapping_mul(yn1)); 46 | 47 | while q0 >= TWO32 || q0 * yn0 > TWO32 * rhat + un0 { 48 | q0 -= 1; 49 | rhat += yn1; 50 | if rhat >= TWO32 { 51 | break; 52 | } 53 | } 54 | 55 | let rem = un21.wrapping_mul(TWO32).wrapping_add(un0).wrapping_sub(y.wrapping_mul(q0)); 56 | (q1 * TWO32 + q0, rem >> s) 57 | } 58 | 59 | fuzz_target!(|data: &[u8]| { 60 | if data.len() == 24 { 61 | let mut buf = [0u8; 8]; 62 | buf.copy_from_slice(&data[..8]); 63 | let x = u64::from_ne_bytes(buf); 64 | buf.copy_from_slice(&data[8..16]); 65 | let y = u64::from_ne_bytes(buf); 66 | buf.copy_from_slice(&data[16..24]); 67 | let z = u64::from_ne_bytes(buf); 68 | if x < z { 69 | assert_eq!(div_mod_word(x, y, z), div_mod_word_u128(x, y, z)); 70 | } 71 | } 72 | }); 73 | -------------------------------------------------------------------------------- /uint/fuzz/fuzz_targets/isqrt.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | #![no_main] 10 | 11 | use libfuzzer_sys::fuzz_target; 12 | use uint::*; 13 | 14 | construct_uint! { 15 | pub struct U256(4); 16 | } 17 | 18 | fn isqrt(mut me: U256) -> U256 { 19 | let one = U256::one(); 20 | if me <= one { 21 | return me; 22 | } 23 | // the implementation is based on: 24 | // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2) 25 | 26 | // "bit" starts at the highest power of four <= self. 27 | let max_shift = 4 * 64 as u32 - 1; 28 | let shift: u32 = (max_shift - me.leading_zeros()) & !1; 29 | let mut bit = one << shift; 30 | let mut result = U256::zero(); 31 | while !bit.is_zero() { 32 | let x = result + bit; 33 | result >>= 1; 34 | if me >= x { 35 | me -= x; 36 | result += bit; 37 | } 38 | bit >>= 2; 39 | } 40 | result 41 | } 42 | 43 | fuzz_target!(|data: &[u8]| { 44 | if data.len() == 32 { 45 | let x = U256::from_little_endian(data); 46 | let expected = isqrt(x); 47 | let got = x.integer_sqrt(); 48 | assert_eq!(got, expected); 49 | } 50 | }); 51 | -------------------------------------------------------------------------------- /uint/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Efficient large, fixed-size big integers and hashes. 10 | 11 | #![cfg_attr(not(feature = "std"), no_std)] 12 | 13 | #[doc(hidden)] 14 | pub use byteorder; 15 | 16 | // Re-export libcore using an alias so that the macros can work without 17 | // requiring `extern crate core` downstream. 18 | #[doc(hidden)] 19 | pub use core as core_; 20 | 21 | #[doc(hidden)] 22 | pub use hex; 23 | 24 | #[cfg(feature = "quickcheck")] 25 | #[doc(hidden)] 26 | pub use quickcheck; 27 | 28 | #[cfg(feature = "arbitrary")] 29 | #[doc(hidden)] 30 | pub use arbitrary; 31 | 32 | #[doc(hidden)] 33 | pub use static_assertions; 34 | 35 | pub use crunchy::unroll; 36 | 37 | #[macro_use] 38 | #[rustfmt::skip] 39 | mod uint; 40 | pub use crate::uint::*; 41 | --------------------------------------------------------------------------------