diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..b429316bb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,2 @@ +[*] +indent_size = 2 diff --git a/.eslintrc.yml b/.eslintrc.yml deleted file mode 100644 index 30b02597e..000000000 --- a/.eslintrc.yml +++ /dev/null @@ -1,21 +0,0 @@ -env: - es6: true - node: true -extends: - - 'eslint:recommended' -parserOptions: - ecmaVersion: 2018 -rules: - indent: - - error - - 4 - linebreak-style: - - error - - unix - quotes: - - error - - single - semi: - - error - - always - no-console: off diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 36d300f2b..000000000 --- a/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# Idea IDE files. -**/.idea/ - -# VSCode IDE files. -**/.vscode/ - -# Compilation files by Rust. -**/target/ -Cargo.lock - -# Backup files generated by rustfmt. -**/*.rs.bk - -# OS X -**/.DS_Store/ - -# JS modules -**/node_modules/ -package-lock.json -yarn.lock -.nyc_output - -# Borsh schema file -**/schema_schema.dat - diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8428221c8..000000000 --- a/.travis.yml +++ /dev/null @@ -1,50 +0,0 @@ -language: rust -rust: - - stable - - beta - - nightly-2020-05-15 - - nightly - -matrix: - allow_failures: - - rust: nightly - fast_finish: true - -branches: - only: - - master - -install: - - cargo build --verbose --manifest-path=borsh-rs/Cargo.toml - -script: - - cargo build --verbose --manifest-path=borsh-rs/Cargo.toml - - cargo test --verbose --manifest-path=borsh-rs/Cargo.toml - - cd borsh-rs/borsh && cargo test --verbose --no-default-features - -addons: - apt: - packages: - - libcurl4-openssl-dev - - libelf-dev - - libdw-dev - - cmake - - gcc - - binutils-dev - - libiberty-dev - -after_success: | - cd borsh-rs - wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && - tar xzf master.tar.gz && - cd kcov-master && - mkdir build && - cd build && - cmake .. && - make && - make install DESTDIR=../../kcov-build && - cd ../.. && - rm -rf kcov-master && - for file in target/debug/*; do [ -x "${file}" ] || continue; mkdir -p "target/cov/$(basename $file)"; ./kcov-build/usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done && - bash <(curl -s https://codecov.io/bash) && - echo "Uploaded code coverage" \ No newline at end of file diff --git a/LICENSE-APACHE b/LICENSE-APACHE deleted file mode 100644 index 263ddc774..000000000 --- a/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2019 Near - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/LICENSE-MIT.txt b/LICENSE-MIT.txt deleted file mode 100644 index 31aa79387..000000000 --- a/LICENSE-MIT.txt +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 005daaa9c..9a4b4e35f 100644 --- a/README.md +++ b/README.md @@ -6,102 +6,42 @@ Binary Object Representation Serializer for Hashing

-

- npm - npm - Crates.io version - Download - Join the community on Discord - Apache 2.0 License - Travis Build -

-

- Website - | - Example - | - Features - | - Benchmarks - | - Specification - | - Releasing -

+ Website + | + Join Community + | + Implementations + | + Benchmarks + | + Specification + Why do we need yet another serialization format? Borsh is the first serializer that prioritizes the following qualities that are crucial for security-critical projects: -* Consistent and specified binary representation: - * Consistent means there is a bijective mapping between objects and their binary representations. There is no two binary representations that deserialize - into the same object. This is extremely useful for applications that use binary representation to compute hash; - * Borsh comes with a full specification that can be used for implementations in other languages; -* Safe. Borsh implementations use safe coding practices. In Rust, Borsh uses almost only safe code, with one exception usage of `unsafe` to avoid an exhaustion attack; -* Speed. In Rust, Borsh achieves high performance by opting out from [Serde](https://serde.rs) which makes it faster - than [bincode](https://github.com/servo/bincode) in some cases; which also reduces the code size. - -## Example - -```rust -use borsh::{BorshSerialize, BorshDeserialize}; - -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] -struct A { - x: u64, - y: String, -} -#[test] -fn test_simple_struct() { - let a = A { - x: 3301, - y: "liber primus".to_string(), - }; - let encoded_a = a.try_to_vec().unwrap(); - let decoded_a = A::try_from_slice(&encoded_a).unwrap(); - assert_eq!(a, decoded_a); -} -``` - -## Features - -Opting out from Serde allows borsh to have some features that currently are not available for serde-compatible serializers. -Currently we support two features: `borsh_init` and `borsh_skip` (the former one not available in Serde). - -`borsh_init` allows to automatically run an initialization function right after deserialization. This adds a lot of convenience for objects that are architectured to be used as strictly immutable. Usage example: -```rust -#[derive(BorshSerialize, BorshDeserialize)] -#[borsh_init(init)] -struct Message { - message: String, - timestamp: u64, - public_key: CryptoKey, - signature: CryptoSignature - hash: CryptoHash -} +- Consistent and specified binary representation: + - Consistent means there is a bijective mapping between objects and their binary representations. There is no two binary representations that deserialize + into the same object. This is extremely useful for applications that use binary representation to compute hash; + - Borsh comes with a full specification that can be used for implementations in other languages; +- Safe. Borsh implementations use safe coding practices. In Rust, Borsh uses almost only safe code, with one exception usage of `unsafe` to avoid an exhaustion attack; +- Speed. In Rust, Borsh achieves high performance by opting out from [Serde](https://serde.rs) which makes it faster + than [bincode](https://github.com/servo/bincode) in some cases; which also reduces the code size. -impl Message { - pub fn init(&mut self) { - self.hash = CryptoHash::new().write_string(self.message).write_u64(self.timestamp); - self.signature.verify(self.hash, self.public_key); - } -} -``` +## Implementations -`borsh_skip` allows to skip serializing/deserializing fields, assuming they implement `Default` trait, similary to `#[serde(skip)]`. -```rust -#[derive(BorshSerialize, BorshDeserialize)] -struct A { - x: u64, - #[borsh_skip] - y: f32, -} -``` +| Platform | Repository | Latest Release | +| --------------------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| Rust | [borsh-rs](https://github.com/near/borsh-rs) | Crates.io version | +| TypeScript, JavaScript | [borsh-js](https://github.com/near/borsh-js) | npm | +| Java, Kotlin, Scala, Clojure, etc | [borshj](https://github.com/near/borshj) | | +| Python | [borsh-py](https://github.com/near/borsh-py) | Work-in-progress | ## Benchmarks We measured the following benchmarks on objects that blockchain projects care about the most: blocks, block headers, -transactions, accounts. We took object structure from the [nearprotocol](https://nearprotocol.com) blockchain. +transactions, accounts. We took object structure from the [NEAR Protocol](https://near.org) blockchain. We used [Criterion](https://bheisler.github.io/criterion.rs/book/index.html) for building the following graphs. The benchmarks were run on Google Cloud [n1-standard-2 (2 vCPUs, 7.5 GB memory)](https://cloud.google.com/compute/docs/machine-types). @@ -125,159 +65,150 @@ Block de-serialization speed vs block size in bytes: See complete report [here](http://borsh.io/criterion/report/index.html). ## Specification -In short, Borsh is a non self-describing binary serialization format. It is designed to serialize any objects to canonical and deterministic set of bytes.

- -General principles: -* integers are little endian; -* sizes of dynamic containers are written before values as `u32`; -* all unordered containers (hashmap/hashset) are ordered in lexicographic order by key (in tie breaker case on value); -* structs are serialized in the order of fields in the struct; -* enums are serialized with using `u8` for the enum ordinal and then storing data inside the enum value (if present). - -Formal specification: -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Informal typeRust EBNF * Pseudocode
Integersinteger_type: ["u8" | "u16" | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" | "i128" ]little_endian(x)
Floatsfloat_type: ["f32" | "f64" ]err_if_nan(x)
little_endian(x as integer_type)
Unitunit_type: "()"We do not write anything
Fixed sized arraysarray_type: '[' ident ';' literal ']'for el in x
  repr(el as ident)
Dynamic sized arrayvec_type: "Vec<" ident '>'repr(len() as u32)
- for el in x
-   repr(el as ident) -
Structstruct_type: "struct" ident fields repr(fields)
Fieldsfields: [named_fields | unnamed_fields]
Named fieldsnamed_fields: '{' ident_field0 ':' ident_type0 ',' ident_field1 ':' ident_type1 ',' ... '}'repr(ident_field0 as ident_type0)
- repr(ident_field1 as ident_type1)
- ... -
Unnamed fieldsunnamed_fields: '(' ident_type0 ',' ident_type1 ',' ... ')'repr(x.0 as type0)
repr(x.1 as type1)
...
Enumenum: 'enum' ident '{' variant0 ',' variant1 ',' ... '}'
- variant: ident [ fields ] ? -
Suppose X is the number of the variant that the enum takes.
- repr(X as u8)
- repr(x.X as fieldsX) -
HashMaphashmap: "HashMap<" ident0, ident1 ">" - repr(x.len() as u32)
- for (k, v) in x.sorted_by_key() {
-   repr(k as ident0)
-   repr(v as ident1)
- }
HashSethashset: "HashSet<" ident ">" - repr(x.len() as u32)
- for el in x.sorted() {
-  repr(el as ident)
- }
Optionoption_type: "Option<" ident '>' if x.is_some() {
-   repr(1 as u8)
-   repr(x.unwrap() as ident)
- } else {
-   repr(0 as u8)
- } -
Stringstring_type: "String" encoded = utf8_encoding(x) as Vec<u8>
- repr(encoded.len() as u32)
- repr(encoded as Vec<u8>)
-
- -Note: -* Some parts of Rust grammar are not yet formalized, like enums and variants. We backwards derive EBNF forms of Rust grammar from [syn types](https://github.com/dtolnay/syn); -* We had to extend repetitions of EBNF and instead of defining them as `[ ident_field ':' ident_type ',' ] *` we define them as `ident_field0 ':' ident_type0 ',' ident_field1 ':' ident_type1 ',' ...` so that we can refer to individual elements in the pseudocode; -* We use `repr()` function to denote that we are writing the representation of the given element into an imaginary buffer. - -## Releasing - -After you merged your change into the master branch and bumped the versions of all three crates it is time to officially release the new version. - -Make sure `borsh`, `borsh-derive` and `borsh-derive-internal` all have the new crate versions. Then navigate to each folder and run (in the given order): -```bash -cd ../borsh-derive-internal; cargo publish -cd ../borsh-derive; cargo publish -cd ../borsh; cargo publish -``` -Make sure you are on the master branch, then tag the code and push the tag: -```bash -git tag -a v9.9.9 -m "My superawesome change." -git push origin v9.9.9 -``` +In short, Borsh is a non self-describing binary serialization format. It is designed to serialize any objects to canonical and deterministic set of bytes. -# TypeScript/JavaScript - -## Contributing - -Install dependencies: -```bash -yarn install -``` +General principles: -Continuesly build with: -```bash -yarn dev -``` +- integers are little endian; +- sizes of dynamic containers are written before values as `u32`; +- all unordered containers (hashmap/hashset) are ordered in lexicographic order by key (in tie breaker case on value); +- structs are serialized in the order of fields in the struct; +- enums are serialized with using `u8` for the enum ordinal and then storing data inside the enum value (if present). -Run tests: -```bash -yarn test -``` +Formal specification: -Run linter -```bash -yarn lint -``` -## Publish +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Informal typeRust EBNF * Pseudocode
Integersinteger_type: ["u8" | "u16" | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" | "i128" ]little_endian(x)
Floatsfloat_type: ["f32" | "f64" ] + err_if_nan(x)
+ little_endian(x as integer_type) +
Unitunit_type: "()"We do not write anything
Fixed sized arraysarray_type: '[' ident ';' literal ']' + for el in x {
+   repr(el as ident)
+ } +
Dynamic sized arrayvec_type: "Vec<" ident '>' + repr(len() as u32)
+ for el in x {
+   repr(el as ident)
+ } +
Structstruct_type: "struct" ident fieldsrepr(fields)
Fieldsfields: [named_fields | unnamed_fields]
Named fieldsnamed_fields: '{' ident_field0 ':' ident_type0 ',' ident_field1 ':' ident_type1 ',' ... '}' + repr(ident_field0 as ident_type0)
+ repr(ident_field1 as ident_type1)
+ ... +
Unnamed fieldsunnamed_fields: '(' ident_type0 ',' ident_type1 ',' ... ')' + repr(x.0 as type0)
+ repr(x.1 as type1)
+ ... +
Enum + enum: 'enum' ident '{' variant0 ',' variant1 ',' ... '}'
+ variant: ident [ fields ] ? +
+ Suppose X is the number of the variant that the enum takes.
+ repr(X as u8)
+ repr(x.X as fieldsX) +
HashMaphashmap: "HashMap<" ident0, ident1 ">" + repr(x.len() as u32)
+ for (k, v) in x.sorted_by_key() {
+   repr(k as ident0)
+   repr(v as ident1)
+ } +
HashSethashset: "HashSet<" ident ">" + repr(x.len() as u32)
+ for el in x.sorted() {
+   repr(el as ident)
+ } +
Optionoption_type: "Option<" ident '>' + if x.is_some() {
+   repr(1 as u8)
+   repr(x.unwrap() as ident
+ } else {
+   repr(0 as u8)
+ } +
Stringstring_type: "String" + encoded = utf8_encoding(x) as Vec<u8>
+ repr(encoded.len() as u32)
+ repr(encoded as Vec<u8>) +
+
-Prepare `dist` version by running: -```bash -yarn build -``` +Note: -When publishing to npm use [np](https://github.com/sindresorhus/np). \ No newline at end of file +- Some parts of Rust grammar are not yet formalized, like enums and variants. We backwards derive EBNF forms of Rust grammar from [syn types](https://github.com/dtolnay/syn); +- We had to extend repetitions of EBNF and instead of defining them as `[ ident_field ':' ident_type ',' ] *` we define them as `ident_field0 ':' ident_type0 ',' ident_field1 ':' ident_type1 ',' ...` so that we can refer to individual elements in the pseudocode; +- We use `repr()` function to denote that we are writing the representation of the given element into an imaginary buffer. diff --git a/borsh-rs/CHANGELOG.md b/borsh-rs/CHANGELOG.md deleted file mode 100644 index 0707c4f2d..000000000 --- a/borsh-rs/CHANGELOG.md +++ /dev/null @@ -1,18 +0,0 @@ -# Changelog - -## 0.8.0 -- Add no_std support. - -## 0.7.2 -- Implement `BorshSerialize` for reference fields (`&T`) - -## 0.7.1 -- Implement `BorshSerialize` for `&T` if `T` implements `BorshSerialize`. - -## 0.7.0 - -- Extended `Box` implementation for `?Sized` types (`[T]`, `str`, ...). -- Added support for `std::borrow::Cow` -- Avoid silent integer casts since they can lead to hidden security issues. -- Removed `Cargo.lock` as it is advised for lib crates. - diff --git a/borsh-rs/Cargo.toml b/borsh-rs/Cargo.toml deleted file mode 100644 index f8bcfd1e0..000000000 --- a/borsh-rs/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[workspace] -members = [ -"borsh", -"borsh-derive", -"borsh-derive-internal", -"borsh-schema-derive-internal", -"benchmarks", -] -exclude = [ -"fuzz", -] diff --git a/borsh-rs/benchmarks/Cargo.toml b/borsh-rs/benchmarks/Cargo.toml deleted file mode 100644 index 98d3bfbdc..000000000 --- a/borsh-rs/benchmarks/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "benchmarks" -version = "0.1.0" -authors = ["Near Inc "] -edition = "2018" - -# This is somehow needed for command line arguments to work: https://github.com/bheisler/criterion.rs/issues/193#issuecomment-415740713 -[lib] -bench = false - -[dependencies] -rand_xorshift = "0.2.0" -rand = "0.7.0" -borsh = { path = "../borsh", default-features = false } -serde = { version = "1.0", features = ["derive"] } -speedy-derive = "0.5" -speedy = "0.5" - -[dev-dependencies] -criterion = "0.3.0" -bincode = "1.1.4" -serde_cbor = "0.10" - - -[[bench]] -name = "bench" -harness = false - -[features] -default = ["borsh/std"] \ No newline at end of file diff --git a/borsh-rs/benchmarks/README.md b/borsh-rs/benchmarks/README.md deleted file mode 100644 index b12bf6345..000000000 --- a/borsh-rs/benchmarks/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Borsh benchmarks - -To run benchmarks execute: - -```bash -cargo bench -``` - -If you want to make a change and see how it affects the performance then -copy `criterion` folder from `docs` into `target` folder so that you have `target/criterion`, and run the benchmarks. -Criterion will print whether the change has statistically significant positive/negative impact based on p-values or -whether it is within noise. Unfortunately, benchmarks related to serializing `Account` and `SignedTransaction` turned out to -be highly volatile therefore prefer using `Block` and `BlockHeader` as the measurement of the performance change. -We use default Criterion setting for determining statistical significance, which corresponds to 2 sigma. - -We run benchmarks using `n1-standard-2 (2 vCPUs, 7.5 GB memory)` on GCloud. Make sure the instance -is not running any other heavy process. diff --git a/borsh-rs/benchmarks/benches/bench.rs b/borsh-rs/benchmarks/benches/bench.rs deleted file mode 100644 index 43536f4be..000000000 --- a/borsh-rs/benchmarks/benches/bench.rs +++ /dev/null @@ -1,180 +0,0 @@ -use benchmarks::{Account, Block, BlockHeader, Generate, SignedTransaction}; -use borsh::{BorshDeserialize, BorshSerialize}; -use rand::SeedableRng; -use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize}; -use speedy::Endianness; -use speedy::{Readable, Writable}; - -use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; - -fn ser_obj(group_name: &str, num_samples: usize, c: &mut Criterion) -where - for<'a> T: Generate - + BorshSerialize - + BorshDeserialize - + SerdeSerialize - + SerdeDeserialize<'a> - + Readable<'a, speedy::Endianness> - + Writable - + 'static, -{ - let mut rng = rand_xorshift::XorShiftRng::from_seed([0u8; 16]); - let mut group = c.benchmark_group(group_name); - - let objects: Vec<_> = (0..num_samples).map(|_| T::generate(&mut rng)).collect(); - let borsh_datas: Vec> = objects.iter().map(|t| t.try_to_vec().unwrap()).collect(); - let borsh_sizes: Vec<_> = borsh_datas.iter().map(|d| d.len()).collect(); - - for i in 0..objects.len() { - let size = borsh_sizes[i]; - let obj = &objects[i]; - - let benchmark_param_display = format!("idx={}; size={}", i, size); - - group.throughput(Throughput::Bytes(size as u64)); - group.bench_with_input( - BenchmarkId::new("cbor", benchmark_param_display.clone()), - obj, - |b, d| { - b.iter(|| serde_cbor::to_vec(d).unwrap()); - }, - ); - group.bench_with_input( - BenchmarkId::new("bincode", benchmark_param_display.clone()), - obj, - |b, d| { - b.iter(|| bincode::serialize(d).unwrap()); - }, - ); - group.bench_with_input( - BenchmarkId::new("borsh", benchmark_param_display.clone()), - obj, - |b, d| { - b.iter(|| d.try_to_vec().unwrap()); - }, - ); - group.bench_with_input( - BenchmarkId::new("speedy", benchmark_param_display), - obj, - |b, d| { - b.iter(|| d.write_to_vec(Endianness::LittleEndian).unwrap()); - }, - ); - } - group.finish(); -} - -fn de_obj(group_name: &str, num_samples: usize, c: &mut Criterion) -where - for<'a> T: Generate - + BorshSerialize - + BorshDeserialize - + SerdeSerialize - + SerdeDeserialize<'a> - + Readable<'a, speedy::Endianness> - + Writable - + 'static, -{ - let mut rng = rand_xorshift::XorShiftRng::from_seed([0u8; 16]); - let mut group = c.benchmark_group(group_name); - - let objects: Vec<_> = (0..num_samples).map(|_| T::generate(&mut rng)).collect(); - let cbor_datas: Vec> = objects - .iter() - .map(|t| serde_cbor::to_vec(t).unwrap()) - .collect(); - let bincode_datas: Vec> = objects - .iter() - .map(|t| bincode::serialize(t).unwrap()) - .collect(); - let borsh_datas: Vec> = objects.iter().map(|t| t.try_to_vec().unwrap()).collect(); - let speedy_datas: Vec> = objects - .iter() - .map(|t| t.write_to_vec(Endianness::LittleEndian).unwrap()) - .collect(); - - let borsh_sizes: Vec<_> = borsh_datas.iter().map(|d| d.len()).collect(); - - for i in 0..objects.len() { - let size = borsh_sizes[i]; - let cbor_data = &cbor_datas[i]; - let bincode_data = &bincode_datas[i]; - let borsh_data = &borsh_datas[i]; - let speedy_data = &speedy_datas[i]; - - let benchmark_param_display = format!("idx={}; size={}", i, size); - - group.throughput(Throughput::Bytes(size as u64)); - group.bench_with_input( - BenchmarkId::new("cbor", benchmark_param_display.clone()), - cbor_data, - |b, d| { - b.iter(|| serde_cbor::from_slice::(&d).unwrap()); - }, - ); - group.bench_with_input( - BenchmarkId::new("bincode", benchmark_param_display.clone()), - bincode_data, - |b, d| { - b.iter(|| bincode::deserialize::(&d).unwrap()); - }, - ); - group.bench_with_input( - BenchmarkId::new("borsh", benchmark_param_display.clone()), - borsh_data, - |b, d| { - b.iter(|| T::try_from_slice(&d).unwrap()); - }, - ); - group.bench_with_input( - BenchmarkId::new("speedy", benchmark_param_display), - speedy_data, - |b, d| { - b.iter(|| T::read_from_buffer(Endianness::LittleEndian, &d).unwrap()); - }, - ); - } - group.finish(); -} - -fn ser_account(c: &mut Criterion) { - ser_obj::("ser_account", 10, c); -} - -fn ser_transaction(c: &mut Criterion) { - ser_obj::("ser_transaction", 10, c); -} - -fn ser_header(c: &mut Criterion) { - ser_obj::("ser_header", 10, c); -} - -fn ser_block(c: &mut Criterion) { - ser_obj::("ser_block", 10, c); -} - -fn de_account(c: &mut Criterion) { - de_obj::("de_account", 10, c); -} - -fn de_transaction(c: &mut Criterion) { - de_obj::("de_transaction", 10, c); -} - -fn de_header(c: &mut Criterion) { - de_obj::("de_header", 10, c); -} - -fn de_block(c: &mut Criterion) { - de_obj::("de_block", 10, c); -} - -criterion_group!( - ser_benches, - ser_account, - ser_transaction, - ser_header, - ser_block -); -criterion_group!(de_benches, de_account, de_transaction, de_header, de_block); -criterion_main!(ser_benches, de_benches); diff --git a/borsh-rs/benchmarks/src/lib.rs b/borsh-rs/benchmarks/src/lib.rs deleted file mode 100644 index b2fc3dc31..000000000 --- a/borsh-rs/benchmarks/src/lib.rs +++ /dev/null @@ -1,759 +0,0 @@ -//! This library contains data structures used for benchmarking. - -use borsh::{BorshDeserialize, BorshSerialize}; -use rand::distributions::{Alphanumeric, Distribution, Standard}; -use rand::Rng; -use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize}; -extern crate speedy_derive; -use speedy::{Context, Readable, Reader, Writable, Writer}; - -pub trait Generate { - fn generate(rng: &mut R) -> Self; -} - -#[derive( - BorshSerialize, BorshDeserialize, Debug, Clone, Eq, PartialEq, SerdeSerialize, SerdeDeserialize, -)] -pub struct CryptoHash([u8; 32]); -impl Generate for CryptoHash { - fn generate(rng: &mut R) -> Self { - let mut res = [0u8; 32]; - rng.fill_bytes(&mut res); - CryptoHash(res) - } -} - -impl<'a, C> Readable<'a, C> for CryptoHash -where - C: Context, -{ - fn read_from>(reader: &mut R) -> std::result::Result { - let mut data = [0u8; 32]; - reader.read_bytes(&mut data)?; - Ok(Self(data)) - } -} - -impl Writable for CryptoHash { - fn write_to<'a, T: ?Sized + Writer<'a, C>>( - &'a self, - writer: &mut T, - ) -> std::result::Result<(), std::io::Error> { - writer.write_bytes(&self.0).map(|_| ()) - } -} - -#[derive( - BorshSerialize, BorshDeserialize, Debug, Clone, Eq, PartialEq, SerdeSerialize, SerdeDeserialize, -)] -pub struct MerkleHash([u8; 32]); -impl Generate for MerkleHash { - fn generate(rng: &mut R) -> Self { - let mut res = [0u8; 32]; - rng.fill_bytes(&mut res); - MerkleHash(res) - } -} - -impl<'a, C> Readable<'a, C> for MerkleHash -where - C: Context, -{ - fn read_from>(reader: &mut R) -> std::result::Result { - let mut data = [0u8; 32]; - reader.read_bytes(&mut data)?; - Ok(Self(data)) - } -} - -impl Writable for MerkleHash { - fn write_to<'a, T: ?Sized + Writer<'a, C>>( - &'a self, - writer: &mut T, - ) -> std::result::Result<(), std::io::Error> { - writer.write_bytes(&self.0).map(|_| ()) - } -} - -#[derive( - BorshSerialize, BorshDeserialize, Debug, Clone, Eq, PartialEq, SerdeSerialize, SerdeDeserialize, -)] -pub struct Signature([u8; 32]); -impl Generate for Signature { - fn generate(rng: &mut R) -> Self { - let mut res = [0u8; 32]; - rng.fill_bytes(&mut res); - Signature(res) - } -} - -impl<'a, C> Readable<'a, C> for Signature -where - C: Context, -{ - fn read_from>(reader: &mut R) -> std::result::Result { - let mut data = [0u8; 32]; - reader.read_bytes(&mut data)?; - Ok(Self(data)) - } -} - -impl Writable for Signature { - fn write_to<'a, T: ?Sized + Writer<'a, C>>( - &'a self, - writer: &mut T, - ) -> std::result::Result<(), std::io::Error> { - writer.write_bytes(&self.0).map(|_| ()) - } -} - -#[derive( - BorshSerialize, BorshDeserialize, Debug, Clone, Eq, PartialEq, SerdeSerialize, SerdeDeserialize, -)] -pub struct PublicKey([u8; 32]); -impl Generate for PublicKey { - fn generate(rng: &mut R) -> Self { - let mut res = [0u8; 32]; - rng.fill_bytes(&mut res); - PublicKey(res) - } -} - -impl<'a, C> Readable<'a, C> for PublicKey -where - C: Context, -{ - fn read_from>(reader: &mut R) -> std::result::Result { - let mut data = [0u8; 32]; - reader.read_bytes(&mut data)?; - Ok(Self(data)) - } -} - -impl Writable for PublicKey { - fn write_to<'a, T: ?Sized + Writer<'a, C>>( - &'a self, - writer: &mut T, - ) -> std::result::Result<(), std::io::Error> { - writer.write_bytes(&self.0).map(|_| ()) - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct AccountId(String); -impl Generate for String { - fn generate(rng: &mut R) -> Self { - let len: usize = rng.gen_range(5, 200); - rng.sample_iter(&Alphanumeric).take(len).collect::() - } -} - -impl Generate for AccountId { - fn generate(rng: &mut R) -> Self { - AccountId(String::generate(rng)) - } -} - -pub type Balance = u64; - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct ValidatorStake { - pub account_id: AccountId, - pub public_key: PublicKey, - pub amount: Balance, -} - -impl Generate for ValidatorStake { - fn generate(rng: &mut R) -> Self { - Self { - account_id: AccountId::generate(rng), - public_key: PublicKey::generate(rng), - amount: u64::generate(rng), - } - } -} - -pub type BlockIndex = u64; -pub type Weight = u64; - -pub fn generate_vec_primitives(rng: &mut R, min_number: usize, max_number: usize) -> Vec -where - Standard: Distribution, - R: rand::Rng, -{ - let num: usize = rng.gen_range(min_number, max_number + 1); - let mut res = vec![]; - for _ in 0..num { - res.push(rng.gen()); - } - res -} - -pub fn generate_vec( - rng: &mut R, - min_number: usize, - max_number: usize, -) -> Vec { - let num: usize = rng.gen_range(min_number, max_number + 1); - let mut res = vec![]; - for _ in 0..num { - res.push(T::generate(rng)); - } - res -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct BlockHeaderInner { - pub height: BlockIndex, - pub epoch_hash: CryptoHash, - pub prev_hash: CryptoHash, - pub prev_state_root: MerkleHash, - pub tx_root: MerkleHash, - pub timestamp: u64, - pub approval_mask: Vec, - pub approval_sigs: Vec, - pub total_weight: Weight, - pub validator_proposals: Vec, -} - -impl Generate for BlockHeaderInner { - fn generate(rng: &mut R) -> Self { - Self { - height: u64::generate(rng), - epoch_hash: CryptoHash::generate(rng), - prev_hash: CryptoHash::generate(rng), - prev_state_root: MerkleHash::generate(rng), - tx_root: MerkleHash::generate(rng), - timestamp: u64::generate(rng), - approval_mask: generate_vec_primitives(rng, 2, 1000), - approval_sigs: generate_vec(rng, 2, 1000), - total_weight: u64::generate(rng), - validator_proposals: generate_vec(rng, 2, 1000), - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct BlockHeader { - pub inner: BlockHeaderInner, - pub signature: Signature, - pub hash: CryptoHash, -} - -impl Generate for BlockHeader { - fn generate(rng: &mut R) -> Self { - Self { - inner: BlockHeaderInner::generate(rng), - signature: Signature::generate(rng), - hash: CryptoHash::generate(rng), - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct Block { - pub header: BlockHeader, - pub transactions: Vec, -} - -impl Generate for Block { - fn generate(rng: &mut R) -> Self { - Self { - header: BlockHeader::generate(rng), - transactions: generate_vec(rng, 0, 1000), - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct SignedTransaction { - transaction: Transaction, - signature: Signature, - hash: CryptoHash, -} - -impl Generate for SignedTransaction { - fn generate(rng: &mut R) -> Self { - Self { - transaction: Transaction::generate(rng), - signature: Signature::generate(rng), - hash: CryptoHash::generate(rng), - } - } -} - -pub type Nonce = u64; - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct Transaction { - signer_id: AccountId, - public_key: PublicKey, - nonce: Nonce, - receiver_id: AccountId, - actions: Vec, -} - -impl Generate for Transaction { - fn generate(rng: &mut R) -> Self { - Self { - signer_id: AccountId::generate(rng), - public_key: PublicKey::generate(rng), - nonce: u64::generate(rng), - receiver_id: AccountId::generate(rng), - actions: generate_vec(rng, 1, 10), - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub enum Action { - CreateAccount(CreateAccountAction), - DeployContract(DeployContractAction), - FunctionCall(FunctionCallAction), - Transfer(TransferAction), - Stake(StakeAction), - AddKey(AddKeyAction), - DeleteKey(DeleteKeyAction), - DeleteAccount(DeleteAccountAction), -} - -impl Generate for Action { - fn generate(rng: &mut R) -> Self { - use Action::*; - // Deploy contract action is 1000 times less frequent than other actions. - if u64::generate(rng) % 1000 == 0 { - DeployContract(DeployContractAction::generate(rng)) - } else { - match u64::generate(rng) % 7 { - 0 => CreateAccount(CreateAccountAction::generate(rng)), - 1 => FunctionCall(FunctionCallAction::generate(rng)), - 2 => Transfer(TransferAction::generate(rng)), - 3 => Stake(StakeAction::generate(rng)), - 4 => AddKey(AddKeyAction::generate(rng)), - 5 => DeleteKey(DeleteKeyAction::generate(rng)), - 6 => DeleteAccount(DeleteAccountAction::generate(rng)), - _ => unimplemented!(), - } - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct CreateAccountAction {} -impl Generate for CreateAccountAction { - fn generate(_rng: &mut R) -> Self { - Self {} - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct DeployContractAction { - code: Vec, -} - -pub fn generate_vec_u8(rng: &mut R, min_number: usize, max_number: usize) -> Vec { - let num: usize = rng.gen_range(min_number, max_number + 1); - let mut res = vec![0u8; num]; - rng.fill_bytes(&mut res); - res -} - -impl Generate for DeployContractAction { - fn generate(rng: &mut R) -> Self { - Self { - // Between 20KiB and 1MiB. - code: generate_vec_u8(rng, 20 * 2usize.pow(10), 2usize.pow(20)), - } - } -} - -pub type Gas = u64; - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct FunctionCallAction { - method_name: String, - args: Vec, - gas: Gas, - deposit: Balance, -} - -impl Generate for FunctionCallAction { - fn generate(rng: &mut R) -> Self { - Self { - method_name: String::generate(rng), - args: generate_vec_u8(rng, 0, 1000), - gas: u64::generate(rng), - deposit: u64::generate(rng), - } - } -} -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct TransferAction { - deposit: Balance, -} -impl Generate for TransferAction { - fn generate(rng: &mut R) -> Self { - Self { - deposit: u64::generate(rng), - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct StakeAction { - stake: Balance, - public_key: PublicKey, -} - -impl Generate for StakeAction { - fn generate(rng: &mut R) -> Self { - Self { - stake: u64::generate(rng), - public_key: PublicKey::generate(rng), - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct AddKeyAction { - public_key: PublicKey, - access_key: AccessKey, -} - -impl Generate for AddKeyAction { - fn generate(rng: &mut R) -> Self { - Self { - public_key: PublicKey::generate(rng), - access_key: AccessKey::generate(rng), - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct DeleteKeyAction { - public_key: PublicKey, -} - -impl Generate for DeleteKeyAction { - fn generate(rng: &mut R) -> Self { - Self { - public_key: PublicKey::generate(rng), - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct DeleteAccountAction { - beneficiary_id: AccountId, -} - -impl Generate for DeleteAccountAction { - fn generate(rng: &mut R) -> Self { - Self { - beneficiary_id: AccountId::generate(rng), - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct AccessKey { - nonce: Nonce, - permission: AccessKeyPermission, -} - -impl Generate for AccessKey { - fn generate(rng: &mut R) -> Self { - Self { - nonce: u64::generate(rng), - permission: AccessKeyPermission::generate(rng), - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub enum AccessKeyPermission { - FunctionCall(FunctionCallPermission), - FullAccess, -} - -impl Generate for AccessKeyPermission { - fn generate(rng: &mut R) -> Self { - if u64::generate(rng) % 2 == 0 { - AccessKeyPermission::FunctionCall(FunctionCallPermission::generate(rng)) - } else { - AccessKeyPermission::FullAccess - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct FunctionCallPermission { - allowance: Option, - receiver_id: AccountId, - method_names: Vec, -} - -fn generate_option(rng: &mut R) -> Option { - if u64::generate(rng) % 2 == 0 { - None - } else { - Some(T::generate(rng)) - } -} - -impl Generate for u64 { - fn generate(rng: &mut R) -> Self { - rng.next_u64() - } -} - -impl Generate for FunctionCallPermission { - fn generate(rng: &mut R) -> Self { - Self { - allowance: generate_option(rng), - receiver_id: AccountId::generate(rng), - method_names: generate_vec(rng, 0, 10), - } - } -} - -#[derive( - BorshSerialize, - BorshDeserialize, - Debug, - Clone, - Eq, - PartialEq, - SerdeSerialize, - SerdeDeserialize, - Readable, - Writable, -)] -pub struct Account { - pub amount: Balance, - pub staked: Balance, - pub code_hash: CryptoHash, - pub storage_usage: u64, - pub storage_paid_at: u64, -} - -impl Generate for Account { - fn generate(rng: &mut R) -> Self { - Self { - amount: u64::generate(rng), - staked: u64::generate(rng), - code_hash: CryptoHash::generate(rng), - storage_usage: u64::generate(rng), - storage_paid_at: u64::generate(rng), - } - } -} diff --git a/borsh-rs/borsh-derive-internal/Cargo.toml b/borsh-rs/borsh-derive-internal/Cargo.toml deleted file mode 100644 index 57cee6fb3..000000000 --- a/borsh-rs/borsh-derive-internal/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "borsh-derive-internal" -version = "0.8.0" -authors = ["Near Inc "] -edition = "2018" -license = "Apache-2.0" -readme = "README.md" -categories = ["encoding", "network-programming"] -repository = "https://github.com/nearprotocol/borsh" -homepage = "http://borsh.io" -description = """ -Binary Object Representation Serializer for Hashing -""" - -[dependencies] -proc-macro2 = "1" -syn = {version = "1", features = ["full", "fold"] } -quote = "1" diff --git a/borsh-rs/borsh-derive-internal/README.md b/borsh-rs/borsh-derive-internal/README.md deleted file mode 120000 index fe8400541..000000000 --- a/borsh-rs/borsh-derive-internal/README.md +++ /dev/null @@ -1 +0,0 @@ -../../README.md \ No newline at end of file diff --git a/borsh-rs/borsh-derive-internal/src/attribute_helpers.rs b/borsh-rs/borsh-derive-internal/src/attribute_helpers.rs deleted file mode 100644 index 9ed895b4b..000000000 --- a/borsh-rs/borsh-derive-internal/src/attribute_helpers.rs +++ /dev/null @@ -1,34 +0,0 @@ -use syn::spanned::Spanned; -use syn::{Attribute, Error, Meta, NestedMeta, Path}; -use quote::ToTokens; - -pub fn contains_skip(attrs: &[Attribute]) -> bool { - for attr in attrs.iter() { - if let Ok(Meta::Path(path)) = attr.parse_meta() { - if path.to_token_stream().to_string().as_str() == "borsh_skip" { - return true; - } - } - } - false -} - -pub fn contains_initialize_with(attrs: &[Attribute]) -> syn::Result> { - for attr in attrs.iter() { - if let Ok(Meta::List(meta_list)) = attr.parse_meta() { - if meta_list.path.to_token_stream().to_string().as_str() == "borsh_init" { - if meta_list.nested.len() != 1 { - return Err(Error::new( - meta_list.span(), - "borsh_init requires exactly one initialization method.", - )); - } - let nested_meta = meta_list.nested.iter().next().unwrap(); - if let NestedMeta::Meta(Meta::Path(path)) = nested_meta { - return Ok(Some(path.clone())); - } - } - } - } - Ok(None) -} diff --git a/borsh-rs/borsh-derive-internal/src/enum_de.rs b/borsh-rs/borsh-derive-internal/src/enum_de.rs deleted file mode 100644 index 61e3a0734..000000000 --- a/borsh-rs/borsh-derive-internal/src/enum_de.rs +++ /dev/null @@ -1,113 +0,0 @@ -use core::convert::TryFrom; - -use quote::quote; -use syn::export::TokenStream2; -use syn::{Fields, Ident, ItemEnum, WhereClause}; - -use crate::attribute_helpers::{contains_initialize_with, contains_skip}; - -pub fn enum_de(input: &ItemEnum, cratename: Ident) -> syn::Result { - let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.map_or_else( - || WhereClause { - where_token: Default::default(), - predicates: Default::default(), - }, - Clone::clone, - ); - let init_method = contains_initialize_with(&input.attrs)?; - let mut variant_arms = TokenStream2::new(); - for (variant_idx, variant) in input.variants.iter().enumerate() { - let variant_idx = u8::try_from(variant_idx).expect("up to 256 enum variants are supported"); - let variant_ident = &variant.ident; - let mut variant_header = TokenStream2::new(); - match &variant.fields { - Fields::Named(fields) => { - for field in &fields.named { - let field_name = field.ident.as_ref().unwrap(); - if contains_skip(&field.attrs) { - variant_header.extend(quote! { - #field_name: Default::default(), - }); - } else { - let field_type = &field.ty; - where_clause.predicates.push(syn::parse2(quote! { - #field_type: #cratename::BorshDeserialize - }).unwrap()); - - variant_header.extend(quote! { - #field_name: #cratename::BorshDeserialize::deserialize(buf)?, - }); - } - } - variant_header = quote! { { #variant_header }}; - } - Fields::Unnamed(fields) => { - for field in fields.unnamed.iter() { - if contains_skip(&field.attrs) { - variant_header.extend(quote! { Default::default(), }); - } else { - let field_type = &field.ty; - where_clause.predicates.push(syn::parse2(quote! { - #field_type: #cratename::BorshDeserialize - }).unwrap()); - - variant_header - .extend(quote! { #cratename::BorshDeserialize::deserialize(buf)?, }); - } - } - variant_header = quote! { ( #variant_header )}; - } - Fields::Unit => {} - } - variant_arms.extend(quote! { - #variant_idx => #name::#variant_ident #variant_header , - }); - } - let variant_idx = quote! { - let variant_idx: u8 = #cratename::BorshDeserialize::deserialize(buf)?; - }; - if let Some(method_ident) = init_method { - Ok(quote! { - impl #impl_generics #cratename::de::BorshDeserialize for #name #ty_generics #where_clause { - fn deserialize(buf: &mut &[u8]) -> core::result::Result { - #variant_idx - let mut return_value = match variant_idx { - #variant_arms - _ => { - let msg = #cratename::maybestd::format!("Unexpected variant index: {:?}", variant_idx); - - return Err(#cratename::maybestd::io::Error::new( - #cratename::maybestd::io::ErrorKind::InvalidInput, - msg, - )); - } - }; - return_value.#method_ident(); - Ok(return_value) - } - } - }) - } else { - Ok(quote! { - impl #impl_generics #cratename::de::BorshDeserialize for #name #ty_generics #where_clause { - fn deserialize(buf: &mut &[u8]) -> core::result::Result { - #variant_idx - let return_value = match variant_idx { - #variant_arms - _ => { - let msg = #cratename::maybestd::format!("Unexpected variant index: {:?}", variant_idx); - - return Err(#cratename::maybestd::io::Error::new( - #cratename::maybestd::io::ErrorKind::InvalidInput, - msg, - )); - } - }; - Ok(return_value) - } - } - }) - } -} diff --git a/borsh-rs/borsh-derive-internal/src/enum_ser.rs b/borsh-rs/borsh-derive-internal/src/enum_ser.rs deleted file mode 100644 index e81ebe159..000000000 --- a/borsh-rs/borsh-derive-internal/src/enum_ser.rs +++ /dev/null @@ -1,90 +0,0 @@ -use core::convert::TryFrom; - -use quote::quote; -use syn::export::{Span, TokenStream2}; -use syn::{Fields, Ident, ItemEnum, WhereClause}; - -use crate::attribute_helpers::contains_skip; - -pub fn enum_ser(input: &ItemEnum, cratename: Ident) -> syn::Result { - let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.map_or_else( - || WhereClause { - where_token: Default::default(), - predicates: Default::default(), - }, - Clone::clone, - ); - let mut body = TokenStream2::new(); - for (variant_idx, variant) in input.variants.iter().enumerate() { - let variant_idx = u8::try_from(variant_idx).expect("up to 256 enum variants are supported"); - let variant_ident = &variant.ident; - let mut variant_header = TokenStream2::new(); - let mut variant_body = TokenStream2::new(); - match &variant.fields { - Fields::Named(fields) => { - for field in &fields.named { - let field_name = field.ident.as_ref().unwrap(); - if contains_skip(&field.attrs) { - variant_header.extend(quote! { _#field_name, }); - continue; - } else { - let field_type = &field.ty; - where_clause.predicates.push(syn::parse2(quote! { - #field_type: #cratename::ser::BorshSerialize - }).unwrap()); - variant_header.extend(quote! { #field_name, }); - } - variant_body.extend(quote! { - #cratename::BorshSerialize::serialize(#field_name, writer)?; - }) - } - variant_header = quote! { { #variant_header }}; - } - Fields::Unnamed(fields) => { - for (field_idx, field) in fields.unnamed.iter().enumerate() { - let field_idx = - u32::try_from(field_idx).expect("up to 2^32 fields are supported"); - if contains_skip(&field.attrs) { - let field_ident = - Ident::new(format!("_id{}", field_idx).as_str(), Span::call_site()); - variant_header.extend(quote! { #field_ident, }); - continue; - } else { - let field_type = &field.ty; - where_clause.predicates.push(syn::parse2(quote! { - #field_type: #cratename::ser::BorshSerialize - }).unwrap()); - - let field_ident = - Ident::new(format!("id{}", field_idx).as_str(), Span::call_site()); - variant_header.extend(quote! { #field_ident, }); - variant_body.extend(quote! { - #cratename::BorshSerialize::serialize(#field_ident, writer)?; - }) - } - } - variant_header = quote! { ( #variant_header )}; - } - Fields::Unit => {} - } - body.extend(quote!( - #name::#variant_ident #variant_header => { - let variant_idx: u8 = #variant_idx; - writer.write_all(&variant_idx.to_le_bytes())?; - #variant_body - } - )) - } - Ok(quote! { - impl #impl_generics #cratename::ser::BorshSerialize for #name #ty_generics #where_clause { - fn serialize(&self, writer: &mut W) -> core::result::Result<(), #cratename::maybestd::io::Error> { - match self { - #body - } - Ok(()) - } - } - }) -} diff --git a/borsh-rs/borsh-derive-internal/src/lib.rs b/borsh-rs/borsh-derive-internal/src/lib.rs deleted file mode 100644 index e01b99c85..000000000 --- a/borsh-rs/borsh-derive-internal/src/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![recursion_limit = "128"] - -mod attribute_helpers; -mod enum_de; -mod enum_ser; -mod struct_de; -mod struct_ser; -mod union_de; -mod union_ser; - -pub use enum_de::enum_de; -pub use enum_ser::enum_ser; -pub use struct_de::struct_de; -pub use struct_ser::struct_ser; -pub use union_de::union_de; -pub use union_ser::union_ser; diff --git a/borsh-rs/borsh-derive-internal/src/struct_de.rs b/borsh-rs/borsh-derive-internal/src/struct_de.rs deleted file mode 100644 index 71a53b077..000000000 --- a/borsh-rs/borsh-derive-internal/src/struct_de.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::attribute_helpers::{contains_initialize_with, contains_skip}; -use quote::quote; -use syn::export::TokenStream2; -use syn::{Fields, Ident, ItemStruct, WhereClause}; - -pub fn struct_de(input: &ItemStruct, cratename: Ident) -> syn::Result { - let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.map_or_else( - || WhereClause { - where_token: Default::default(), - predicates: Default::default(), - }, - Clone::clone, - ); - let init_method = contains_initialize_with(&input.attrs)?; - let return_value = match &input.fields { - Fields::Named(fields) => { - let mut body = TokenStream2::new(); - for field in &fields.named { - let field_name = field.ident.as_ref().unwrap(); - let delta = if contains_skip(&field.attrs) { - quote! { - #field_name: Default::default(), - } - } else { - let field_type = &field.ty; - where_clause.predicates.push(syn::parse2(quote! { - #field_type: #cratename::BorshDeserialize - }).unwrap()); - - quote! { - #field_name: #cratename::BorshDeserialize::deserialize(buf)?, - } - }; - body.extend(delta); - } - quote! { - Self { #body } - } - } - Fields::Unnamed(fields) => { - let mut body = TokenStream2::new(); - for _ in 0..fields.unnamed.len() { - let delta = quote! { - #cratename::BorshDeserialize::deserialize(buf)?, - }; - body.extend(delta); - } - quote! { - Self( #body ) - } - } - Fields::Unit => { - quote! { - Self {} - } - } - }; - if let Some(method_ident) = init_method { - Ok(quote! { - impl #impl_generics #cratename::de::BorshDeserialize for #name #ty_generics #where_clause { - fn deserialize(buf: &mut &[u8]) -> core::result::Result { - let mut return_value = #return_value; - return_value.#method_ident(); - Ok(return_value) - } - } - }) - } else { - Ok(quote! { - impl #impl_generics #cratename::de::BorshDeserialize for #name #ty_generics #where_clause { - fn deserialize(buf: &mut &[u8]) -> core::result::Result { - Ok(#return_value) - } - } - }) - } -} diff --git a/borsh-rs/borsh-derive-internal/src/struct_ser.rs b/borsh-rs/borsh-derive-internal/src/struct_ser.rs deleted file mode 100644 index 1048c2f94..000000000 --- a/borsh-rs/borsh-derive-internal/src/struct_ser.rs +++ /dev/null @@ -1,150 +0,0 @@ -use core::convert::TryFrom; - -use quote::quote; -use syn::export::{Span, TokenStream2}; -use syn::{Fields, Ident, Index, ItemStruct, WhereClause}; - -use crate::attribute_helpers::contains_skip; - -pub fn struct_ser(input: &ItemStruct, cratename: Ident) -> syn::Result { - let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.map_or_else( - || WhereClause { - where_token: Default::default(), - predicates: Default::default(), - }, - Clone::clone, - ); - let mut body = TokenStream2::new(); - match &input.fields { - Fields::Named(fields) => { - for field in &fields.named { - if contains_skip(&field.attrs) { - continue; - } - let field_name = field.ident.as_ref().unwrap(); - let delta = quote! { - #cratename::BorshSerialize::serialize(&self.#field_name, writer)?; - }; - body.extend(delta); - - let field_type = &field.ty; - where_clause.predicates.push(syn::parse2(quote! { - #field_type: #cratename::ser::BorshSerialize - }).unwrap()); - } - } - Fields::Unnamed(fields) => { - for field_idx in 0..fields.unnamed.len() { - let field_idx = Index { - index: u32::try_from(field_idx).expect("up to 2^32 fields are supported"), - span: Span::call_site(), - }; - let delta = quote! { - #cratename::BorshSerialize::serialize(&self.#field_idx, writer)?; - }; - body.extend(delta); - } - } - Fields::Unit => {} - } - Ok(quote! { - impl #impl_generics #cratename::ser::BorshSerialize for #name #ty_generics #where_clause { - fn serialize(&self, writer: &mut W) -> core::result::Result<(), #cratename::maybestd::io::Error> { - #body - Ok(()) - } - } - }) -} - -// Rustfmt removes comas. -#[rustfmt::skip] -#[cfg(test)] -mod tests { - use super::*; - - fn assert_eq(expected: TokenStream2, actual: TokenStream2) { - assert_eq!(expected.to_string(), actual.to_string()) - } - - #[test] - fn simple_struct() { - let item_struct: ItemStruct = syn::parse2(quote!{ - struct A { - x: u64, - y: String, - } - }).unwrap(); - - let actual = struct_ser(&item_struct, Ident::new("borsh", Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::ser::BorshSerialize for A - where - u64: borsh::ser::BorshSerialize, - String: borsh::ser::BorshSerialize - { - fn serialize(&self, writer: &mut W) -> core::result::Result<(), borsh::maybestd::io::Error> { - borsh::BorshSerialize::serialize(&self.x, writer)?; - borsh::BorshSerialize::serialize(&self.y, writer)?; - Ok(()) - } - } - }; - assert_eq(expected, actual); - } - - #[test] - fn simple_generics() { - let item_struct: ItemStruct = syn::parse2(quote!{ - struct A { - x: HashMap, - y: String, - } - }).unwrap(); - - let actual = struct_ser(&item_struct, Ident::new("borsh", Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::ser::BorshSerialize for A - where - HashMap: borsh::ser::BorshSerialize, - String: borsh::ser::BorshSerialize - { - fn serialize(&self, writer: &mut W) -> core::result::Result<(), borsh::maybestd::io::Error> { - borsh::BorshSerialize::serialize(&self.x, writer)?; - borsh::BorshSerialize::serialize(&self.y, writer)?; - Ok(()) - } - } - }; - assert_eq(expected, actual); - } - - #[test] - fn bound_generics() { - let item_struct: ItemStruct = syn::parse2(quote!{ - struct A where V: Value { - x: HashMap, - y: String, - } - }).unwrap(); - - let actual = struct_ser(&item_struct, Ident::new("borsh", Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::ser::BorshSerialize for A - where - V: Value, - HashMap: borsh::ser::BorshSerialize, - String: borsh::ser::BorshSerialize - { - fn serialize(&self, writer: &mut W) -> core::result::Result<(), borsh::maybestd::io::Error> { - borsh::BorshSerialize::serialize(&self.x, writer)?; - borsh::BorshSerialize::serialize(&self.y, writer)?; - Ok(()) - } - } - }; - assert_eq(expected, actual); - } -} diff --git a/borsh-rs/borsh-derive-internal/src/union_de.rs b/borsh-rs/borsh-derive-internal/src/union_de.rs deleted file mode 100644 index 66248169f..000000000 --- a/borsh-rs/borsh-derive-internal/src/union_de.rs +++ /dev/null @@ -1,6 +0,0 @@ -use syn::export::TokenStream2; -use syn::{Ident, ItemUnion}; - -pub fn union_de(_input: &ItemUnion, _cratename: Ident) -> syn::Result { - unimplemented!() -} diff --git a/borsh-rs/borsh-derive-internal/src/union_ser.rs b/borsh-rs/borsh-derive-internal/src/union_ser.rs deleted file mode 100644 index 3109f6dbe..000000000 --- a/borsh-rs/borsh-derive-internal/src/union_ser.rs +++ /dev/null @@ -1,6 +0,0 @@ -use syn::export::TokenStream2; -use syn::{Ident, ItemUnion}; - -pub fn union_ser(_input: &ItemUnion, _cratename: Ident) -> syn::Result { - unimplemented!() -} diff --git a/borsh-rs/borsh-derive/Cargo.toml b/borsh-rs/borsh-derive/Cargo.toml deleted file mode 100644 index f5faa2f58..000000000 --- a/borsh-rs/borsh-derive/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "borsh-derive" -version = "0.8.0" -authors = ["Near Inc "] -edition = "2018" -license = "Apache-2.0" -readme = "README.md" -categories = ["encoding", "network-programming"] -repository = "https://github.com/nearprotocol/borsh" -homepage = "http://borsh.io" -description = """ -Binary Object Representation Serializer for Hashing -""" - -[lib] -proc-macro = true - -[dependencies] -borsh-derive-internal = { path = "../borsh-derive-internal", version="0.8.0"} -borsh-schema-derive-internal = { path = "../borsh-schema-derive-internal", version="0.8.0"} -syn = {version = "1", features = ["full", "fold"] } -proc-macro-crate = "0.1.5" diff --git a/borsh-rs/borsh-derive/README.md b/borsh-rs/borsh-derive/README.md deleted file mode 120000 index fe8400541..000000000 --- a/borsh-rs/borsh-derive/README.md +++ /dev/null @@ -1 +0,0 @@ -../../README.md \ No newline at end of file diff --git a/borsh-rs/borsh-derive/src/lib.rs b/borsh-rs/borsh-derive/src/lib.rs deleted file mode 100644 index 459b975d1..000000000 --- a/borsh-rs/borsh-derive/src/lib.rs +++ /dev/null @@ -1,79 +0,0 @@ -extern crate proc_macro; -use borsh_derive_internal::*; -use borsh_schema_derive_internal::*; -use proc_macro::TokenStream; -use proc_macro_crate::crate_name; -use syn::export::Span; -use syn::{Ident, ItemEnum, ItemStruct, ItemUnion}; - -#[proc_macro_derive(BorshSerialize, attributes(borsh_skip))] -pub fn borsh_serialize(input: TokenStream) -> TokenStream { - let cratename = Ident::new( - &crate_name("borsh").unwrap_or("borsh".to_string()), - Span::call_site(), - ); - - let res = if let Ok(input) = syn::parse::(input.clone()) { - struct_ser(&input, cratename) - } else if let Ok(input) = syn::parse::(input.clone()) { - enum_ser(&input, cratename) - } else if let Ok(input) = syn::parse::(input.clone()) { - union_ser(&input, cratename) - } else { - // Derive macros can only be defined on structs, enums, and unions. - unreachable!() - }; - TokenStream::from(match res { - Ok(res) => res, - Err(err) => err.to_compile_error(), - }) -} - -#[proc_macro_derive(BorshDeserialize, attributes(borsh_skip, borsh_init))] -pub fn borsh_deserialize(input: TokenStream) -> TokenStream { - let cratename = Ident::new( - &crate_name("borsh").unwrap_or("borsh".to_string()), - Span::call_site(), - ); - - let res = if let Ok(input) = syn::parse::(input.clone()) { - struct_de(&input, cratename) - } else if let Ok(input) = syn::parse::(input.clone()) { - enum_de(&input, cratename) - } else if let Ok(input) = syn::parse::(input.clone()) { - union_de(&input, cratename) - } else { - // Derive macros can only be defined on structs, enums, and unions. - unreachable!() - }; - TokenStream::from(match res { - Ok(res) => res, - Err(err) => err.to_compile_error(), - }) -} - -#[proc_macro_derive(BorshSchema, attributes(borsh_skip))] -pub fn borsh_schema(input: TokenStream) -> TokenStream { - let cratename = Ident::new( - &crate_name("borsh").unwrap_or("borsh".to_string()), - Span::call_site(), - ); - - let res = if let Ok(input) = syn::parse::(input.clone()) { - process_struct(&input, cratename) - } else if let Ok(input) = syn::parse::(input.clone()) { - process_enum(&input, cratename) - } else if let Ok(_) = syn::parse::(input.clone()) { - Err(syn::Error::new( - Span::call_site(), - "Borsh schema does not support unions yet.", - )) - } else { - // Derive macros can only be defined on structs, enums, and unions. - unreachable!() - }; - TokenStream::from(match res { - Ok(res) => res, - Err(err) => err.to_compile_error(), - }) -} diff --git a/borsh-rs/borsh-schema-derive-internal/Cargo.toml b/borsh-rs/borsh-schema-derive-internal/Cargo.toml deleted file mode 100644 index 9134140ae..000000000 --- a/borsh-rs/borsh-schema-derive-internal/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "borsh-schema-derive-internal" -version = "0.8.0" -authors = ["Near Inc "] -edition = "2018" -license = "Apache-2.0" -categories = ["encoding", "network-programming"] -repository = "https://github.com/nearprotocol/borsh" -homepage = "http://borsh.io" -description = """ -Schema Generator for Borsh -""" - -[dependencies] -proc-macro2 = "1" -syn = {version = "1", features = ["full", "fold"] } -quote = "1" diff --git a/borsh-rs/borsh-schema-derive-internal/src/enum_schema.rs b/borsh-rs/borsh-schema-derive-internal/src/enum_schema.rs deleted file mode 100644 index bdea772c7..000000000 --- a/borsh-rs/borsh-schema-derive-internal/src/enum_schema.rs +++ /dev/null @@ -1,326 +0,0 @@ -use crate::helpers::declaration; -use quote::quote; -use syn::export::{Span, ToTokens, TokenStream2}; -use syn::{ - parse_quote, AttrStyle, Attribute, Field, Fields, FieldsUnnamed, Ident, ItemEnum, ItemStruct, - Visibility, -}; - -pub fn process_enum(input: &ItemEnum, cratename: Ident) -> syn::Result { - let name = &input.ident; - let name_str = name.to_token_stream().to_string(); - let generics = &input.generics; - let (impl_generics, ty_generics, _) = generics.split_for_impl(); - // Generate function that returns the name of the type. - let (declaration, where_clause) = declaration(&name_str, &input.generics, cratename.clone()); - - // Generate function that returns the schema for variants. - // Definitions of the variants. - let mut variants_defs = vec![]; - // Definitions of the anonymous structs used in variants. - let mut anonymous_defs = TokenStream2::new(); - // Recursive calls to `add_definitions_recursively`. - let mut add_recursive_defs = TokenStream2::new(); - for variant in &input.variants { - let variant_name_str = variant.ident.to_token_stream().to_string(); - let full_variant_name_str = format!("{}{}", name_str, variant_name_str); - let full_variant_ident = Ident::new(full_variant_name_str.as_str(), Span::call_site()); - let mut anonymous_struct = ItemStruct { - attrs: vec![], - vis: Visibility::Inherited, - struct_token: Default::default(), - ident: full_variant_ident.clone(), - generics: (*generics).clone(), - fields: variant.fields.clone(), - semi_token: Some(Default::default()), - }; - let generic_params = generics - .type_params() - .fold(TokenStream2::new(), |acc, generic| { - let ident = &generic.ident; - quote! { - #acc - #ident , - } - }); - if !generic_params.is_empty() { - let attr = Attribute { - pound_token: Default::default(), - style: AttrStyle::Outer, - bracket_token: Default::default(), - path: parse_quote! {borsh_skip}, - tokens: Default::default(), - }; - // Whether we should convert the struct from unit struct to regular struct. - let mut unit_to_regular = false; - match &mut anonymous_struct.fields { - Fields::Named(named) => { - named.named.push(Field { - attrs: vec![attr.clone()], - vis: Visibility::Inherited, - ident: Some(Ident::new("borsh_schema_phantom_data", Span::call_site())), - colon_token: None, - ty: parse_quote! {::core::marker::PhantomData<(#generic_params)>}, - }); - } - Fields::Unnamed(unnamed) => { - unnamed.unnamed.push(Field { - attrs: vec![attr.clone()], - vis: Visibility::Inherited, - ident: None, - colon_token: None, - ty: parse_quote! {::core::marker::PhantomData<(#generic_params)>}, - }); - } - Fields::Unit => { - unit_to_regular = true; - } - } - if unit_to_regular { - let mut fields = FieldsUnnamed { - paren_token: Default::default(), - unnamed: Default::default(), - }; - fields.unnamed.push(Field { - attrs: vec![attr], - vis: Visibility::Inherited, - ident: None, - colon_token: None, - ty: parse_quote! {::core::marker::PhantomData<(#generic_params)>}, - }); - anonymous_struct.fields = Fields::Unnamed(fields); - } - } - anonymous_defs.extend(quote! { - #[derive(#cratename::BorshSchema)] - #anonymous_struct - }); - add_recursive_defs.extend(quote! { - <#full_variant_ident #ty_generics>::add_definitions_recursively(definitions); - }); - variants_defs.push(quote! { - (#variant_name_str.to_string(), <#full_variant_ident #ty_generics>::declaration()) - }); - } - - let type_definitions = quote! { - fn add_definitions_recursively(definitions: &mut #cratename::maybestd::collections::HashMap<#cratename::schema::Declaration, #cratename::schema::Definition>) { - #anonymous_defs - #add_recursive_defs - let variants = #cratename::maybestd::vec![#(#variants_defs),*]; - let definition = #cratename::schema::Definition::Enum{variants}; - Self::add_definition(Self::declaration(), definition, definitions); - } - }; - let where_clause = if !where_clause.is_empty() { - quote! { where #(#where_clause),*} - } else { - TokenStream2::new() - }; - Ok(quote! { - impl #impl_generics #cratename::BorshSchema for #name #ty_generics #where_clause { - fn declaration() -> #cratename::schema::Declaration { - #declaration - } - #type_definitions - } - }) -} - -// Rustfmt removes comas. -#[rustfmt::skip] -#[cfg(test)] -mod tests { - use super::*; - - fn assert_eq(expected: TokenStream2, actual: TokenStream2) { - assert_eq!(expected.to_string(), actual.to_string()) - } - - #[test] - fn simple_enum() { - let item_enum: ItemEnum = syn::parse2(quote!{ - enum A { - Bacon, - Eggs - } - }).unwrap(); - - let actual = process_enum(&item_enum, Ident::new("borsh", Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::BorshSchema for A { - fn declaration() -> borsh::schema::Declaration { - "A".to_string() - } - fn add_definitions_recursively( - definitions: &mut borsh::maybestd::collections::HashMap< - borsh::schema::Declaration, - borsh::schema::Definition - > - ) { - #[derive(borsh :: BorshSchema)] - struct ABacon; - #[derive(borsh :: BorshSchema)] - struct AEggs; - ::add_definitions_recursively(definitions); - ::add_definitions_recursively(definitions); - let variants = borsh::maybestd::vec![ - ("Bacon".to_string(), ::declaration()), - ("Eggs".to_string(), ::declaration()) - ]; - let definition = borsh::schema::Definition::Enum { variants }; - Self::add_definition(Self::declaration(), definition, definitions); - } - } - }; - assert_eq(expected, actual); - } - - #[test] - fn single_field_enum() { - let item_enum: ItemEnum = syn::parse2(quote! { - enum A { - Bacon, - } - }).unwrap(); - - let actual = process_enum(&item_enum, Ident::new("borsh", Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::BorshSchema for A { - fn declaration() -> borsh::schema::Declaration { - "A".to_string() - } - fn add_definitions_recursively( - definitions: &mut borsh::maybestd::collections::HashMap< - borsh::schema::Declaration, - borsh::schema::Definition - > - ) { - #[derive(borsh :: BorshSchema)] - struct ABacon; - ::add_definitions_recursively(definitions); - let variants = borsh::maybestd::vec![("Bacon".to_string(), ::declaration())]; - let definition = borsh::schema::Definition::Enum { variants }; - Self::add_definition(Self::declaration(), definition, definitions); - } - } - }; - assert_eq(expected, actual); - } - - #[test] - fn complex_enum() { - let item_enum: ItemEnum = syn::parse2(quote! { - enum A { - Bacon, - Eggs, - Salad(Tomatoes, Cucumber, Oil), - Sausage{wrapper: Wrapper, filling: Filling}, - } - }).unwrap(); - - let actual = process_enum(&item_enum, Ident::new("borsh", Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::BorshSchema for A { - fn declaration() -> borsh::schema::Declaration { - "A".to_string() - } - fn add_definitions_recursively( - definitions: &mut borsh::maybestd::collections::HashMap< - borsh::schema::Declaration, - borsh::schema::Definition - > - ) { - #[derive(borsh :: BorshSchema)] - struct ABacon; - #[derive(borsh :: BorshSchema)] - struct AEggs; - #[derive(borsh :: BorshSchema)] - struct ASalad(Tomatoes, Cucumber, Oil); - #[derive(borsh :: BorshSchema)] - struct ASausage { - wrapper: Wrapper, - filling: Filling - } - ::add_definitions_recursively(definitions); - ::add_definitions_recursively(definitions); - ::add_definitions_recursively(definitions); - ::add_definitions_recursively(definitions); - let variants = borsh::maybestd::vec![ - ("Bacon".to_string(), ::declaration()), - ("Eggs".to_string(), ::declaration()), - ("Salad".to_string(), ::declaration()), - ("Sausage".to_string(), ::declaration()) - ]; - let definition = borsh::schema::Definition::Enum { variants }; - Self::add_definition(Self::declaration(), definition, definitions); - } - } - }; - assert_eq(expected, actual); - } - - #[test] - fn complex_enum_generics() { - let item_enum: ItemEnum = syn::parse2(quote! { - enum A { - Bacon, - Eggs, - Salad(Tomatoes, C, Oil), - Sausage{wrapper: W, filling: Filling}, - } - }).unwrap(); - - let actual = process_enum(&item_enum, Ident::new("borsh", Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::BorshSchema for A - where - C: borsh::BorshSchema, - W: borsh::BorshSchema - { - fn declaration() -> borsh::schema::Declaration { - let params = borsh::maybestd::vec![::declaration(), ::declaration()]; - format!(r#"{}<{}>"#, "A", params.join(", ")) - } - fn add_definitions_recursively( - definitions: &mut borsh::maybestd::collections::HashMap< - borsh::schema::Declaration, - borsh::schema::Definition - > - ) { - #[derive(borsh :: BorshSchema)] - struct ABacon(#[borsh_skip] ::core::marker::PhantomData<(C, W)>); - #[derive(borsh :: BorshSchema)] - struct AEggs(#[borsh_skip] ::core::marker::PhantomData<(C, W)>); - #[derive(borsh :: BorshSchema)] - struct ASalad( - Tomatoes, - C, - Oil, - #[borsh_skip] ::core::marker::PhantomData<(C, W)> - ); - #[derive(borsh :: BorshSchema)] - struct ASausage { - wrapper: W, - filling: Filling, - #[borsh_skip] - borsh_schema_phantom_data: ::core::marker::PhantomData<(C, W)> - } - >::add_definitions_recursively(definitions); - >::add_definitions_recursively(definitions); - >::add_definitions_recursively(definitions); - >::add_definitions_recursively(definitions); - let variants = borsh::maybestd::vec![ - ("Bacon".to_string(), >::declaration()), - ("Eggs".to_string(), >::declaration()), - ("Salad".to_string(), >::declaration()), - ("Sausage".to_string(), >::declaration()) - ]; - let definition = borsh::schema::Definition::Enum { variants }; - Self::add_definition(Self::declaration(), definition, definitions); - } - } - }; - assert_eq(expected, actual); - } -} diff --git a/borsh-rs/borsh-schema-derive-internal/src/helpers.rs b/borsh-rs/borsh-schema-derive-internal/src/helpers.rs deleted file mode 100644 index 87781ec05..000000000 --- a/borsh-rs/borsh-schema-derive-internal/src/helpers.rs +++ /dev/null @@ -1,45 +0,0 @@ -use quote::{quote, ToTokens}; -use syn::export::TokenStream2; -use syn::{Attribute, Generics, Meta, Ident}; - -pub fn contains_skip(attrs: &[Attribute]) -> bool { - for attr in attrs.iter() { - if let Ok(Meta::Path(path)) = attr.parse_meta() { - if path.to_token_stream().to_string().as_str() == "borsh_skip" { - return true; - } - } - } - false -} - -pub fn declaration(ident_str: &String, generics: &Generics, cratename: Ident) -> (TokenStream2, Vec) { - let (_, _, where_clause_generics) = generics.split_for_impl(); - // Generate function that returns the name of the type. - let mut declaration_params = vec![]; - let mut where_clause = vec![]; - if let Some(where_clause_generics) = where_clause_generics { - let where_clause_generics = &where_clause_generics.predicates; - where_clause.push(quote! {#where_clause_generics}); - } - for type_param in generics.type_params() { - let type_param_name = &type_param.ident; - declaration_params.push(quote! { - <#type_param_name>::declaration() - }); - where_clause.push(quote! { - #type_param_name: #cratename::BorshSchema - }); - } - let result = if declaration_params.is_empty() { - quote! { - #ident_str.to_string() - } - } else { - quote! { - let params = #cratename::maybestd::vec![#(#declaration_params),*]; - format!(r#"{}<{}>"#, #ident_str, params.join(", ")) - } - }; - (result, where_clause) -} diff --git a/borsh-rs/borsh-schema-derive-internal/src/lib.rs b/borsh-rs/borsh-schema-derive-internal/src/lib.rs deleted file mode 100644 index b75c1ee6a..000000000 --- a/borsh-rs/borsh-schema-derive-internal/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![recursion_limit = "128"] - -mod helpers; - -mod enum_schema; -mod struct_schema; -pub use enum_schema::process_enum; -pub use struct_schema::process_struct; diff --git a/borsh-rs/borsh-schema-derive-internal/src/struct_schema.rs b/borsh-rs/borsh-schema-derive-internal/src/struct_schema.rs deleted file mode 100644 index e624fb489..000000000 --- a/borsh-rs/borsh-schema-derive-internal/src/struct_schema.rs +++ /dev/null @@ -1,382 +0,0 @@ -use crate::helpers::{contains_skip, declaration}; -use quote::quote; -use syn::export::{ToTokens, TokenStream2}; -use syn::{Fields, ItemStruct, Ident}; - - -pub fn process_struct(input: &ItemStruct, cratename: Ident) -> syn::Result { - let name = &input.ident; - let name_str = name.to_token_stream().to_string(); - let generics = &input.generics; - let (impl_generics, ty_generics, _) = generics.split_for_impl(); - // Generate function that returns the name of the type. - let (declaration, mut where_clause) = declaration(&name_str, &input.generics, cratename.clone()); - - // Generate function that returns the schema of required types. - let mut fields_vec = vec![]; - let mut struct_fields = TokenStream2::new(); - let mut add_definitions_recursively_rec = TokenStream2::new(); - match &input.fields { - Fields::Named(fields) => { - for field in &fields.named { - if contains_skip(&field.attrs) { - continue; - } - let field_name = field.ident.as_ref().unwrap().to_token_stream().to_string(); - let field_type = &field.ty; - fields_vec.push(quote! { - (#field_name.to_string(), <#field_type>::declaration()) - }); - add_definitions_recursively_rec.extend(quote! { - <#field_type>::add_definitions_recursively(definitions); - }); - where_clause.push(quote! { - #field_type: #cratename::BorshSchema - }); - } - if !fields_vec.is_empty() { - struct_fields = quote! { - let fields = #cratename::schema::Fields::NamedFields(#cratename::maybestd::vec![#(#fields_vec),*]); - }; - } - } - Fields::Unnamed(fields) => { - for field in &fields.unnamed { - if contains_skip(&field.attrs) { - continue; - } - let field_type = &field.ty; - fields_vec.push(quote! { - <#field_type>::declaration() - }); - add_definitions_recursively_rec.extend(quote! { - <#field_type>::add_definitions_recursively(definitions); - }); - where_clause.push(quote! { - #field_type: #cratename::BorshSchema - }); - } - if !fields_vec.is_empty() { - struct_fields = quote! { - let fields = #cratename::schema::Fields::UnnamedFields(#cratename::maybestd::vec![#(#fields_vec),*]); - }; - } - } - Fields::Unit => {} - } - - if fields_vec.is_empty() { - struct_fields = quote! { - let fields = #cratename::schema::Fields::Empty; - }; - } - - let add_definitions_recursively = quote! { - fn add_definitions_recursively(definitions: &mut #cratename::maybestd::collections::HashMap<#cratename::schema::Declaration, #cratename::schema::Definition>) { - #struct_fields - let definition = #cratename::schema::Definition::Struct { fields }; - Self::add_definition(Self::declaration(), definition, definitions); - #add_definitions_recursively_rec - } - }; - let where_clause = if !where_clause.is_empty() { - quote! { where #(#where_clause),*} - } else { - TokenStream2::new() - }; - Ok(quote! { - impl #impl_generics #cratename::BorshSchema for #name #ty_generics #where_clause { - fn declaration() -> #cratename::schema::Declaration { - #declaration - } - #add_definitions_recursively - } - }) -} - -// Rustfmt removes comas. -#[rustfmt::skip::macros(quote)] -#[cfg(test)] -mod tests { - use super::*; - - fn assert_eq(expected: TokenStream2, actual: TokenStream2) { - assert_eq!(expected.to_string(), actual.to_string()) - } - - #[test] - fn unit_struct() { - let item_struct: ItemStruct = syn::parse2(quote!{ - struct A; - }) - .unwrap(); - - let actual = process_struct(&item_struct, Ident::new("borsh", proc_macro2::Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::BorshSchema for A - { - fn declaration() -> borsh::schema::Declaration { - "A".to_string() - } - fn add_definitions_recursively(definitions: &mut borsh::maybestd::collections::HashMap) { - let fields = borsh::schema::Fields::Empty; - let definition = borsh::schema::Definition::Struct { fields }; - Self::add_definition(Self::declaration(), definition, definitions); - } - } - }; - assert_eq(expected, actual); - } - - #[test] - fn wrapper_struct() { - let item_struct: ItemStruct = syn::parse2(quote!{ - struct A(T); - }) - .unwrap(); - - let actual = process_struct(&item_struct, Ident::new("borsh", proc_macro2::Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::BorshSchema for A - where - T: borsh::BorshSchema, - T: borsh::BorshSchema - { - fn declaration() -> borsh::schema::Declaration { - let params = borsh::maybestd::vec![::declaration()]; - format!(r#"{}<{}>"#, "A", params.join(", ")) - } - fn add_definitions_recursively( - definitions: &mut borsh::maybestd::collections::HashMap< - borsh::schema::Declaration, - borsh::schema::Definition - > - ) { - let fields = borsh::schema::Fields::UnnamedFields(borsh::maybestd::vec![::declaration()]); - let definition = borsh::schema::Definition::Struct { fields }; - Self::add_definition(Self::declaration(), definition, definitions); - ::add_definitions_recursively(definitions); - } - } - }; - assert_eq(expected, actual); - } - - #[test] - fn tuple_struct() { - let item_struct: ItemStruct = syn::parse2(quote!{ - struct A(u64, String); - }) - .unwrap(); - - let actual = process_struct(&item_struct, Ident::new("borsh", proc_macro2::Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::BorshSchema for A - where - u64: borsh::BorshSchema, - String: borsh::BorshSchema - { - fn declaration() -> borsh::schema::Declaration { - "A".to_string() - } - fn add_definitions_recursively( - definitions: &mut borsh::maybestd::collections::HashMap< - borsh::schema::Declaration, - borsh::schema::Definition - > - ) { - let fields = borsh::schema::Fields::UnnamedFields(borsh::maybestd::vec![ - ::declaration(), - ::declaration() - ]); - let definition = borsh::schema::Definition::Struct { fields }; - Self::add_definition(Self::declaration(), definition, definitions); - ::add_definitions_recursively(definitions); - ::add_definitions_recursively(definitions); - } - } - }; - assert_eq(expected, actual); - } - - #[test] - fn tuple_struct_params() { - let item_struct: ItemStruct = syn::parse2(quote!{ - struct A(K, V); - }) - .unwrap(); - - let actual = process_struct(&item_struct, Ident::new("borsh", proc_macro2::Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::BorshSchema for A - where - K: borsh::BorshSchema, - V: borsh::BorshSchema, - K: borsh::BorshSchema, - V: borsh::BorshSchema - { - fn declaration() -> borsh::schema::Declaration { - let params = borsh::maybestd::vec![::declaration(), ::declaration()]; - format!(r#"{}<{}>"#, "A", params.join(", ")) - } - fn add_definitions_recursively( - definitions: &mut borsh::maybestd::collections::HashMap< - borsh::schema::Declaration, - borsh::schema::Definition - > - ) { - let fields = - borsh::schema::Fields::UnnamedFields(borsh::maybestd::vec![::declaration(), ::declaration()]); - let definition = borsh::schema::Definition::Struct { fields }; - Self::add_definition(Self::declaration(), definition, definitions); - ::add_definitions_recursively(definitions); - ::add_definitions_recursively(definitions); - } - } - }; - assert_eq(expected, actual); - } - - #[test] - fn simple_struct() { - let item_struct: ItemStruct = syn::parse2(quote!{ - struct A { - x: u64, - y: String, - } - }) - .unwrap(); - - let actual = process_struct(&item_struct, Ident::new("borsh", proc_macro2::Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::BorshSchema for A - where - u64: borsh::BorshSchema, - String: borsh::BorshSchema - { - fn declaration() -> borsh::schema::Declaration { - "A".to_string() - } - fn add_definitions_recursively( - definitions: &mut borsh::maybestd::collections::HashMap< - borsh::schema::Declaration, - borsh::schema::Definition - > - ) { - let fields = borsh::schema::Fields::NamedFields(borsh::maybestd::vec![ - ("x".to_string(), ::declaration()), - ("y".to_string(), ::declaration()) - ]); - let definition = borsh::schema::Definition::Struct { fields }; - Self::add_definition(Self::declaration(), definition, definitions); - ::add_definitions_recursively(definitions); - ::add_definitions_recursively(definitions); - } - } - }; - assert_eq(expected, actual); - } - - #[test] - fn simple_generics() { - let item_struct: ItemStruct = syn::parse2(quote!{ - struct A { - x: HashMap, - y: String, - } - }) - .unwrap(); - - let actual = process_struct(&item_struct, Ident::new("borsh", proc_macro2::Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::BorshSchema for A - where - K: borsh::BorshSchema, - V: borsh::BorshSchema, - HashMap: borsh::BorshSchema, - String: borsh::BorshSchema - { - fn declaration() -> borsh::schema::Declaration { - let params = borsh::maybestd::vec![::declaration(), ::declaration()]; - format!(r#"{}<{}>"#, "A", params.join(", ")) - } - fn add_definitions_recursively( - definitions: &mut borsh::maybestd::collections::HashMap< - borsh::schema::Declaration, - borsh::schema::Definition - > - ) { - let fields = borsh::schema::Fields::NamedFields(borsh::maybestd::vec![ - ("x".to_string(), >::declaration()), - ("y".to_string(), ::declaration()) - ]); - let definition = borsh::schema::Definition::Struct { fields }; - Self::add_definition(Self::declaration(), definition, definitions); - >::add_definitions_recursively(definitions); - ::add_definitions_recursively(definitions); - } - } - }; - assert_eq(expected, actual); - } - - #[test] - fn tuple_struct_whole_skip() { - let item_struct: ItemStruct = syn::parse2(quote!{ - struct A(#[borsh_skip] String); - }) - .unwrap(); - - let actual = process_struct(&item_struct, Ident::new("borsh", proc_macro2::Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::BorshSchema for A { - fn declaration() -> borsh::schema::Declaration { - "A".to_string() - } - fn add_definitions_recursively( - definitions: &mut borsh::maybestd::collections::HashMap< - borsh::schema::Declaration, - borsh::schema::Definition - > - ) { - let fields = borsh::schema::Fields::Empty; - let definition = borsh::schema::Definition::Struct { fields }; - Self::add_definition(Self::declaration(), definition, definitions); - } - } - }; - assert_eq(expected, actual); - } - - #[test] - fn tuple_struct_partial_skip() { - let item_struct: ItemStruct = syn::parse2(quote!{ - struct A(#[borsh_skip] u64, String); - }) - .unwrap(); - - let actual = process_struct(&item_struct, Ident::new("borsh", proc_macro2::Span::call_site())).unwrap(); - let expected = quote!{ - impl borsh::BorshSchema for A - where - String: borsh::BorshSchema - { - fn declaration() -> borsh::schema::Declaration { - "A".to_string() - } - fn add_definitions_recursively( - definitions: &mut borsh::maybestd::collections::HashMap< - borsh::schema::Declaration, - borsh::schema::Definition - > - ) { - let fields = borsh::schema::Fields::UnnamedFields(borsh::maybestd::vec![::declaration()]); - let definition = borsh::schema::Definition::Struct { fields }; - Self::add_definition(Self::declaration(), definition, definitions); - ::add_definitions_recursively(definitions); - } - } - }; - assert_eq(expected, actual); - } -} diff --git a/borsh-rs/borsh/Cargo.toml b/borsh-rs/borsh/Cargo.toml deleted file mode 100644 index dde5ee7f7..000000000 --- a/borsh-rs/borsh/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "borsh" -version = "0.8.0" -authors = ["Near Inc "] -edition = "2018" -license = "Apache-2.0" -readme = "README.md" -categories = ["encoding", "network-programming"] -repository = "https://github.com/nearprotocol/borsh" -homepage = "http://borsh.io" -description = """ -Binary Object Representation Serializer for Hashing -""" - -[lib] -name = "borsh" -path = "src/lib.rs" - -[[bin]] -name = "generate_schema_schema" -path = "src/generate_schema_schema.rs" - -[dependencies] -borsh-derive = { path = "../borsh-derive", version = "0.8.0" } -hashbrown = "0.9.1" - -[features] -default = ["std"] -std = [] diff --git a/borsh-rs/borsh/README.md b/borsh-rs/borsh/README.md deleted file mode 120000 index fe8400541..000000000 --- a/borsh-rs/borsh/README.md +++ /dev/null @@ -1 +0,0 @@ -../../README.md \ No newline at end of file diff --git a/borsh-rs/borsh/src/de/hint.rs b/borsh-rs/borsh/src/de/hint.rs deleted file mode 100644 index 7af550cef..000000000 --- a/borsh-rs/borsh/src/de/hint.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[inline] -pub fn cautious(hint: u32) -> usize { - let el_size = core::mem::size_of::() as u32; - core::cmp::max(core::cmp::min(hint, 4096 / el_size), 1) as usize -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - pub fn test_cautious_u8() { - assert_eq!(cautious::(10), 10); - } -} diff --git a/borsh-rs/borsh/src/de/mod.rs b/borsh-rs/borsh/src/de/mod.rs deleted file mode 100644 index ec3c75eed..000000000 --- a/borsh-rs/borsh/src/de/mod.rs +++ /dev/null @@ -1,528 +0,0 @@ -use core::{ - convert::TryInto, - hash::Hash, - mem::{forget, size_of} -}; - -use crate::maybestd::{ - io::{Error, ErrorKind, Result}, - borrow::{ - Cow, - ToOwned, - Borrow - }, - collections::{BTreeMap, HashMap, HashSet}, - format, - string::{String, ToString}, - vec::Vec, - boxed::Box -}; - - -mod hint; - -const ERROR_NOT_ALL_BYTES_READ: &str = "Not all bytes read"; -const ERROR_UNEXPECTED_LENGTH_OF_INPUT: &str = "Unexpected length of input"; - -/// A data-structure that can be de-serialized from binary format by NBOR. -pub trait BorshDeserialize: Sized { - /// Deserializes this instance from a given slice of bytes. - /// Updates the buffer to point at the remaining bytes. - fn deserialize(buf: &mut &[u8]) -> Result; - - /// Deserialize this instance from a slice of bytes. - fn try_from_slice(v: &[u8]) -> Result { - let mut v_mut = v; - let result = Self::deserialize(&mut v_mut)?; - if !v_mut.is_empty() { - return Err(Error::new( - ErrorKind::InvalidData, - ERROR_NOT_ALL_BYTES_READ, - )); - } - Ok(result) - } - - /// Whether Self is u8. - /// NOTE: `Vec` is the most common use-case for serialization and deserialization, it's - /// worth handling it as a special case to improve performance. - /// It's a workaround for specific `Vec` implementation versus generic `Vec` - /// implementation. See https://github.com/rust-lang/rfcs/pull/1210 for details. - #[inline] - fn is_u8() -> bool { - false - } -} - -impl BorshDeserialize for u8 { - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - if buf.is_empty() { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); - } - let res = buf[0]; - *buf = &buf[1..]; - Ok(res) - } - - #[inline] - fn is_u8() -> bool { - true - } -} - -macro_rules! impl_for_integer { - ($type: ident) => { - impl BorshDeserialize for $type { - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - if buf.len() < size_of::<$type>() { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); - } - let res = $type::from_le_bytes(buf[..size_of::<$type>()].try_into().unwrap()); - *buf = &buf[size_of::<$type>()..]; - Ok(res) - } - } - }; -} - -impl_for_integer!(i8); -impl_for_integer!(i16); -impl_for_integer!(i32); -impl_for_integer!(i64); -impl_for_integer!(i128); -impl_for_integer!(u16); -impl_for_integer!(u32); -impl_for_integer!(u64); -impl_for_integer!(u128); - -// Note NaNs have a portability issue. Specifically, signalling NaNs on MIPS are quiet NaNs on x86, -// and vice-versa. We disallow NaNs to avoid this issue. -macro_rules! impl_for_float { - ($type: ident, $int_type: ident) => { - impl BorshDeserialize for $type { - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - if buf.len() < size_of::<$type>() { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); - } - let res = $type::from_bits($int_type::from_le_bytes( - buf[..size_of::<$int_type>()].try_into().unwrap(), - )); - *buf = &buf[size_of::<$int_type>()..]; - if res.is_nan() { - return Err(Error::new( - ErrorKind::InvalidInput, - "For portability reasons we do not allow to deserialize NaNs.", - )); - } - Ok(res) - } - } - }; -} - -impl_for_float!(f32, u32); -impl_for_float!(f64, u64); - -impl BorshDeserialize for bool { - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - if buf.is_empty() { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); - } - let b = buf[0]; - *buf = &buf[1..]; - if b == 0 { - Ok(false) - } else if b == 1 { - Ok(true) - } else { - let msg = format!("Invalid bool representation: {}", b); - - Err(Error::new( - ErrorKind::InvalidInput, - msg, - )) - } - } -} - - - -impl BorshDeserialize for Option -where - T: BorshDeserialize, -{ - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - if buf.is_empty() { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); - } - let flag = buf[0]; - *buf = &buf[1..]; - if flag == 0 { - Ok(None) - } else if flag == 1 { - Ok(Some(T::deserialize(buf)?)) - } else { - let msg = format!( - "Invalid Option representation: {}. The first byte must be 0 or 1", - flag - ); - - Err(Error::new( - ErrorKind::InvalidInput, - msg, - )) - } - } -} - -impl BorshDeserialize for core::result::Result -where - T: BorshDeserialize, - E: BorshDeserialize, -{ - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - if buf.is_empty() { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); - } - let flag = buf[0]; - *buf = &buf[1..]; - if flag == 0 { - Ok(Err(E::deserialize(buf)?)) - } else if flag == 1 { - Ok(Ok(T::deserialize(buf)?)) - } else { - let msg = format!( - "Invalid Result representation: {}. The first byte must be 0 or 1", - flag - ); - - Err(Error::new( - ErrorKind::InvalidInput, - msg, - )) - } - } -} - -impl BorshDeserialize for String { - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - String::from_utf8(Vec::::deserialize(buf)?) - .map_err(|err| { - let msg = err.to_string(); - Error::new(ErrorKind::InvalidData, msg) - }) - } -} - -impl BorshDeserialize for Vec -where - T: BorshDeserialize, -{ - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - let len = u32::deserialize(buf)?; - if len == 0 { - Ok(Vec::new()) - } else if T::is_u8() && size_of::() == size_of::() { - let len = len.try_into().map_err(|_| ErrorKind::InvalidInput)?; - if buf.len() < len { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); - } - let result = buf[..len].to_vec(); - *buf = &buf[len..]; - // See comment from https://doc.rust-lang.org/std/mem/fn.transmute.html - // The no-copy, unsafe way, still using transmute, but not UB. - // This is equivalent to the original, but safer, and reuses the - // same `Vec` internals. Therefore, the new inner type must have the - // exact same size, and the same alignment, as the old type. - // - // The size of the memory should match because `size_of::() == size_of::()`. - // - // `T::is_u8()` is a workaround for not being able to implement `Vec` separately. - let result = unsafe { - // Ensure the original vector is not dropped. - let mut v_clone = core::mem::ManuallyDrop::new(result); - Vec::from_raw_parts( - v_clone.as_mut_ptr() as *mut T, - v_clone.len(), - v_clone.capacity(), - ) - }; - Ok(result) - } else if size_of::() == 0 { - let mut result = Vec::new(); - result.push(T::deserialize(buf)?); - - let p = result.as_mut_ptr(); - unsafe { - forget(result); - let len = len.try_into().map_err(|_| ErrorKind::InvalidInput)?; - let result = Vec::from_raw_parts(p, len, len); - Ok(result) - } - } else { - // TODO(16): return capacity allocation when we can safely do that. - let mut result = Vec::with_capacity(hint::cautious::(len)); - for _ in 0..len { - result.push(T::deserialize(buf)?); - } - Ok(result) - } - } -} - -impl BorshDeserialize for Cow<'_, T> -where - T: ToOwned + ?Sized, - T::Owned: BorshDeserialize, -{ - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - Ok(Cow::Owned(BorshDeserialize::deserialize(buf)?)) - } -} - - -impl BorshDeserialize for HashSet -where - T: BorshDeserialize + Eq + Hash, -{ - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - let vec = >::deserialize(buf)?; - Ok(vec.into_iter().collect::>()) - } -} - - -impl BorshDeserialize for HashMap -where - K: BorshDeserialize + Eq + Hash, - V: BorshDeserialize, -{ - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - let len = u32::deserialize(buf)?; - // TODO(16): return capacity allocation when we can safely do that. - let mut result = HashMap::new(); - for _ in 0..len { - let key = K::deserialize(buf)?; - let value = V::deserialize(buf)?; - result.insert(key, value); - } - Ok(result) - } -} - - -impl BorshDeserialize for BTreeMap -where - K: BorshDeserialize + Ord + core::hash::Hash, - V: BorshDeserialize, -{ - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - let len = u32::deserialize(buf)?; - let mut result = BTreeMap::new(); - for _ in 0..len { - let key = K::deserialize(buf)?; - let value = V::deserialize(buf)?; - result.insert(key, value); - } - Ok(result) - } -} - -#[cfg(feature = "std")] -impl BorshDeserialize for std::net::SocketAddr { - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - let kind = u8::deserialize(buf)?; - match kind { - 0 => std::net::SocketAddrV4::deserialize(buf).map(std::net::SocketAddr::V4), - 1 => std::net::SocketAddrV6::deserialize(buf).map(std::net::SocketAddr::V6), - value => Err(Error::new( - ErrorKind::InvalidInput, - format!("Invalid SocketAddr variant: {}", value), - )), - } - } -} - -#[cfg(feature = "std")] -impl BorshDeserialize for std::net::SocketAddrV4 { - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - let ip = std::net::Ipv4Addr::deserialize(buf)?; - let port = u16::deserialize(buf)?; - Ok(std::net::SocketAddrV4::new(ip, port)) - } -} - -#[cfg(feature = "std")] -impl BorshDeserialize for std::net::SocketAddrV6 { - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - let ip = std::net::Ipv6Addr::deserialize(buf)?; - let port = u16::deserialize(buf)?; - Ok(std::net::SocketAddrV6::new(ip, port, 0, 0)) - } -} - -#[cfg(feature = "std")] -impl BorshDeserialize for std::net::Ipv4Addr { - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - if buf.len() < 4 { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); - } - let bytes: [u8; 4] = buf[..4].try_into().unwrap(); - let res = std::net::Ipv4Addr::from(bytes); - *buf = &buf[4..]; - Ok(res) - } -} - -#[cfg(feature = "std")] -impl BorshDeserialize for std::net::Ipv6Addr { - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - if buf.len() < 16 { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); - } - let bytes: [u8; 16] = buf[..16].try_into().unwrap(); - let res = std::net::Ipv6Addr::from(bytes); - *buf = &buf[16..]; - Ok(res) - } -} - -impl BorshDeserialize for Box -where - U: Into> + Borrow, - T: ToOwned + ?Sized, - T::Owned: BorshDeserialize, -{ - fn deserialize(buf: &mut &[u8]) -> Result { - Ok(T::Owned::deserialize(buf)?.into()) - } -} - -macro_rules! impl_arrays { - ($($len:expr)+) => { - $( - impl BorshDeserialize for [T; $len] - where - T: BorshDeserialize + Default + Copy - { - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - let mut result = [T::default(); $len]; - if T::is_u8() && size_of::() == size_of::() { - if buf.len() < $len { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); - } - // The size of the memory should match because `size_of::() == size_of::()`. - // `T::is_u8()` is a workaround for not being able to implement `[u8; *]` separately. - result.copy_from_slice(unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const T, $len) }); - *buf = &buf[$len..]; - } else { - for i in 0..$len { - result[i] = T::deserialize(buf)?; - } - } - Ok(result) - } - } - )+ - }; -} - -impl_arrays!(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 64 65 128 256 512 1024 2048); - -impl BorshDeserialize for [T; 0] -where - T: BorshDeserialize + Default + Copy, -{ - #[inline] - fn deserialize(_buf: &mut &[u8]) -> Result { - Ok([T::default(); 0]) - } -} - -impl BorshDeserialize for () { - fn deserialize(_buf: &mut &[u8]) -> Result { - Ok(()) - } -} - -macro_rules! impl_tuple { - ($($name:ident)+) => { - impl<$($name),+> BorshDeserialize for ($($name),+) - where $($name: BorshDeserialize,)+ - { - #[inline] - fn deserialize(buf: &mut &[u8]) -> Result { - - Ok(($($name::deserialize(buf)?,)+)) - } - } - }; -} - -impl_tuple!(T0 T1); -impl_tuple!(T0 T1 T2); -impl_tuple!(T0 T1 T2 T3); -impl_tuple!(T0 T1 T2 T3 T4); -impl_tuple!(T0 T1 T2 T3 T4 T5); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17 T18); -impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17 T18 T19); diff --git a/borsh-rs/borsh/src/generate_schema_schema.rs b/borsh-rs/borsh/src/generate_schema_schema.rs deleted file mode 100644 index f93bdb327..000000000 --- a/borsh-rs/borsh/src/generate_schema_schema.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Generate `BorshSchemaCointainer` for `BorshSchemaContainer` and save it into a file. -use borsh::schema::BorshSchema; -use borsh::BorshSerialize; -use std::fs::File; -use std::io::Write; - -fn main() { - let container = borsh::schema::BorshSchemaContainer::schema_container(); - println!("{:?}", container); - let data = container - .try_to_vec() - .expect("Failed to serialize BorshSchemaContainer"); - let mut file = File::create("schema_schema.dat").expect("Failed to create file"); - file.write_all(&data).expect("Failed to write file"); -} diff --git a/borsh-rs/borsh/src/lib.rs b/borsh-rs/borsh/src/lib.rs deleted file mode 100644 index 38916f82c..000000000 --- a/borsh-rs/borsh/src/lib.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(not(feature = "std"))] -extern crate alloc; - -pub use borsh_derive::{BorshDeserialize, BorshSchema, BorshSerialize}; - -pub mod de; -pub mod schema; -pub mod schema_helpers; -pub mod ser; - - -pub use de::BorshDeserialize; -pub use schema::BorshSchema; -pub use schema_helpers::{try_from_slice_with_schema, try_to_vec_with_schema}; -pub use ser::BorshSerialize; - -/// A facade around all the types we need from the `std`, `core`, and `alloc` -/// crates. This avoids elaborate import wrangling having to happen in every -/// module. -#[cfg(feature = "std")] -pub mod maybestd { - pub use std::{ - borrow, string, vec, format, boxed, rc, sync, collections, io - }; -} - -#[cfg(not(feature = "std"))] -mod nostd_io; - -#[cfg(not(feature = "std"))] -pub mod maybestd { - pub use alloc::{ - borrow, string, vec, format, boxed, rc, sync, - }; - - pub mod collections { - pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; - pub use hashbrown::*; - } - - pub mod io { - pub use super::super::nostd_io::*; - } - - pub use hashbrown::{HashMap, HashSet}; - - pub mod hash_map { - pub use hashbrown::hash_map::Entry; - } -} diff --git a/borsh-rs/borsh/src/nostd_io.rs b/borsh-rs/borsh/src/nostd_io.rs deleted file mode 100644 index 16eb425e8..000000000 --- a/borsh-rs/borsh/src/nostd_io.rs +++ /dev/null @@ -1,691 +0,0 @@ -//! Taken from https://github.com/bbqsrc/bare-io (with adjustments) - -use core::{convert::From, fmt, result}; -use crate::maybestd::string::String; - -/// A specialized [`Result`] type for I/O operations. -/// -/// This type is broadly used across [`std::io`] for any operation which may -/// produce an error. -/// -/// This typedef is generally used to avoid writing out [`io::Error`] directly and -/// is otherwise a direct mapping to [`Result`]. -/// -/// While usual Rust style is to import types directly, aliases of [`Result`] -/// often are not, to make it easier to distinguish between them. [`Result`] is -/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias -/// will generally use `io::Result` instead of shadowing the [prelude]'s import -/// of [`std::result::Result`][`Result`]. -/// -/// [`std::io`]: crate::io -/// [`io::Error`]: Error -/// [`Result`]: crate::result::Result -/// [prelude]: crate::prelude -/// -/// # Examples -/// -/// A convenience function that bubbles an `io::Result` to its caller: -/// -/// ``` -/// use std::io; -/// -/// fn get_string() -> io::Result { -/// let mut buffer = String::new(); -/// -/// io::stdin().read_line(&mut buffer)?; -/// -/// Ok(buffer) -/// } -/// ``` -pub type Result = result::Result; - -/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and -/// associated traits. -/// -/// Errors mostly originate from the underlying OS, but custom instances of -/// `Error` can be created with crafted error messages and a particular value of -/// [`ErrorKind`]. -/// -/// [`Read`]: crate::io::Read -/// [`Write`]: crate::io::Write -/// [`Seek`]: crate::io::Seek -pub struct Error { - repr: Repr, -} - -impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.repr, f) - } -} - -enum Repr { - Simple(ErrorKind), - Custom(Custom), -} - -#[derive(Debug)] -struct Custom { - kind: ErrorKind, - error: String, -} - -/// A list specifying general categories of I/O error. -/// -/// This list is intended to grow over time and it is not recommended to -/// exhaustively match against it. -/// -/// It is used with the [`io::Error`] type. -/// -/// [`io::Error`]: Error -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -// #[allow(deprecated)] -#[non_exhaustive] -pub enum ErrorKind { - /// An entity was not found, often a file. - NotFound, - /// The operation lacked the necessary privileges to complete. - PermissionDenied, - /// The connection was refused by the remote server. - ConnectionRefused, - /// The connection was reset by the remote server. - ConnectionReset, - /// The connection was aborted (terminated) by the remote server. - ConnectionAborted, - /// The network operation failed because it was not connected yet. - NotConnected, - /// A socket address could not be bound because the address is already in - /// use elsewhere. - AddrInUse, - /// A nonexistent interface was requested or the requested address was not - /// local. - AddrNotAvailable, - /// The operation failed because a pipe was closed. - BrokenPipe, - /// An entity already exists, often a file. - AlreadyExists, - /// The operation needs to block to complete, but the blocking operation was - /// requested to not occur. - WouldBlock, - /// A parameter was incorrect. - InvalidInput, - /// Data not valid for the operation were encountered. - /// - /// Unlike [`InvalidInput`], this typically means that the operation - /// parameters were valid, however the error was caused by malformed - /// input data. - /// - /// For example, a function that reads a file into a string will error with - /// `InvalidData` if the file's contents are not valid UTF-8. - /// - /// [`InvalidInput`]: ErrorKind::InvalidInput - InvalidData, - /// The I/O operation's timeout expired, causing it to be canceled. - TimedOut, - /// An error returned when an operation could not be completed because a - /// call to [`write`] returned [`Ok(0)`]. - /// - /// This typically means that an operation could only succeed if it wrote a - /// particular number of bytes but only a smaller number of bytes could be - /// written. - /// - /// [`write`]: crate::io::Write::write - /// [`Ok(0)`]: Ok - WriteZero, - /// This operation was interrupted. - /// - /// Interrupted operations can typically be retried. - Interrupted, - /// Any I/O error not part of this list. - /// - /// Errors that are `Other` now may move to a different or a new - /// [`ErrorKind`] variant in the future. It is not recommended to match - /// an error against `Other` and to expect any additional characteristics, - /// e.g., a specific [`Error::raw_os_error`] return value. - Other, - - /// An error returned when an operation could not be completed because an - /// "end of file" was reached prematurely. - /// - /// This typically means that an operation could only succeed if it read a - /// particular number of bytes but only a smaller number of bytes could be - /// read. - UnexpectedEof, -} - -impl ErrorKind { - pub(crate) fn as_str(&self) -> &'static str { - match *self { - ErrorKind::NotFound => "entity not found", - ErrorKind::PermissionDenied => "permission denied", - ErrorKind::ConnectionRefused => "connection refused", - ErrorKind::ConnectionReset => "connection reset", - ErrorKind::ConnectionAborted => "connection aborted", - ErrorKind::NotConnected => "not connected", - ErrorKind::AddrInUse => "address in use", - ErrorKind::AddrNotAvailable => "address not available", - ErrorKind::BrokenPipe => "broken pipe", - ErrorKind::AlreadyExists => "entity already exists", - ErrorKind::WouldBlock => "operation would block", - ErrorKind::InvalidInput => "invalid input parameter", - ErrorKind::InvalidData => "invalid data", - ErrorKind::TimedOut => "timed out", - ErrorKind::WriteZero => "write zero", - ErrorKind::Interrupted => "operation interrupted", - ErrorKind::Other => "other os error", - ErrorKind::UnexpectedEof => "unexpected end of file", - } - } -} - -/// Intended for use for errors not exposed to the user, where allocating onto -/// the heap (for normal construction via Error::new) is too costly. -impl From for Error { - /// Converts an [`ErrorKind`] into an [`Error`]. - /// - /// This conversion allocates a new error with a simple representation of error kind. - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// let not_found = ErrorKind::NotFound; - /// let error = Error::from(not_found); - /// assert_eq!("entity not found", format!("{}", error)); - /// ``` - #[inline] - fn from(kind: ErrorKind) -> Error { - Error { - repr: Repr::Simple(kind), - } - } -} - -impl Error { - /// Creates a new I/O error from a known kind of error as well as an - /// arbitrary error payload. - /// - /// This function is used to generically create I/O errors which do not - /// originate from the OS itself. The `error` argument is an arbitrary - /// payload which will be contained in this [`Error`]. - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// // errors can be created from strings - /// let custom_error = Error::new(ErrorKind::Other, "oh no!"); - /// - /// // errors can also be created from other errors - /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); - /// ``` - pub fn new>(kind: ErrorKind, error: T) -> Error { - Self::_new(kind, error.into()) - } - - fn _new(kind: ErrorKind, error: String) -> Error { - Error { - repr: Repr::Custom(Custom { kind, error }), - } - } - - /// Returns a reference to the inner error wrapped by this error (if any). - /// - /// If this [`Error`] was constructed via [`new`] then this function will - /// return [`Some`], otherwise it will return [`None`]. - /// - /// [`new`]: Error::new - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// fn print_error(err: &Error) { - /// if let Some(inner_err) = err.get_ref() { - /// println!("Inner error: {:?}", inner_err); - /// } else { - /// println!("No inner error"); - /// } - /// } - /// - /// fn main() { - /// // Will print "No inner error". - /// print_error(&Error::last_os_error()); - /// // Will print "Inner error: ...". - /// print_error(&Error::new(ErrorKind::Other, "oh no!")); - /// } - /// ``` - pub fn get_ref(&self) -> Option<&str> { - match self.repr { - Repr::Simple(..) => None, - Repr::Custom(ref c) => Some(&c.error), - } - } - - /// Consumes the `Error`, returning its inner error (if any). - /// - /// If this [`Error`] was constructed via [`new`] then this function will - /// return [`Some`], otherwise it will return [`None`]. - /// - /// [`new`]: Error::new - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// fn print_error(err: Error) { - /// if let Some(inner_err) = err.into_inner() { - /// println!("Inner error: {}", inner_err); - /// } else { - /// println!("No inner error"); - /// } - /// } - /// - /// fn main() { - /// // Will print "No inner error". - /// print_error(Error::last_os_error()); - /// // Will print "Inner error: ...". - /// print_error(Error::new(ErrorKind::Other, "oh no!")); - /// } - /// ``` - pub fn into_inner(self) -> Option { - match self.repr { - Repr::Simple(..) => None, - Repr::Custom(c) => Some(c.error), - } - } - - /// Returns the corresponding [`ErrorKind`] for this error. - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// fn print_error(err: Error) { - /// println!("{:?}", err.kind()); - /// } - /// - /// fn main() { - /// // Will print "Other". - /// print_error(Error::last_os_error()); - /// // Will print "AddrInUse". - /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!")); - /// } - /// ``` - pub fn kind(&self) -> ErrorKind { - match self.repr { - Repr::Custom(ref c) => c.kind, - Repr::Simple(kind) => kind, - } - } -} - -impl fmt::Debug for Repr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt), - Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(), - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.repr { - Repr::Custom(ref c) => c.error.fmt(fmt), - Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()), - } - } -} - -fn _assert_error_is_sync_send() { - fn _is_sync_send() {} - _is_sync_send::(); -} - - -/// A trait for objects which are byte-oriented sinks. -/// -/// Implementors of the `Write` trait are sometimes called 'writers'. -/// -/// Writers are defined by two required methods, [`write`] and [`flush`]: -/// -/// * The [`write`] method will attempt to write some data into the object, -/// returning how many bytes were successfully written. -/// -/// * The [`flush`] method is useful for adaptors and explicit buffers -/// themselves for ensuring that all buffered data has been pushed out to the -/// 'true sink'. -/// -/// Writers are intended to be composable with one another. Many implementors -/// throughout [`std::io`] take and provide types which implement the `Write` -/// trait. -/// -/// [`write`]: Write::write -/// [`flush`]: Write::flush -/// [`std::io`]: self -/// -/// # Examples -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::fs::File; -/// -/// fn main() -> std::io::Result<()> { -/// let data = b"some bytes"; -/// -/// let mut pos = 0; -/// let mut buffer = File::create("foo.txt")?; -/// -/// while pos < data.len() { -/// let bytes_written = buffer.write(&data[pos..])?; -/// pos += bytes_written; -/// } -/// Ok(()) -/// } -/// ``` -/// -/// The trait also provides convenience methods like [`write_all`], which calls -/// `write` in a loop until its entire input has been written. -/// -/// [`write_all`]: Write::write_all -pub trait Write { - /// Write a buffer into this writer, returning how many bytes were written. - /// - /// This function will attempt to write the entire contents of `buf`, but - /// the entire write may not succeed, or the write may also generate an - /// error. A call to `write` represents *at most one* attempt to write to - /// any wrapped object. - /// - /// Calls to `write` are not guaranteed to block waiting for data to be - /// written, and a write which would otherwise block can be indicated through - /// an [`Err`] variant. - /// - /// If the return value is [`Ok(n)`] then it must be guaranteed that - /// `n <= buf.len()`. A return value of `0` typically means that the - /// underlying object is no longer able to accept bytes and will likely not - /// be able to in the future as well, or that the buffer provided is empty. - /// - /// # Errors - /// - /// Each call to `write` may generate an I/O error indicating that the - /// operation could not be completed. If an error is returned then no bytes - /// in the buffer were written to this writer. - /// - /// It is **not** considered an error if the entire buffer could not be - /// written to this writer. - /// - /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the - /// write operation should be retried if there is nothing else to do. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// // Writes some prefix of the byte string, not necessarily all of it. - /// buffer.write(b"some bytes")?; - /// Ok(()) - /// } - /// ``` - /// - /// [`Ok(n)`]: Ok - fn write(&mut self, buf: &[u8]) -> Result; - - /// Flush this output stream, ensuring that all intermediately buffered - /// contents reach their destination. - /// - /// # Errors - /// - /// It is considered an error if not all bytes could be written due to - /// I/O errors or EOF being reached. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::io::BufWriter; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = BufWriter::new(File::create("foo.txt")?); - /// - /// buffer.write_all(b"some bytes")?; - /// buffer.flush()?; - /// Ok(()) - /// } - /// ``` - fn flush(&mut self) -> Result<()>; - - /// Attempts to write an entire buffer into this writer. - /// - /// This method will continuously call [`write`] until there is no more data - /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is - /// returned. This method will not return until the entire buffer has been - /// successfully written or such an error occurs. The first error that is - /// not of [`ErrorKind::Interrupted`] kind generated from this method will be - /// returned. - /// - /// If the buffer contains no data, this will never call [`write`]. - /// - /// # Errors - /// - /// This function will return the first error of - /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns. - /// - /// [`write`]: Write::write - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// buffer.write_all(b"some bytes")?; - /// Ok(()) - /// } - /// ``` - fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { - while !buf.is_empty() { - match self.write(buf) { - Ok(0) => { - return Err(Error::new( - ErrorKind::WriteZero, - "failed to write whole buffer", - )); - } - Ok(n) => buf = &buf[n..], - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(()) - } - /// Writes a formatted string into this writer, returning any error - /// encountered. - /// - /// This method is primarily used to interface with the - /// [`format_args!()`] macro, but it is rare that this should - /// explicitly be called. The [`write!()`] macro should be favored to - /// invoke this method instead. - /// - /// This function internally uses the [`write_all`] method on - /// this trait and hence will continuously write data so long as no errors - /// are received. This also means that partial writes are not indicated in - /// this signature. - /// - /// [`write_all`]: Write::write_all - /// - /// # Errors - /// - /// This function will return any I/O error reported while formatting. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// // this call - /// write!(buffer, "{:.*}", 2, 1.234567)?; - /// // turns into this: - /// buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?; - /// Ok(()) - /// } - /// ``` - fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> { - // Create a shim which translates a Write to a fmt::Write and saves - // off I/O errors. instead of discarding them - struct Adaptor<'a, T: ?Sized + 'a> { - inner: &'a mut T, - error: Result<()>, - } - - impl fmt::Write for Adaptor<'_, T> { - fn write_str(&mut self, s: &str) -> fmt::Result { - match self.inner.write_all(s.as_bytes()) { - Ok(()) => Ok(()), - Err(e) => { - self.error = Err(e); - Err(fmt::Error) - } - } - } - } - - let mut output = Adaptor { - inner: self, - error: Ok(()), - }; - match fmt::write(&mut output, fmt) { - Ok(()) => Ok(()), - Err(..) => { - // check if the error came from the underlying `Write` or not - if output.error.is_err() { - output.error - } else { - Err(Error::new(ErrorKind::Other, "formatter error")) - } - } - } - } - - /// Creates a "by reference" adaptor for this instance of `Write`. - /// - /// The returned adaptor also implements `Write` and will simply borrow this - /// current writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::Write; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// let reference = buffer.by_ref(); - /// - /// // we can use reference just like our original buffer - /// reference.write_all(b"some bytes")?; - /// Ok(()) - /// } - /// ``` - fn by_ref(&mut self) -> &mut Self - where - Self: Sized, - { - self - } -} - -impl Write for &mut W { - #[inline] - fn write(&mut self, buf: &[u8]) -> Result { - (**self).write(buf) - } - - #[inline] - fn flush(&mut self) -> Result<()> { - (**self).flush() - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> Result<()> { - (**self).write_all(buf) - } - - #[inline] - fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> { - (**self).write_fmt(fmt) - } -} - -/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting -/// its data. -/// -/// Note that writing updates the slice to point to the yet unwritten part. -/// The slice will be empty when it has been completely overwritten. -impl Write for &mut [u8] { - #[inline] - fn write(&mut self, data: &[u8]) -> Result { - let amt = core::cmp::min(data.len(), self.len()); - let (a, b) = core::mem::replace(self, &mut []).split_at_mut(amt); - a.copy_from_slice(&data[..amt]); - *self = b; - Ok(amt) - } - - #[inline] - fn write_all(&mut self, data: &[u8]) -> Result<()> { - if self.write(data)? == data.len() { - Ok(()) - } else { - Err(Error::new( - ErrorKind::WriteZero, - "failed to write whole buffer", - )) - } - } - - #[inline] - fn flush(&mut self) -> Result<()> { - Ok(()) - } -} - -/// Write is implemented for `Vec` by appending to the vector. -/// The vector will grow as needed. -impl Write for alloc::vec::Vec { - #[inline] - fn write(&mut self, buf: &[u8]) -> Result { - self.extend_from_slice(buf); - Ok(buf.len()) - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> Result<()> { - self.extend_from_slice(buf); - Ok(()) - } - - #[inline] - fn flush(&mut self) -> Result<()> { - Ok(()) - } -} diff --git a/borsh-rs/borsh/src/schema.rs b/borsh-rs/borsh/src/schema.rs deleted file mode 100644 index 56665df92..000000000 --- a/borsh-rs/borsh/src/schema.rs +++ /dev/null @@ -1,462 +0,0 @@ -//! Since Borsh is not a self-descriptive format we have a way to describe types serialized with Borsh so that -//! we can deserialize serialized blobs without having Rust types available. Additionally, this can be used to -//! serialize content provided in a different format, e.g. JSON object `{"user": "alice", "message": "Message"}` -//! can be serialized by JS code into Borsh format such that it can be deserialized into `struct UserMessage {user: String, message: String}` -//! on Rust side. -//! -//! The important components are: `BorshSchema` trait, `Definition` and `Declaration` types, and `BorshSchemaContainer` struct. -//! * `BorshSchema` trait allows any type that implements it to be self-descriptive, i.e. generate it's own schema; -//! * `Declaration` is used to describe the type identifier, e.g. `HashMap`; -//! * `Definition` is used to describe the structure of the type; -//! * `BorshSchemaContainer` is used to store all declarations and defintions that are needed to work with a single type. - -#![allow(dead_code)] // Unclear why rust check complains on fields of `Definition` variants. -use crate as borsh; // For `#[derive(BorshSerialize, BorshDeserialize)]`. -use crate::{BorshDeserialize, BorshSchema as BorshSchemaMacro, BorshSerialize}; -use crate::maybestd::{ - collections::{hash_map::Entry, HashMap}, - string::{ToString, String}, - vec::Vec, vec, - boxed::Box, - format -}; - -/// The type that we use to represent the declaration of the Borsh type. -pub type Declaration = String; -/// The type that we use for the name of the variant. -pub type VariantName = String; -/// The name of the field in the struct (can be used to convert JSON to Borsh using the schema). -pub type FieldName = String; -/// The type that we use to represent the definition of the Borsh type. -#[derive(PartialEq, Debug, BorshSerialize, BorshDeserialize, BorshSchemaMacro)] -pub enum Definition { - /// A fixed-size array with the length known at the compile time and the same-type elements. - Array { length: u32, elements: Declaration }, - /// A sequence of elements of length known at the run time and the same-type elements. - Sequence { elements: Declaration }, - /// A fixed-size tuple with the length known at the compile time and the elements of different - /// types. - Tuple { elements: Vec }, - /// A tagged union, a.k.a enum. Tagged-unions have variants with associated structures. - Enum { - variants: Vec<(VariantName, Declaration)>, - }, - /// A structure, structurally similar to a tuple. - Struct { fields: Fields }, -} - -/// The collection representing the fields of a struct. -#[derive(PartialEq, Debug, BorshSerialize, BorshDeserialize, BorshSchemaMacro)] -pub enum Fields { - /// The struct with named fields. - NamedFields(Vec<(FieldName, Declaration)>), - /// The struct with unnamed fields, structurally identical to a tuple. - UnnamedFields(Vec), - /// The struct with no fields. - Empty, -} - -/// All schema information needed to deserialize a single type. -#[derive(PartialEq, Debug, BorshSerialize, BorshDeserialize, BorshSchemaMacro)] -pub struct BorshSchemaContainer { - /// Declaration of the type. - pub declaration: Declaration, - /// All definitions needed to deserialize the given type. - pub definitions: HashMap, -} - -/// The declaration and the definition of the type that can be used to (de)serialize Borsh without -/// the Rust type that produced it. -pub trait BorshSchema { - /// Recursively, using DFS, add type definitions required for this type. For primitive types - /// this is an empty map. Type definition explains how to serialize/deserialize a type. - fn add_definitions_recursively(definitions: &mut HashMap); - - /// Helper method to add a single type definition to the map. - fn add_definition( - declaration: Declaration, - definition: Definition, - definitions: &mut HashMap, - ) { - match definitions.entry(declaration) { - Entry::Occupied(occ) => { - let existing_def = occ.get(); - assert_eq!(existing_def, &definition, "Redefining type schema for the same type name. Types with the same names are not supported."); - } - Entry::Vacant(vac) => { - vac.insert(definition); - } - } - } - /// Get the name of the type without brackets. - fn declaration() -> Declaration; - - fn schema_container() -> BorshSchemaContainer { - let mut definitions = HashMap::new(); - Self::add_definitions_recursively(&mut definitions); - BorshSchemaContainer { - declaration: Self::declaration(), - definitions, - } - } -} - -impl BorshSchema for Box -where - T: BorshSchema, -{ - fn add_definitions_recursively(definitions: &mut HashMap) { - T::add_definitions_recursively(definitions); - } - - fn declaration() -> Declaration { - T::declaration() - } -} - -impl BorshSchema for () { - fn add_definitions_recursively(_definitions: &mut HashMap) {} - - fn declaration() -> Declaration { - "nil".to_string() - } -} - -macro_rules! impl_for_renamed_primitives { - ($($type: ident : $name: ident)+) => { - $( - impl BorshSchema for $type { - fn add_definitions_recursively(_definitions: &mut HashMap) {} - fn declaration() -> Declaration { - stringify!($name).to_string() - } - } - )+ - }; -} - -macro_rules! impl_for_primitives { - ($($type: ident)+) => { - impl_for_renamed_primitives!{$($type : $type)+} - }; -} - -impl_for_primitives!(bool char f32 f64 i8 i16 i32 i64 i128 u8 u16 u32 u64 u128); -impl_for_renamed_primitives!(String: string); - -macro_rules! impl_arrays { - ($($len:expr)+) => { - $( - impl BorshSchema for [T; $len] - where - T: BorshSchema, - { - fn add_definitions_recursively(definitions: &mut HashMap) { - let definition = Definition::Array { length: $len, elements: T::declaration() }; - Self::add_definition(Self::declaration(), definition, definitions); - T::add_definitions_recursively(definitions); - } - fn declaration() -> Declaration { - format!(r#"Array<{}, {}>"#, T::declaration(), $len) - } - } - )+ - }; -} - -impl_arrays!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 32 64 65); - -impl BorshSchema for Option -where - T: BorshSchema, -{ - fn add_definitions_recursively(definitions: &mut HashMap) { - let definition = Definition::Enum { - variants: vec![ - ("None".to_string(), <()>::declaration()), - ("Some".to_string(), T::declaration()), - ], - }; - Self::add_definition(Self::declaration(), definition, definitions); - T::add_definitions_recursively(definitions); - } - - fn declaration() -> Declaration { - format!(r#"Option<{}>"#, T::declaration()) - } -} - -impl BorshSchema for core::result::Result -where - T: BorshSchema, - E: BorshSchema, -{ - fn add_definitions_recursively(definitions: &mut HashMap) { - let definition = Definition::Enum { - variants: vec![ - ("Ok".to_string(), T::declaration()), - ("Err".to_string(), E::declaration()), - ], - }; - Self::add_definition(Self::declaration(), definition, definitions); - T::add_definitions_recursively(definitions); - } - - fn declaration() -> Declaration { - format!(r#"Result<{}, {}>"#, T::declaration(), E::declaration()) - } -} - -impl BorshSchema for Vec -where - T: BorshSchema, -{ - fn add_definitions_recursively(definitions: &mut HashMap) { - let definition = Definition::Sequence { - elements: T::declaration(), - }; - Self::add_definition(Self::declaration(), definition, definitions); - T::add_definitions_recursively(definitions); - } - - fn declaration() -> Declaration { - format!(r#"Vec<{}>"#, T::declaration()) - } -} - -impl BorshSchema for HashMap -where - K: BorshSchema, - V: BorshSchema, -{ - fn add_definitions_recursively(definitions: &mut HashMap) { - let definition = Definition::Sequence { - elements: <(K, V)>::declaration(), - }; - Self::add_definition(Self::declaration(), definition, definitions); - <(K, V)>::add_definitions_recursively(definitions); - } - - fn declaration() -> Declaration { - format!(r#"HashMap<{}, {}>"#, K::declaration(), V::declaration()) - } -} - -macro_rules! impl_tuple { - ($($name:ident),+) => { - impl<$($name),+> BorshSchema for ($($name),+) - where - $($name: BorshSchema),+ - { - fn add_definitions_recursively(definitions: &mut HashMap) { - let mut elements = vec![]; - $( - elements.push($name::declaration()); - )+ - - let definition = Definition::Tuple { elements }; - Self::add_definition(Self::declaration(), definition, definitions); - $( - $name::add_definitions_recursively(definitions); - )+ - } - - fn declaration() -> Declaration { - let params = vec![$($name::declaration()),+]; - format!(r#"Tuple<{}>"#, params.join(", ")) - } - } - }; -} - -impl_tuple!(T0, T1); -impl_tuple!(T0, T1, T2); -impl_tuple!(T0, T1, T2, T3); -impl_tuple!(T0, T1, T2, T3, T4); -impl_tuple!(T0, T1, T2, T3, T4, T5); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18); -impl_tuple!( - T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19 -); -impl_tuple!( - T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20 -); - -#[cfg(test)] -mod tests { - use super::*; - use crate::maybestd::collections::HashMap; - - macro_rules! map( - () => { HashMap::new() }; - { $($key:expr => $value:expr),+ } => { - { - let mut m = HashMap::new(); - $( - m.insert($key.to_string(), $value); - )+ - m - } - }; - ); - - #[test] - fn simple_option() { - let actual_name = Option::::declaration(); - let mut actual_defs = map!(); - Option::::add_definitions_recursively(&mut actual_defs); - assert_eq!("Option", actual_name); - assert_eq!( - map! {"Option" => - Definition::Enum{ variants: vec![ - ("None".to_string(), "nil".to_string()), - ("Some".to_string(), "u64".to_string()), - ]} - }, - actual_defs - ); - } - - #[test] - fn nested_option() { - let actual_name = Option::>::declaration(); - let mut actual_defs = map!(); - Option::>::add_definitions_recursively(&mut actual_defs); - assert_eq!("Option>", actual_name); - assert_eq!( - map! { - "Option" => - Definition::Enum {variants: vec![ - ("None".to_string(), "nil".to_string()), - ("Some".to_string(), "u64".to_string()), - ]}, - "Option>" => - Definition::Enum {variants: vec![ - ("None".to_string(), "nil".to_string()), - ("Some".to_string(), "Option".to_string()), - ]} - }, - actual_defs - ); - } - - #[test] - fn simple_vec() { - let actual_name = Vec::::declaration(); - let mut actual_defs = map!(); - Vec::::add_definitions_recursively(&mut actual_defs); - assert_eq!("Vec", actual_name); - assert_eq!( - map! { - "Vec" => Definition::Sequence { elements: "u64".to_string() } - }, - actual_defs - ); - } - - #[test] - fn nested_vec() { - let actual_name = Vec::>::declaration(); - let mut actual_defs = map!(); - Vec::>::add_definitions_recursively(&mut actual_defs); - assert_eq!("Vec>", actual_name); - assert_eq!( - map! { - "Vec" => Definition::Sequence { elements: "u64".to_string() }, - "Vec>" => Definition::Sequence { elements: "Vec".to_string() } - }, - actual_defs - ); - } - - #[test] - fn simple_tuple() { - let actual_name = <(u64, String)>::declaration(); - let mut actual_defs = map!(); - <(u64, String)>::add_definitions_recursively(&mut actual_defs); - assert_eq!("Tuple", actual_name); - assert_eq!( - map! { - "Tuple" => Definition::Tuple { elements: vec![ "u64".to_string(), "string".to_string()]} - }, - actual_defs - ); - } - - #[test] - fn nested_tuple() { - let actual_name = <(u64, (u8, bool), String)>::declaration(); - let mut actual_defs = map!(); - <(u64, (u8, bool), String)>::add_definitions_recursively(&mut actual_defs); - assert_eq!("Tuple, string>", actual_name); - assert_eq!( - map! { - "Tuple, string>" => Definition::Tuple { elements: vec![ - "u64".to_string(), - "Tuple".to_string(), - "string".to_string(), - ]}, - "Tuple" => Definition::Tuple { elements: vec![ "u8".to_string(), "bool".to_string()]} - }, - actual_defs - ); - } - - #[test] - fn simple_map() { - let actual_name = HashMap::::declaration(); - let mut actual_defs = map!(); - HashMap::::add_definitions_recursively(&mut actual_defs); - assert_eq!("HashMap", actual_name); - assert_eq!( - map! { - "HashMap" => Definition::Sequence { elements: "Tuple".to_string()} , - "Tuple" => Definition::Tuple { elements: vec![ "u64".to_string(), "string".to_string()]} - }, - actual_defs - ); - } - - #[test] - fn simple_array() { - let actual_name = <[u64; 32]>::declaration(); - let mut actual_defs = map!(); - <[u64; 32]>::add_definitions_recursively(&mut actual_defs); - assert_eq!("Array", actual_name); - assert_eq!( - map! {"Array" => Definition::Array { length: 32, elements: "u64".to_string()}}, - actual_defs - ); - } - - #[test] - fn nested_array() { - let actual_name = <[[[u64; 9]; 10]; 32]>::declaration(); - let mut actual_defs = map!(); - <[[[u64; 9]; 10]; 32]>::add_definitions_recursively(&mut actual_defs); - assert_eq!("Array, 10>, 32>", actual_name); - assert_eq!( - map! { - "Array" => - Definition::Array { length: 9, elements: "u64".to_string() }, - "Array, 10>" => - Definition::Array { length: 10, elements: "Array".to_string() }, - "Array, 10>, 32>" => - Definition::Array { length: 32, elements: "Array, 10>".to_string() } - }, - actual_defs - ); - } -} diff --git a/borsh-rs/borsh/src/schema_helpers.rs b/borsh-rs/borsh/src/schema_helpers.rs deleted file mode 100644 index 92435a257..000000000 --- a/borsh-rs/borsh/src/schema_helpers.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::maybestd::{ - io::{Error, ErrorKind, Result}, - vec::Vec -}; -use crate::schema::BorshSchemaContainer; -use crate::{BorshDeserialize, BorshSchema, BorshSerialize}; - -/// Deserialize this instance from a slice of bytes, but assume that at the beginning we have -/// bytes describing the schema of the type. We deserialize this schema and verify that it is -/// correct. -pub fn try_from_slice_with_schema(v: &[u8]) -> Result { - let (schema, object) = <(BorshSchemaContainer, T)>::try_from_slice(v)?; - if T::schema_container() != schema { - return Err(Error::new( - ErrorKind::InvalidData, - "Borsh schema does not match", - )); - } - Ok(object) -} - -/// Serialize object into a vector of bytes and prefix with the schema serialized as vector of -/// bytes in Borsh format. -pub fn try_to_vec_with_schema(value: &T) -> Result> { - let schema = T::schema_container(); - let mut res = schema.try_to_vec()?; - res.extend(value.try_to_vec()?); - Ok(res) -} diff --git a/borsh-rs/borsh/src/ser/mod.rs b/borsh-rs/borsh/src/ser/mod.rs deleted file mode 100644 index dfdbe5688..000000000 --- a/borsh-rs/borsh/src/ser/mod.rs +++ /dev/null @@ -1,374 +0,0 @@ -use core::convert::TryFrom; -use core::mem::size_of; - -use crate::maybestd::{ - io::{ErrorKind, Result, Write}, - collections::{HashMap, HashSet}, - borrow::{ToOwned, Cow}, - string::String, - boxed::Box, - vec::Vec -}; - -const DEFAULT_SERIALIZER_CAPACITY: usize = 1024; - -/// A data-structure that can be serialized into binary format by NBOR. -pub trait BorshSerialize { - fn serialize(&self, writer: &mut W) -> Result<()>; - - /// Serialize this instance into a vector of bytes. - fn try_to_vec(&self) -> Result> { - let mut result = Vec::with_capacity(DEFAULT_SERIALIZER_CAPACITY); - self.serialize(&mut result)?; - Ok(result) - } - - /// Whether Self is u8. - /// NOTE: `Vec` is the most common use-case for serialization and deserialization, it's - /// worth handling it as a special case to improve performance. - /// It's a workaround for specific `Vec` implementation versus generic `Vec` - /// implementation. See https://github.com/rust-lang/rfcs/pull/1210 for details. - #[inline] - fn is_u8() -> bool { - false - } -} - -impl BorshSerialize for u8 { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - writer.write_all(core::slice::from_ref(self)) - } - - #[inline] - fn is_u8() -> bool { - true - } -} - -macro_rules! impl_for_integer { - ($type: ident) => { - impl BorshSerialize for $type { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - let bytes = self.to_le_bytes(); - writer.write_all(&bytes) - } - } - }; -} - -impl_for_integer!(i8); -impl_for_integer!(i16); -impl_for_integer!(i32); -impl_for_integer!(i64); -impl_for_integer!(i128); -impl_for_integer!(u16); -impl_for_integer!(u32); -impl_for_integer!(u64); -impl_for_integer!(u128); - -// Note NaNs have a portability issue. Specifically, signalling NaNs on MIPS are quiet NaNs on x86, -// and vice-versa. We disallow NaNs to avoid this issue. -macro_rules! impl_for_float { - ($type: ident) => { - impl BorshSerialize for $type { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - assert!( - !self.is_nan(), - "For portability reasons we do not allow to serialize NaNs." - ); - writer.write_all(&self.to_bits().to_le_bytes()) - } - } - }; -} - -impl_for_float!(f32); -impl_for_float!(f64); - -impl BorshSerialize for bool { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - (if *self { 1u8 } else { 0u8 }).serialize(writer) - } -} - -impl BorshSerialize for Option -where - T: BorshSerialize, -{ - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - match self { - None => 0u8.serialize(writer), - Some(value) => { - 1u8.serialize(writer)?; - value.serialize(writer) - } - } - } -} - -impl BorshSerialize for core::result::Result -where - T: BorshSerialize, - E: BorshSerialize, -{ - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - match self { - Err(e) => { - 0u8.serialize(writer)?; - e.serialize(writer) - } - Ok(v) => { - 1u8.serialize(writer)?; - v.serialize(writer) - } - } - } -} - -impl BorshSerialize for str { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_bytes().serialize(writer) - } -} - -impl BorshSerialize for String { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_bytes().serialize(writer) - } -} - -impl BorshSerialize for [T] -where - T: BorshSerialize, -{ - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - writer.write_all( - &(u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidInput)?).to_le_bytes(), - )?; - if T::is_u8() && size_of::() == size_of::() { - // The code below uses unsafe memory representation from `&[T]` to `&[u8]`. - // The size of the memory should match because `size_of::() == size_of::()`. - // - // `T::is_u8()` is a workaround for not being able to implement `Vec` separately. - let buf = unsafe { core::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()) }; - writer.write_all(buf)?; - } else { - for item in self { - item.serialize(writer)?; - } - } - Ok(()) - } -} - -impl BorshSerialize for &T { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - (*self).serialize(writer) - } -} - -impl BorshSerialize for Cow<'_, T> -where - T: BorshSerialize + ToOwned + ?Sized, -{ - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_ref().serialize(writer) - } -} - -impl BorshSerialize for Vec -where - T: BorshSerialize, -{ - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_slice().serialize(writer) - } -} - -impl BorshSerialize for HashMap -where - K: BorshSerialize + PartialOrd, - V: BorshSerialize, -{ - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - let mut vec = self.iter().collect::>(); - vec.sort_by(|(a, _), (b, _)| a.partial_cmp(b).unwrap()); - u32::try_from(vec.len()) - .map_err(|_| ErrorKind::InvalidInput)? - .serialize(writer)?; - for (key, value) in vec { - key.serialize(writer)?; - value.serialize(writer)?; - } - Ok(()) - } -} - - -impl BorshSerialize for HashSet - where - T: BorshSerialize + PartialOrd, -{ - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - let mut vec = self.iter().collect::>(); - vec.sort_by(|a, b| a.partial_cmp(b).unwrap()); - u32::try_from(vec.len()) - .map_err(|_| ErrorKind::InvalidInput)? - .serialize(writer)?; - for item in vec { - item.serialize(writer)?; - } - Ok(()) - } -} - - -#[cfg(feature = "std")] -impl BorshSerialize for std::net::SocketAddr { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - match *self { - std::net::SocketAddr::V4(ref addr) => { - 0u8.serialize(writer)?; - addr.serialize(writer) - } - std::net::SocketAddr::V6(ref addr) => { - 1u8.serialize(writer)?; - addr.serialize(writer) - } - } - } -} - -#[cfg(feature = "std")] -impl BorshSerialize for std::net::SocketAddrV4 { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - self.ip().serialize(writer)?; - self.port().serialize(writer) - } -} - -#[cfg(feature = "std")] -impl BorshSerialize for std::net::SocketAddrV6 { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - self.ip().serialize(writer)?; - self.port().serialize(writer) - } -} - -#[cfg(feature = "std")] -impl BorshSerialize for std::net::Ipv4Addr { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - writer.write_all(&self.octets()) - } -} - -#[cfg(feature = "std")] -impl BorshSerialize for std::net::Ipv6Addr { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - writer.write_all(&self.octets()) - } -} - -impl BorshSerialize for Box { - fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_ref().serialize(writer) - } -} - -macro_rules! impl_arrays { - ($($len:expr)+) => { - $( - impl BorshSerialize for [T; $len] - where T: BorshSerialize - { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - if T::is_u8() && size_of::() == size_of::() { - // The code below uses unsafe memory representation from `&[T]` to `&[u8]`. - // The size of the memory should match because `size_of::() == size_of::()`. - // - // `T::is_u8()` is a workaround for not being able to implement `[u8; *]` separately. - let buf = unsafe { core::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()) }; - writer.write_all(buf)?; - } else { - for el in self.iter() { - el.serialize(writer)?; - } - } - Ok(()) - } - } - )+ - }; -} - -impl BorshSerialize for [T; 0] -where - T: BorshSerialize, -{ - #[inline] - fn serialize(&self, _writer: &mut W) -> Result<()> { - Ok(()) - } -} - -impl_arrays!(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 64 65 128 256 512 1024 2048); - -impl BorshSerialize for () { - fn serialize(&self, _writer: &mut W) -> Result<()> { - Ok(()) - } -} - -macro_rules! impl_tuple { - ($($idx:tt $name:ident)+) => { - impl<$($name),+> BorshSerialize for ($($name),+) - where $($name: BorshSerialize,)+ - { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - $(self.$idx.serialize(writer)?;)+ - Ok(()) - } - } - }; -} - -impl_tuple!(0 T0 1 T1); -impl_tuple!(0 T0 1 T1 2 T2); -impl_tuple!(0 T0 1 T1 2 T2 3 T3); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15 16 T16); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15 16 T16 17 T17); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15 16 T16 17 T17 18 T18); -impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15 16 T16 17 T17 18 T18 19 T19); diff --git a/borsh-rs/borsh/tests/test_arrays.rs b/borsh-rs/borsh/tests/test_arrays.rs deleted file mode 100644 index 61890b263..000000000 --- a/borsh-rs/borsh/tests/test_arrays.rs +++ /dev/null @@ -1,39 +0,0 @@ -use borsh::{BorshDeserialize, BorshSerialize}; - -macro_rules! test_array { - ($v: expr, $t: ty, $len: expr) => { - let buf = $v.try_to_vec().unwrap(); - let actual_v: [$t; $len] = - BorshDeserialize::try_from_slice(&buf).expect("failed to deserialize"); - assert_eq!($v.len(), actual_v.len()); - for i in 0..$len { - assert_eq!($v[i], actual_v[i]); - } - }; -} - -macro_rules! test_arrays { - ($test_name: ident, $el: expr, $t: ty) => { - #[test] - fn $test_name() { - test_array!([$el; 0], $t, 0); - test_array!([$el; 1], $t, 1); - test_array!([$el; 2], $t, 2); - test_array!([$el; 3], $t, 3); - test_array!([$el; 4], $t, 4); - test_array!([$el; 8], $t, 8); - test_array!([$el; 16], $t, 16); - test_array!([$el; 32], $t, 32); - test_array!([$el; 64], $t, 64); - test_array!([$el; 65], $t, 65); - } - }; -} - -test_arrays!(test_array_u8, 100u8, u8); -test_arrays!(test_array_i8, 100i8, i8); -test_arrays!(test_array_u32, 1000000000u32, u32); -test_arrays!(test_array_u64, 1000000000000000000u64, u64); -test_arrays!(test_array_u128, 1000000000000000000000000000000000000u128, u128); -test_arrays!(test_array_f32, 1000000000.0f32, f32); -test_arrays!(test_array_array_u8, [100u8; 32], [u8; 32]); diff --git a/borsh-rs/borsh/tests/test_de_errors.rs b/borsh-rs/borsh/tests/test_de_errors.rs deleted file mode 100644 index 2c4cbce38..000000000 --- a/borsh-rs/borsh/tests/test_de_errors.rs +++ /dev/null @@ -1,144 +0,0 @@ -use borsh::BorshDeserialize; - -#[derive(BorshDeserialize, Debug)] -enum A { - X, - Y, -} - -#[derive(BorshDeserialize, Debug)] -struct B { - x: u64, - y: u32, -} - -const ERROR_UNEXPECTED_LENGTH_OF_INPUT: &str = "Unexpected length of input"; - -#[test] -fn test_missing_bytes() { - let bytes = vec![1, 0]; - assert_eq!( - B::try_from_slice(&bytes).unwrap_err().to_string(), - ERROR_UNEXPECTED_LENGTH_OF_INPUT - ); -} - -#[test] -fn test_invalid_enum_variant() { - let bytes = vec![123]; - assert_eq!( - A::try_from_slice(&bytes).unwrap_err().to_string(), - "Unexpected variant index: 123" - ); -} - -#[test] -fn test_extra_bytes() { - let bytes = vec![1, 0, 0, 0, 32, 32]; - assert_eq!( - >::try_from_slice(&bytes).unwrap_err().to_string(), - "Not all bytes read" - ); -} - -#[test] -fn test_invalid_bool() { - for i in 2u8..=255 { - let bytes = [i]; - assert_eq!( - ::try_from_slice(&bytes).unwrap_err().to_string(), - format!("Invalid bool representation: {}", i) - ); - } -} - -#[test] -fn test_invalid_option() { - for i in 2u8..=255 { - let bytes = [i, 32]; - assert_eq!( - >::try_from_slice(&bytes) - .unwrap_err() - .to_string(), - format!( - "Invalid Option representation: {}. The first byte must be 0 or 1", - i - ) - ); - } -} - -#[test] -fn test_invalid_result() { - for i in 2u8..=255 { - let bytes = [i, 0]; - assert_eq!( - >::try_from_slice(&bytes) - .unwrap_err() - .to_string(), - format!( - "Invalid Result representation: {}. The first byte must be 0 or 1", - i - ) - ); - } -} - -#[test] -fn test_invalid_length() { - let bytes = vec![255u8; 4]; - assert_eq!( - >::try_from_slice(&bytes).unwrap_err().to_string(), - ERROR_UNEXPECTED_LENGTH_OF_INPUT - ); -} - -#[test] -fn test_invalid_length_string() { - let bytes = vec![255u8; 4]; - assert_eq!( - String::try_from_slice(&bytes).unwrap_err().to_string(), - ERROR_UNEXPECTED_LENGTH_OF_INPUT - ); -} - -#[test] -fn test_non_utf_string() { - let bytes = vec![1, 0, 0, 0, 0xC0]; - assert_eq!( - String::try_from_slice(&bytes).unwrap_err().to_string(), - "invalid utf-8 sequence of 1 bytes from index 0" - ); -} - -#[test] -fn test_nan_float() { - let bytes = vec![0, 0, 192, 127]; - assert_eq!( - f32::try_from_slice(&bytes).unwrap_err().to_string(), - "For portability reasons we do not allow to deserialize NaNs." - ); -} - -#[test] -fn test_evil_bytes_vec_with_extra() { - // Should fail to allocate given length - // test takes a really long time if read() is used instead of read_exact() - let bytes = vec![255, 255, 255, 255, 32, 32]; - assert_eq!( - >::try_from_slice(&bytes) - .unwrap_err() - .to_string(), - ERROR_UNEXPECTED_LENGTH_OF_INPUT - ); -} - -#[test] -fn test_evil_bytes_string_extra() { - // Might fail if reading too much - let bytes = vec![255, 255, 255, 255, 32, 32]; - assert_eq!( - ::try_from_slice(&bytes).unwrap_err().to_string(), - ERROR_UNEXPECTED_LENGTH_OF_INPUT - ); -} diff --git a/borsh-rs/borsh/tests/test_generic_struct.rs b/borsh-rs/borsh/tests/test_generic_struct.rs deleted file mode 100644 index d6dbf4ccc..000000000 --- a/borsh-rs/borsh/tests/test_generic_struct.rs +++ /dev/null @@ -1,30 +0,0 @@ -use borsh::{BorshDeserialize, BorshSerialize}; - -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] -struct A { - x: Vec, - y: String, - b: B, - c: std::result::Result, - d: [u64; 5], -} - -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] -enum B { - X { f: Vec }, - Y(G), -} - -#[test] -fn test_generic_struct() { - let a = A:: { - x: vec!["foo".to_string(), "bar".to_string()], - y: "world".to_string(), - b: B::X { f: vec![1, 2] }, - c: Err("error".to_string()), - d: [0, 1, 2, 3, 4] - }; - let data = a.try_to_vec().unwrap(); - let actual_a = A::::try_from_slice(&data).unwrap(); - assert_eq!(a, actual_a); -} diff --git a/borsh-rs/borsh/tests/test_schema_enums.rs b/borsh-rs/borsh/tests/test_schema_enums.rs deleted file mode 100644 index c7ad0f622..000000000 --- a/borsh-rs/borsh/tests/test_schema_enums.rs +++ /dev/null @@ -1,209 +0,0 @@ -#![allow(dead_code)] // Local structures do not have their fields used. -use borsh::schema::*; -use borsh::schema_helpers::{try_from_slice_with_schema, try_to_vec_with_schema}; -use borsh::maybestd::collections::HashMap; - -macro_rules! map( - () => { HashMap::new() }; - { $($key:expr => $value:expr),+ } => { - { - let mut m = HashMap::new(); - $( - m.insert($key.to_string(), $value); - )+ - m - } - }; -); - -#[test] -pub fn simple_enum() { - #[derive(borsh::BorshSchema)] - enum A { - Bacon, - Eggs, - } - assert_eq!("A".to_string(), A::declaration()); - let mut defs = Default::default(); - A::add_definitions_recursively(&mut defs); - assert_eq!( - map! { - "ABacon" => Definition::Struct{ fields: Fields::Empty }, - "AEggs" => Definition::Struct{ fields: Fields::Empty }, - "A" => Definition::Enum { variants: vec![("Bacon".to_string(), "ABacon".to_string()), ("Eggs".to_string(), "AEggs".to_string())]} - }, - defs - ); -} - -#[test] -pub fn single_field_enum() { - #[derive(borsh::BorshSchema)] - enum A { - Bacon, - } - assert_eq!("A".to_string(), A::declaration()); - let mut defs = Default::default(); - A::add_definitions_recursively(&mut defs); - assert_eq!( - map! { - "ABacon" => Definition::Struct {fields: Fields::Empty}, - "A" => Definition::Enum { variants: vec![("Bacon".to_string(), "ABacon".to_string())]} - }, - defs - ); -} - -#[test] -pub fn complex_enum_with_schema() { - #[derive( - borsh::BorshSchema, - Default, - borsh::BorshSerialize, - borsh::BorshDeserialize, - PartialEq, - Debug, - )] - struct Tomatoes; - #[derive( - borsh::BorshSchema, - Default, - borsh::BorshSerialize, - borsh::BorshDeserialize, - PartialEq, - Debug, - )] - struct Cucumber; - #[derive( - borsh::BorshSchema, - Default, - borsh::BorshSerialize, - borsh::BorshDeserialize, - PartialEq, - Debug, - )] - struct Oil; - #[derive( - borsh::BorshSchema, - Default, - borsh::BorshSerialize, - borsh::BorshDeserialize, - PartialEq, - Debug, - )] - struct Wrapper; - #[derive( - borsh::BorshSchema, - Default, - borsh::BorshSerialize, - borsh::BorshDeserialize, - PartialEq, - Debug, - )] - struct Filling; - #[derive( - borsh::BorshSchema, borsh::BorshSerialize, borsh::BorshDeserialize, PartialEq, Debug, - )] - enum A { - Bacon, - Eggs, - Salad(Tomatoes, Cucumber, Oil), - Sausage { wrapper: Wrapper, filling: Filling }, - } - - impl Default for A { - fn default() -> Self { - A::Sausage { - wrapper: Default::default(), - filling: Default::default(), - } - } - } - // First check schema. - assert_eq!("A".to_string(), A::declaration()); - let mut defs = Default::default(); - A::add_definitions_recursively(&mut defs); - assert_eq!( - map! { - "Cucumber" => Definition::Struct {fields: Fields::Empty}, - "ASalad" => Definition::Struct{ fields: Fields::UnnamedFields(vec!["Tomatoes".to_string(), "Cucumber".to_string(), "Oil".to_string()])}, - "ABacon" => Definition::Struct {fields: Fields::Empty}, - "Oil" => Definition::Struct {fields: Fields::Empty}, - "A" => Definition::Enum{ variants: vec![ - ("Bacon".to_string(), "ABacon".to_string()), - ("Eggs".to_string(), "AEggs".to_string()), - ("Salad".to_string(), "ASalad".to_string()), - ("Sausage".to_string(), "ASausage".to_string())]}, - "Wrapper" => Definition::Struct {fields: Fields::Empty}, - "Tomatoes" => Definition::Struct {fields: Fields::Empty}, - "ASausage" => Definition::Struct { fields: Fields::NamedFields(vec![ - ("wrapper".to_string(), "Wrapper".to_string()), - ("filling".to_string(), "Filling".to_string()) - ])}, - "AEggs" => Definition::Struct {fields: Fields::Empty}, - "Filling" => Definition::Struct {fields: Fields::Empty} - }, - defs - ); - // Then check that we serialize and deserialize with schema. - let obj = A::default(); - let data = try_to_vec_with_schema(&obj).unwrap(); - let obj2: A = try_from_slice_with_schema(&data).unwrap(); - assert_eq!(obj, obj2); -} - -#[test] -pub fn complex_enum_generics() { - #[derive(borsh::BorshSchema)] - struct Tomatoes; - #[derive(borsh::BorshSchema)] - struct Cucumber; - #[derive(borsh::BorshSchema)] - struct Oil; - #[derive(borsh::BorshSchema)] - struct Wrapper; - #[derive(borsh::BorshSchema)] - struct Filling; - #[derive(borsh::BorshSchema)] - enum A { - Bacon, - Eggs, - Salad(Tomatoes, C, Oil), - Sausage { wrapper: W, filling: Filling }, - } - assert_eq!( - "A".to_string(), - >::declaration() - ); - let mut defs = Default::default(); - >::add_definitions_recursively(&mut defs); - assert_eq!( - map! { - "Cucumber" => Definition::Struct {fields: Fields::Empty}, - "ASalad" => Definition::Struct{ - fields: Fields::UnnamedFields(vec!["Tomatoes".to_string(), "Cucumber".to_string(), "Oil".to_string()]) - }, - "ABacon" => Definition::Struct {fields: Fields::Empty}, - "Oil" => Definition::Struct {fields: Fields::Empty}, - "A" => Definition::Enum{ - variants: vec![ - ("Bacon".to_string(), "ABacon".to_string()), - ("Eggs".to_string(), "AEggs".to_string()), - ("Salad".to_string(), "ASalad".to_string()), - ("Sausage".to_string(), "ASausage".to_string()) - ] - }, - "Wrapper" => Definition::Struct {fields: Fields::Empty}, - "Tomatoes" => Definition::Struct {fields: Fields::Empty}, - "ASausage" => Definition::Struct { - fields: Fields::NamedFields(vec![ - ("wrapper".to_string(), "Wrapper".to_string()), - ("filling".to_string(), "Filling".to_string()) - ]) - }, - "AEggs" => Definition::Struct {fields: Fields::Empty}, - "Filling" => Definition::Struct {fields: Fields::Empty} - }, - defs - ); -} diff --git a/borsh-rs/borsh/tests/test_schema_nested.rs b/borsh-rs/borsh/tests/test_schema_nested.rs deleted file mode 100644 index d003eb900..000000000 --- a/borsh-rs/borsh/tests/test_schema_nested.rs +++ /dev/null @@ -1,83 +0,0 @@ -#![allow(dead_code)] // Local structures do not have their fields used. -use borsh::schema::*; -use borsh::maybestd::collections::HashMap; - -macro_rules! map( - () => { HashMap::new() }; - { $($key:expr => $value:expr),+ } => { - { - let mut m = HashMap::new(); - $( - m.insert($key.to_string(), $value); - )+ - m - } - }; -); - -// Checks that recursive definitions work. Also checks that re-instantiations of templated types work. -#[test] -pub fn duplicated_instantiations() { - #[derive(borsh::BorshSchema)] - struct Tomatoes; - #[derive(borsh::BorshSchema)] - struct Cucumber; - #[derive(borsh::BorshSchema)] - struct Oil { - seeds: HashMap, - liquid: Option, - }; - #[derive(borsh::BorshSchema)] - struct Wrapper { - foo: Option, - bar: Box>, - }; - #[derive(borsh::BorshSchema)] - struct Filling; - #[derive(borsh::BorshSchema)] - enum A { - Bacon, - Eggs, - Salad(Tomatoes, C, Oil), - Sausage { wrapper: W, filling: Filling }, - } - assert_eq!( - "A>".to_string(), - >>::declaration() - ); - let mut defs = Default::default(); - >>::add_definitions_recursively(&mut defs); - assert_eq!( - map! { - "A>" => Definition::Enum {variants: vec![ - ("Bacon".to_string(), "ABacon>".to_string()), - ("Eggs".to_string(), "AEggs>".to_string()), - ("Salad".to_string(), "ASalad>".to_string()), - ("Sausage".to_string(), "ASausage>".to_string()) - ]}, - "A" => Definition::Enum {variants: vec![ - ("Bacon".to_string(), "ABacon".to_string()), - ("Eggs".to_string(), "AEggs".to_string()), - ("Salad".to_string(), "ASalad".to_string()), - ("Sausage".to_string(), "ASausage".to_string())]}, - "ABacon>" => Definition::Struct {fields: Fields::Empty}, - "ABacon" => Definition::Struct {fields: Fields::Empty}, - "AEggs>" => Definition::Struct {fields: Fields::Empty}, - "AEggs" => Definition::Struct {fields: Fields::Empty}, - "ASalad>" => Definition::Struct {fields: Fields::UnnamedFields(vec!["Tomatoes".to_string(), "Cucumber".to_string(), "Oil".to_string()])}, - "ASalad" => Definition::Struct { fields: Fields::UnnamedFields( vec!["Tomatoes".to_string(), "string".to_string(), "Oil".to_string() ])}, - "ASausage>" => Definition::Struct {fields: Fields::NamedFields(vec![("wrapper".to_string(), "Wrapper".to_string()), ("filling".to_string(), "Filling".to_string())])}, - "ASausage" => Definition::Struct{ fields: Fields::NamedFields(vec![("wrapper".to_string(), "string".to_string()), ("filling".to_string(), "Filling".to_string())])}, - "Cucumber" => Definition::Struct {fields: Fields::Empty}, - "Filling" => Definition::Struct {fields: Fields::Empty}, - "HashMap" => Definition::Sequence { elements: "Tuple".to_string()}, - "Oil" => Definition::Struct { fields: Fields::NamedFields(vec![("seeds".to_string(), "HashMap".to_string()), ("liquid".to_string(), "Option".to_string())])}, - "Option" => Definition::Enum {variants: vec![("None".to_string(), "nil".to_string()), ("Some".to_string(), "string".to_string())]}, - "Option" => Definition::Enum { variants: vec![("None".to_string(), "nil".to_string()), ("Some".to_string(), "u64".to_string())]}, - "Tomatoes" => Definition::Struct {fields: Fields::Empty}, - "Tuple" => Definition::Tuple {elements: vec!["u64".to_string(), "string".to_string()]}, - "Wrapper" => Definition::Struct{ fields: Fields::NamedFields(vec![("foo".to_string(), "Option".to_string()), ("bar".to_string(), "A".to_string())])} - }, - defs - ); -} diff --git a/borsh-rs/borsh/tests/test_schema_structs.rs b/borsh-rs/borsh/tests/test_schema_structs.rs deleted file mode 100644 index 5fa894380..000000000 --- a/borsh-rs/borsh/tests/test_schema_structs.rs +++ /dev/null @@ -1,131 +0,0 @@ -use borsh::schema::*; -use borsh::maybestd::collections::HashMap; - -macro_rules! map( - () => { HashMap::new() }; - { $($key:expr => $value:expr),+ } => { - { - let mut m = HashMap::new(); - $( - m.insert($key.to_string(), $value); - )+ - m - } - }; -); - -#[test] -pub fn unit_struct() { - #[derive(borsh::BorshSchema)] - struct A; - assert_eq!("A".to_string(), A::declaration()); - let mut defs = Default::default(); - A::add_definitions_recursively(&mut defs); - assert_eq!( - map! { - "A" => Definition::Struct {fields: Fields::Empty} - }, - defs - ); -} - -#[test] -pub fn simple_struct() { - #[derive(borsh::BorshSchema)] - struct A { - _f1: u64, - _f2: String, - }; - assert_eq!("A".to_string(), A::declaration()); - let mut defs = Default::default(); - A::add_definitions_recursively(&mut defs); - assert_eq!( - map! { - "A" => Definition::Struct{ fields: Fields::NamedFields(vec![ - ("_f1".to_string(), "u64".to_string()), - ("_f2".to_string(), "string".to_string()) - ])} - }, - defs - ); -} - -#[test] -pub fn wrapper_struct() { - #[derive(borsh::BorshSchema)] - struct A(T); - assert_eq!("A".to_string(), >::declaration()); - let mut defs = Default::default(); - >::add_definitions_recursively(&mut defs); - assert_eq!( - map! { - "A" => Definition::Struct {fields: Fields::UnnamedFields(vec!["u64".to_string()])} - }, - defs - ); -} - -#[test] -pub fn tuple_struct() { - #[derive(borsh::BorshSchema)] - struct A(u64, String); - assert_eq!("A".to_string(), A::declaration()); - let mut defs = Default::default(); - A::add_definitions_recursively(&mut defs); - assert_eq!( - map! { - "A" => Definition::Struct {fields: Fields::UnnamedFields(vec![ - "u64".to_string(), "string".to_string() - ])} - }, - defs - ); -} - -#[test] -pub fn tuple_struct_params() { - #[derive(borsh::BorshSchema)] - struct A(K, V); - assert_eq!( - "A".to_string(), - >::declaration() - ); - let mut defs = Default::default(); - >::add_definitions_recursively(&mut defs); - assert_eq!( - map! { - "A" => Definition::Struct { fields: Fields::UnnamedFields(vec![ - "u64".to_string(), "string".to_string() - ])} - }, - defs - ); -} - -#[test] -pub fn simple_generics() { - #[derive(borsh::BorshSchema)] - struct A { - _f1: HashMap, - _f2: String, - }; - assert_eq!( - "A".to_string(), - >::declaration() - ); - let mut defs = Default::default(); - >::add_definitions_recursively(&mut defs); - assert_eq!( - map! { - "A" => Definition::Struct { - fields: Fields::NamedFields(vec![ - ("_f1".to_string(), "HashMap".to_string()), - ("_f2".to_string(), "string".to_string()) - ]) - }, - "HashMap" => Definition::Sequence {elements: "Tuple".to_string()}, - "Tuple" => Definition::Tuple{elements: vec!["u64".to_string(), "string".to_string()]} - }, - defs - ); -} diff --git a/borsh-rs/borsh/tests/test_simple_structs.rs b/borsh-rs/borsh/tests/test_simple_structs.rs deleted file mode 100644 index 3e3262ee5..000000000 --- a/borsh-rs/borsh/tests/test_simple_structs.rs +++ /dev/null @@ -1,144 +0,0 @@ -use borsh::{BorshDeserialize, BorshSerialize}; -use borsh::maybestd::collections::{HashMap, HashSet}; - -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] -#[borsh_init(init)] -struct A<'a> { - x: u64, - b: B, - y: f32, - z: String, - t: (String, u64), - m: HashMap, - s: HashSet, - v: Vec, - w: Box<[u8]>, - box_str: Box, - i: [u8; 32], - u: std::result::Result, - lazy: Option, - c: std::borrow::Cow<'a, str>, - cow_arr: std::borrow::Cow<'a, [std::borrow::Cow<'a, str>]>, - #[borsh_skip] - skipped: Option, -} - -impl A<'_> { - pub fn init(&mut self) { - if let Some(v) = self.lazy.as_mut() { - *v *= 10; - } - } -} - -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] -struct B { - x: u64, - y: i32, - c: C, -} - -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] -enum C { - C1, - C2(u64), - C3(u64, u64), - C4 { x: u64, y: u64 }, - C5(D), -} - -#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] -struct D { - x: u64, -} - -#[derive(BorshSerialize)] -struct E<'a, 'b> { - a: &'a A<'b>, -} - -#[derive(BorshSerialize)] -struct F1<'a, 'b> { - aa: &'a [&'a A<'b>], -} - -#[derive(BorshDeserialize)] -struct F2<'b> { - aa: Vec>, -} - -#[test] -fn test_simple_struct() { - let mut map: HashMap = HashMap::new(); - map.insert("test".into(), "test".into()); - let mut set: HashSet = HashSet::new(); - set.insert(std::u64::MAX); - let cow_arr = [ - std::borrow::Cow::Borrowed("Hello1"), - std::borrow::Cow::Owned("Hello2".to_string()), - ]; - let a = A { - x: 1, - b: B { - x: 2, - y: 3, - c: C::C5(D { x: 1 }), - }, - y: 4.0, - z: "123".to_string(), - t: ("Hello".to_string(), 10), - m: map.clone(), - s: set.clone(), - v: vec!["qwe".to_string(), "zxc".to_string()], - w: vec![0].into_boxed_slice(), - box_str: Box::from("asd"), - i: [4u8; 32], - u: Ok("Hello".to_string()), - lazy: Some(5), - c: std::borrow::Cow::Borrowed("Hello"), - cow_arr: std::borrow::Cow::Borrowed(&cow_arr), - skipped: Some(6), - }; - let encoded_a = a.try_to_vec().unwrap(); - let e = E { a: &a }; - let encoded_ref_a = e.try_to_vec().unwrap(); - assert_eq!(encoded_ref_a, encoded_a); - - let decoded_a = A::try_from_slice(&encoded_a).unwrap(); - let expected_a = A { - x: 1, - b: B { - x: 2, - y: 3, - c: C::C5(D { x: 1 }), - }, - y: 4.0, - z: a.z.clone(), - t: ("Hello".to_string(), 10), - m: map.clone(), - s: set.clone(), - v: a.v.clone(), - w: a.w.clone(), - box_str: Box::from("asd"), - i: a.i, - u: Ok("Hello".to_string()), - lazy: Some(50), - c: std::borrow::Cow::Owned("Hello".to_string()), - cow_arr: std::borrow::Cow::Owned(vec![ - std::borrow::Cow::Borrowed("Hello1"), - std::borrow::Cow::Owned("Hello2".to_string()), - ]), - skipped: None, - }; - - assert_eq!(expected_a, decoded_a); - - let f1 = F1 { aa: &[&a, &a] }; - let encoded_f1 = f1.try_to_vec().unwrap(); - let decoded_f2 = F2::try_from_slice(&encoded_f1).unwrap(); - assert_eq!(decoded_f2.aa.len(), 2); - assert!(decoded_f2 - .aa - .iter() - .all(|f2_a| f2_a == &expected_a)); -} diff --git a/borsh-rs/borsh/tests/test_strings.rs b/borsh-rs/borsh/tests/test_strings.rs deleted file mode 100644 index 3d802ad9a..000000000 --- a/borsh-rs/borsh/tests/test_strings.rs +++ /dev/null @@ -1,22 +0,0 @@ -use borsh::{BorshDeserialize, BorshSerialize}; - -macro_rules! test_string { - ($test_name: ident, $str: expr) => { - #[test] - fn $test_name() { - let s = $str.to_string(); - let buf = s.try_to_vec().unwrap(); - let actual_s = ::try_from_slice(&buf).expect("failed to deserialize a string"); - assert_eq!(actual_s, s); - } - }; -} - -test_string!(test_empty_string, ""); -test_string!(test_a, "a"); -test_string!(test_hello_world, "hello world"); -test_string!(test_x_1024, "x".repeat(1024)); -test_string!(test_x_4096, "x".repeat(4096)); -test_string!(test_x_65535, "x".repeat(65535)); -test_string!(test_hello_1000, "hello world!".repeat(1000)); -test_string!(test_non_ascii, "💩"); diff --git a/borsh-rs/borsh/tests/test_vecs.rs b/borsh-rs/borsh/tests/test_vecs.rs deleted file mode 100644 index ceb01f783..000000000 --- a/borsh-rs/borsh/tests/test_vecs.rs +++ /dev/null @@ -1,32 +0,0 @@ -use borsh::{BorshDeserialize, BorshSerialize}; - -macro_rules! test_vec { - ($v: expr, $t: ty) => { - let buf = $v.try_to_vec().unwrap(); - let actual_v: Vec<$t> = - BorshDeserialize::try_from_slice(&buf).expect("failed to deserialize"); - assert_eq!(actual_v, $v); - }; -} - -macro_rules! test_vecs { - ($test_name: ident, $el: expr, $t: ty) => { - #[test] - fn $test_name() { - test_vec!(Vec::<$t>::new(), $t); - test_vec!(vec![$el], $t); - test_vec!(vec![$el; 10], $t); - test_vec!(vec![$el; 100], $t); - test_vec!(vec![$el; 1000], $t); - test_vec!(vec![$el; 10000], $t); - } - }; -} - -test_vecs!(test_vec_u8, 100u8, u8); -test_vecs!(test_vec_i8, 100i8, i8); -test_vecs!(test_vec_u32, 1000000000u32, u32); -test_vecs!(test_vec_f32, 1000000000.0f32, f32); -test_vecs!(test_vec_string, "a".to_string(), String); -test_vecs!(test_vec_vec_u8, vec![100u8; 10], Vec); -test_vecs!(test_vec_vec_u32, vec![100u32; 10], Vec); diff --git a/borsh-rs/borsh/tests/test_zero_size.rs b/borsh-rs/borsh/tests/test_zero_size.rs deleted file mode 100644 index b47943d40..000000000 --- a/borsh-rs/borsh/tests/test_zero_size.rs +++ /dev/null @@ -1,11 +0,0 @@ -use borsh::BorshDeserialize; - -#[derive(BorshDeserialize, PartialEq, Debug)] -struct A; - -#[test] -fn test_deserialize_vector_to_many_zero_size_struct() { - let v = [0u8, 0u8, 0u8, 64u8]; - let a = Vec::::try_from_slice(&v).unwrap(); - assert_eq!(A {}, a[usize::pow(2, 30) - 1]) -} diff --git a/borsh-rs/fuzz/fuzz-run/Cargo.lock b/borsh-rs/fuzz/fuzz-run/Cargo.lock deleted file mode 100644 index da0203771..000000000 --- a/borsh-rs/fuzz/fuzz-run/Cargo.lock +++ /dev/null @@ -1,131 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "arbitrary" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "borsh" -version = "0.2.9" -dependencies = [ - "borsh-derive 0.2.9", -] - -[[package]] -name = "borsh-derive" -version = "0.2.9" -dependencies = [ - "borsh-derive-internal 0.2.9", - "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.2.9" -dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "borsh-fuzz" -version = "0.1.0" -dependencies = [ - "borsh 0.2.9", - "honggfuzz 0.5.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "honggfuzz" -version = "0.5.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arbitrary 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.65" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memmap" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro2" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quote" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-xid" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum arbitrary 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "64cf76cb6e2222ed0ea86b2b0ee2f71c96ec6edd5af42e84d59160e91b836ec4" -"checksum honggfuzz 0.5.45 (registry+https://github.com/rust-lang/crates.io-index)" = "24c27b4aa3049d6d10d8e33d52c9d03ca9aec18f8a449b246f8c4a5b0c10fb34" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" -"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" -"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7bedb3320d0f3035594b0b723c8a28d7d336a3eda3881db79e61d676fb644c" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/borsh-rs/fuzz/fuzz-run/Cargo.toml b/borsh-rs/fuzz/fuzz-run/Cargo.toml deleted file mode 100644 index 9183db7cd..000000000 --- a/borsh-rs/fuzz/fuzz-run/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "borsh-fuzz" -version = "0.1.0" -authors = ["Near Inc "] -edition = "2018" -publish = false - -[[bin]] -name = "borsh-fuzz" -path = "src/main.rs" - -[dependencies] -honggfuzz = "0.5" -borsh = { path = "../../borsh" } diff --git a/borsh-rs/fuzz/fuzz-run/README.md b/borsh-rs/fuzz/fuzz-run/README.md deleted file mode 100644 index 2dbc8a0ad..000000000 --- a/borsh-rs/fuzz/fuzz-run/README.md +++ /dev/null @@ -1 +0,0 @@ -A fuzzer for Borsh deserializer. To start fuzzing, follow instructions here https://github.com/rust-fuzz/honggfuzz-rs#how-to-use-this-crate diff --git a/borsh-rs/fuzz/fuzz-run/src/main.rs b/borsh-rs/fuzz/fuzz-run/src/main.rs deleted file mode 100644 index a955788da..000000000 --- a/borsh-rs/fuzz/fuzz-run/src/main.rs +++ /dev/null @@ -1,67 +0,0 @@ -use borsh::BorshDeserialize; -use std::collections::{BTreeMap, HashMap, HashSet}; - -#[macro_use] -extern crate honggfuzz; - -macro_rules! fuzz_types { - ( - $data:ident; - $( $type:ty, )* - ) => { - $( - let _ = <$type>::deserialize(&mut &$data[..]); - )* - }; - -} - -fn main() { - loop { - fuzz!(|data: &[u8]| { - fuzz_types!( - data; - u32, - u64, - i32, - i64, - f32, - f64, - String, - (u32,u64,i32,i64,f32,f64,String,), - std::net::SocketAddrV4, - std::net::SocketAddrV6, - std::net::Ipv4Addr, - std::net::Ipv6Addr, - Box<[u8]>, - Option, - Option, - Option>, - Option>, - Option>, - Option, - Vec, - Vec, - Vec>, - Vec>, - Vec>, - Vec, - HashSet, - HashSet, - HashSet>, - HashSet>, - HashSet>, - HashSet, - HashMap, - HashMap, - HashMap, - HashMap, Vec>, - HashMap, HashMap>, - BTreeMap, - BTreeMap, - BTreeMap, Vec>, - BTreeMap, BTreeMap>, - ); - }); - } -} diff --git a/borsh-rs/publish.sh b/borsh-rs/publish.sh deleted file mode 100755 index d01920e92..000000000 --- a/borsh-rs/publish.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -set -ex -for p in borsh-schema-derive-internal borsh-derive-internal borsh-derive borsh -do -pushd ./${p} -cargo publish -popd -# Sleep a bit to let the previous package upload to crates.io. Otherwise we fail publishing checks. -sleep 30 -done - diff --git a/borsh-ts/.eslintrc.yml b/borsh-ts/.eslintrc.yml deleted file mode 100644 index 2ddf2ee65..000000000 --- a/borsh-ts/.eslintrc.yml +++ /dev/null @@ -1,18 +0,0 @@ -env: - es6: true - node: true -extends: - - 'eslint:recommended' - - 'plugin:@typescript-eslint/eslint-recommended' - - 'plugin:@typescript-eslint/recommended' -parser: '@typescript-eslint/parser' -rules: - no-inner-declarations: 1 - '@typescript-eslint/no-explicit-any': 1 - '@typescript-eslint/camelcase': 1 - '@typescript-eslint/explicit-function-return-type': 1 - '@typescript-eslint/no-use-before-define': 1 - -parserOptions: - ecmaVersion: 2018 - sourceType: module \ No newline at end of file diff --git a/borsh-ts/index.ts b/borsh-ts/index.ts deleted file mode 100644 index 655a7bd95..000000000 --- a/borsh-ts/index.ts +++ /dev/null @@ -1,319 +0,0 @@ -import BN from 'bn.js'; - -// TODO: Make sure this polyfill not included when not required -import * as encoding from 'text-encoding-utf-8'; -const TextDecoder = (typeof (global as any).TextDecoder !== 'function') ? encoding.TextDecoder : (global as any).TextDecoder; -const textDecoder = new TextDecoder('utf-8', { fatal: true }); - -const INITIAL_LENGTH = 1024; - -export type Schema = Map; - -export class BorshError extends Error { - originalMessage: string; - fieldPath: string[] = []; - - constructor(message: string) { - super(message); - this.originalMessage = message; - } - - addToFieldPath(fieldName: string) { - this.fieldPath.splice(0, 0, fieldName); - // NOTE: Modifying message directly as jest doesn't use .toString() - this.message = this.originalMessage + ': ' + this.fieldPath.join('.'); - } -} - -/// Binary encoder. -export class BinaryWriter { - buf: Buffer; - length: number; - - public constructor() { - this.buf = Buffer.alloc(INITIAL_LENGTH); - this.length = 0; - } - - maybeResize() { - if (this.buf.length < 16 + this.length) { - this.buf = Buffer.concat([this.buf, Buffer.alloc(INITIAL_LENGTH)]); - } - } - - public writeU8(value: number) { - this.maybeResize(); - this.buf.writeUInt8(value, this.length); - this.length += 1; - } - - public writeU32(value: number) { - this.maybeResize(); - this.buf.writeUInt32LE(value, this.length); - this.length += 4; - } - - public writeU64(value: BN) { - this.maybeResize(); - this.writeBuffer(Buffer.from(new BN(value).toArray('le', 8))); - } - - public writeU128(value: BN) { - this.maybeResize(); - this.writeBuffer(Buffer.from(new BN(value).toArray('le', 16))); - } - - private writeBuffer(buffer: Buffer) { - // Buffer.from is needed as this.buf.subarray can return plain Uint8Array in browser - this.buf = Buffer.concat([Buffer.from(this.buf.subarray(0, this.length)), buffer, Buffer.alloc(INITIAL_LENGTH)]); - this.length += buffer.length; - } - - public writeString(str: string) { - this.maybeResize(); - const b = Buffer.from(str, 'utf8'); - this.writeU32(b.length); - this.writeBuffer(b); - } - - public writeFixedArray(array: Uint8Array) { - this.writeBuffer(Buffer.from(array)); - } - - public writeArray(array: any[], fn: any) { - this.maybeResize(); - this.writeU32(array.length); - for (const elem of array) { - this.maybeResize(); - fn(elem); - } - } - - public toArray(): Uint8Array { - return this.buf.subarray(0, this.length); - } -} - -function handlingRangeError(target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor) { - const originalMethod = propertyDescriptor.value; - propertyDescriptor.value = function (...args: any[]) { - try { - return originalMethod.apply(this, args); - } catch (e) { - if (e instanceof RangeError) { - const code = (e as any).code; - if (['ERR_BUFFER_OUT_OF_BOUNDS', 'ERR_OUT_OF_RANGE'].indexOf(code) >= 0) { - throw new BorshError('Reached the end of buffer when deserializing'); - } - } - throw e; - } - }; -} - -export class BinaryReader { - buf: Buffer; - offset: number; - - public constructor(buf: Buffer) { - this.buf = buf; - this.offset = 0; - } - - @handlingRangeError - readU8(): number { - const value = this.buf.readUInt8(this.offset); - this.offset += 1; - return value; - } - - @handlingRangeError - readU32(): number { - const value = this.buf.readUInt32LE(this.offset); - this.offset += 4; - return value; - } - - @handlingRangeError - readU64(): BN { - const buf = this.readBuffer(8); - return new BN(buf, 'le'); - } - - @handlingRangeError - readU128(): BN { - const buf = this.readBuffer(16); - return new BN(buf, 'le'); - } - - private readBuffer(len: number): Buffer { - if ((this.offset + len) > this.buf.length) { - throw new BorshError(`Expected buffer length ${len} isn't within bounds`); - } - const result = this.buf.slice(this.offset, this.offset + len); - this.offset += len; - return result; - } - - @handlingRangeError - readString(): string { - const len = this.readU32(); - const buf = this.readBuffer(len); - try { - // NOTE: Using TextDecoder to fail on invalid UTF-8 - return textDecoder.decode(buf); - } catch (e) { - throw new BorshError(`Error decoding UTF-8 string: ${e}`); - } - } - - @handlingRangeError - readFixedArray(len: number): Uint8Array { - return new Uint8Array(this.readBuffer(len)); - } - - @handlingRangeError - readArray(fn: any): any[] { - const len = this.readU32(); - const result = Array(); - for (let i = 0; i < len; ++i) { - result.push(fn()); - } - return result; - } -} - -function capitalizeFirstLetter(string) { - return string.charAt(0).toUpperCase() + string.slice(1); -} - -function serializeField(schema: Schema, fieldName: string, value: any, fieldType: any, writer: any) { - try { - // TODO: Handle missing values properly (make sure they never result in just skipped write) - if (typeof fieldType === 'string') { - writer[`write${capitalizeFirstLetter(fieldType)}`](value); - - } else if (fieldType instanceof Array) { - if (typeof fieldType[0] === 'number') { - if (value.length !== fieldType[0]) { - throw new BorshError(`Expecting byte array of length ${fieldType[0]}, but got ${value.length} bytes`); - } - writer.writeFixedArray(value); - } else { - writer.writeArray(value, (item: any) => { serializeField(schema, fieldName, item, fieldType[0], writer); }); - } - } else if (fieldType.kind !== undefined) { - switch (fieldType.kind) { - case 'option': { - if (value === null) { - writer.writeU8(0); - } else { - writer.writeU8(1); - serializeField(schema, fieldName, value, fieldType.type, writer); - } - break; - } - default: throw new BorshError(`FieldType ${fieldType} unrecognized`); - } - } else { - serializeStruct(schema, value, writer); - } - } catch (error) { - if (error instanceof BorshError) { - error.addToFieldPath(fieldName); - } - throw error; - } -} - -function serializeStruct(schema: Schema, obj: any, writer: any) { - const structSchema = schema.get(obj.constructor); - if (!structSchema) { - throw new BorshError(`Class ${obj.constructor.name} is missing in schema`); - } - if (structSchema.kind === 'struct') { - structSchema.fields.map(([fieldName, fieldType]: [any, any]) => { - serializeField(schema, fieldName, obj[fieldName], fieldType, writer); - }); - } else if (structSchema.kind === 'enum') { - const name = obj[structSchema.field]; - for (let idx = 0; idx < structSchema.values.length; ++idx) { - const [fieldName, fieldType]: [any, any] = structSchema.values[idx]; - if (fieldName === name) { - writer.writeU8(idx); - serializeField(schema, fieldName, obj[fieldName], fieldType, writer); - break; - } - } - } else { - throw new BorshError(`Unexpected schema kind: ${structSchema.kind} for ${obj.constructor.name}`); - } -} - -/// Serialize given object using schema of the form: -/// { class_name -> [ [field_name, field_type], .. ], .. } -export function serialize(schema: Schema, obj: any): Uint8Array { - const writer = new BinaryWriter(); - serializeStruct(schema, obj, writer); - return writer.toArray(); -} - -function deserializeField(schema: Schema, fieldName: string, fieldType: any, reader: BinaryReader): any { - try { - if (typeof fieldType === 'string') { - return reader[`read${capitalizeFirstLetter(fieldType)}`](); - } - - if (fieldType instanceof Array) { - if (typeof fieldType[0] === 'number') { - return reader.readFixedArray(fieldType[0]); - } - - return reader.readArray(() => deserializeField(schema, fieldName, fieldType[0], reader)); - } - - return deserializeStruct(schema, fieldType, reader); - } catch (error) { - if (error instanceof BorshError) { - error.addToFieldPath(fieldName); - } - throw error; - } -} - -function deserializeStruct(schema: Schema, classType: any, reader: BinaryReader) { - const structSchema = schema.get(classType); - if (!structSchema) { - throw new BorshError(`Class ${classType.name} is missing in schema`); - } - - if (structSchema.kind === 'struct') { - const result = {}; - for (const [fieldName, fieldType] of schema.get(classType).fields) { - result[fieldName] = deserializeField(schema, fieldName, fieldType, reader); - } - return new classType(result); - } - - if (structSchema.kind === 'enum') { - const idx = reader.readU8(); - if (idx >= structSchema.values.length) { - throw new BorshError(`Enum index: ${idx} is out of range`); - } - const [fieldName, fieldType] = structSchema.values[idx]; - const fieldValue = deserializeField(schema, fieldName, fieldType, reader); - return new classType({ [fieldName]: fieldValue }); - } - - throw new BorshError(`Unexpected schema kind: ${structSchema.kind} for ${classType.constructor.name}`); -} - -/// Deserializes object from bytes using schema. -export function deserialize(schema: Schema, classType: any, buffer: Buffer): any { - const reader = new BinaryReader(buffer); - const result = deserializeStruct(schema, classType, reader); - if (reader.offset < buffer.length) { - throw new BorshError(`Unexpected ${buffer.length - reader.offset} bytes after deserialized data`); - } - return result; -} \ No newline at end of file diff --git a/borsh-ts/test/.eslintrc.yml b/borsh-ts/test/.eslintrc.yml deleted file mode 100644 index ab46369c7..000000000 --- a/borsh-ts/test/.eslintrc.yml +++ /dev/null @@ -1,3 +0,0 @@ -extends: '../../.eslintrc.yml' -env: - jest: true diff --git a/borsh-ts/test/fuzz/borsh-roundtrip.js b/borsh-ts/test/fuzz/borsh-roundtrip.js deleted file mode 100644 index f790375d4..000000000 --- a/borsh-ts/test/fuzz/borsh-roundtrip.js +++ /dev/null @@ -1,19 +0,0 @@ -const borsh = require('../../../lib/index.js'); -const transaction = require('./transaction-example/transaction'); - -exports.fuzz = input => { - try { - const deserialized = borsh.deserialize(transaction.SCHEMA, transaction.Transaction, input); - const serialized = borsh.serialize(transaction.SCHEMA, deserialized); - if (!serialized.equals(input)) { - console.log(`Mismatching output:\n${serialized.toString('hex')}\nand input:\n${input.toString('hex')}`); - throw new Error('Mismatching input and output'); - } - } catch (e) { - if (e instanceof borsh.BorshError) { - // Do nothing - } else { - throw e; - } - } -}; \ No newline at end of file diff --git a/borsh-ts/test/fuzz/corpus/004b705c22403d1c22ceab37181f6340b5b269b7faee05d97fe65b1ab91cd171 b/borsh-ts/test/fuzz/corpus/004b705c22403d1c22ceab37181f6340b5b269b7faee05d97fe65b1ab91cd171 deleted file mode 100644 index fcfea9a29..000000000 Binary files a/borsh-ts/test/fuzz/corpus/004b705c22403d1c22ceab37181f6340b5b269b7faee05d97fe65b1ab91cd171 and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/25b2da453a8cb0d574d31a06f0a57fc7b5f2cb5c08ba00ff900a79ebd0637da7 b/borsh-ts/test/fuzz/corpus/25b2da453a8cb0d574d31a06f0a57fc7b5f2cb5c08ba00ff900a79ebd0637da7 deleted file mode 100644 index 3e55b9a7f..000000000 Binary files a/borsh-ts/test/fuzz/corpus/25b2da453a8cb0d574d31a06f0a57fc7b5f2cb5c08ba00ff900a79ebd0637da7 and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/2f6f8117189cb82e111a13b3ffb19fcaf35deef41f8c084726c5aac5a4551696 b/borsh-ts/test/fuzz/corpus/2f6f8117189cb82e111a13b3ffb19fcaf35deef41f8c084726c5aac5a4551696 deleted file mode 100644 index 9f09c84d6..000000000 Binary files a/borsh-ts/test/fuzz/corpus/2f6f8117189cb82e111a13b3ffb19fcaf35deef41f8c084726c5aac5a4551696 and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/4eb3f263ac0d9bac83d67e28d3381c64c61654579dc455a9e5ccaa54bc093721 b/borsh-ts/test/fuzz/corpus/4eb3f263ac0d9bac83d67e28d3381c64c61654579dc455a9e5ccaa54bc093721 deleted file mode 100644 index 0ea79f182..000000000 Binary files a/borsh-ts/test/fuzz/corpus/4eb3f263ac0d9bac83d67e28d3381c64c61654579dc455a9e5ccaa54bc093721 and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/5a0ac0f8936af102c2ea974ba237896a8ee4dffebd27b65c8101a1d8897d6409 b/borsh-ts/test/fuzz/corpus/5a0ac0f8936af102c2ea974ba237896a8ee4dffebd27b65c8101a1d8897d6409 deleted file mode 100644 index 01698c4bc..000000000 Binary files a/borsh-ts/test/fuzz/corpus/5a0ac0f8936af102c2ea974ba237896a8ee4dffebd27b65c8101a1d8897d6409 and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/67fc403d488908e0a27d74a2de056c34c40850bbe61b9ebc82cf48365484f4fc b/borsh-ts/test/fuzz/corpus/67fc403d488908e0a27d74a2de056c34c40850bbe61b9ebc82cf48365484f4fc deleted file mode 100644 index 77435fee1..000000000 Binary files a/borsh-ts/test/fuzz/corpus/67fc403d488908e0a27d74a2de056c34c40850bbe61b9ebc82cf48365484f4fc and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/7fa19d2ffc291390ebe8a238baae9bddbd620d018f803540e09ac1bc82ec3a6c b/borsh-ts/test/fuzz/corpus/7fa19d2ffc291390ebe8a238baae9bddbd620d018f803540e09ac1bc82ec3a6c deleted file mode 100644 index a0e1afd9d..000000000 Binary files a/borsh-ts/test/fuzz/corpus/7fa19d2ffc291390ebe8a238baae9bddbd620d018f803540e09ac1bc82ec3a6c and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/824d229c23c200a937bcd558a5c55d25830a8efffb9e8661a81e2db3584ca512 b/borsh-ts/test/fuzz/corpus/824d229c23c200a937bcd558a5c55d25830a8efffb9e8661a81e2db3584ca512 deleted file mode 100644 index f7c9ac58b..000000000 Binary files a/borsh-ts/test/fuzz/corpus/824d229c23c200a937bcd558a5c55d25830a8efffb9e8661a81e2db3584ca512 and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/9d6a787b7d95c13bb67d02137cf3e506f550fcfa19363050d1e4917250d83d32 b/borsh-ts/test/fuzz/corpus/9d6a787b7d95c13bb67d02137cf3e506f550fcfa19363050d1e4917250d83d32 deleted file mode 100644 index 630b94ad0..000000000 Binary files a/borsh-ts/test/fuzz/corpus/9d6a787b7d95c13bb67d02137cf3e506f550fcfa19363050d1e4917250d83d32 and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/a330e2fd8d25278e3d28205107e67373646fe7c5370030819ccc13990375ca73 b/borsh-ts/test/fuzz/corpus/a330e2fd8d25278e3d28205107e67373646fe7c5370030819ccc13990375ca73 deleted file mode 100644 index ba1b6a5fd..000000000 Binary files a/borsh-ts/test/fuzz/corpus/a330e2fd8d25278e3d28205107e67373646fe7c5370030819ccc13990375ca73 and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/a53d5be4493c7cccab1d70bdaf44b17f2cd52501f1b5567ed05406163cf96fef b/borsh-ts/test/fuzz/corpus/a53d5be4493c7cccab1d70bdaf44b17f2cd52501f1b5567ed05406163cf96fef deleted file mode 100644 index e577158e8..000000000 Binary files a/borsh-ts/test/fuzz/corpus/a53d5be4493c7cccab1d70bdaf44b17f2cd52501f1b5567ed05406163cf96fef and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/b7361e727623b1cdafda1411e27c119009d0fcccbdddd5fe669c8c02bf04f7dd b/borsh-ts/test/fuzz/corpus/b7361e727623b1cdafda1411e27c119009d0fcccbdddd5fe669c8c02bf04f7dd deleted file mode 100644 index d0f9ae032..000000000 Binary files a/borsh-ts/test/fuzz/corpus/b7361e727623b1cdafda1411e27c119009d0fcccbdddd5fe669c8c02bf04f7dd and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/b98f80e8a618038000215158136c1f2dbd9ed3cad450556faf7b18db4184b42e b/borsh-ts/test/fuzz/corpus/b98f80e8a618038000215158136c1f2dbd9ed3cad450556faf7b18db4184b42e deleted file mode 100644 index 0181e35d1..000000000 Binary files a/borsh-ts/test/fuzz/corpus/b98f80e8a618038000215158136c1f2dbd9ed3cad450556faf7b18db4184b42e and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/bec080831059d96afd82176d6e8ee36819bb22b7304f4e23f61d189a6c221f92 b/borsh-ts/test/fuzz/corpus/bec080831059d96afd82176d6e8ee36819bb22b7304f4e23f61d189a6c221f92 deleted file mode 100644 index b04b3f058..000000000 Binary files a/borsh-ts/test/fuzz/corpus/bec080831059d96afd82176d6e8ee36819bb22b7304f4e23f61d189a6c221f92 and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/cf94b13d93b7accf950d3d2a1be308f7d25d21f81622a7ffc7da3733c03eb572 b/borsh-ts/test/fuzz/corpus/cf94b13d93b7accf950d3d2a1be308f7d25d21f81622a7ffc7da3733c03eb572 deleted file mode 100644 index 5ade500ec..000000000 Binary files a/borsh-ts/test/fuzz/corpus/cf94b13d93b7accf950d3d2a1be308f7d25d21f81622a7ffc7da3733c03eb572 and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/d2897d4dc13f861fb5e7caf8e5b7e1c9962a36c8489ada9cb0f798c1ec967eb7 b/borsh-ts/test/fuzz/corpus/d2897d4dc13f861fb5e7caf8e5b7e1c9962a36c8489ada9cb0f798c1ec967eb7 deleted file mode 100644 index 86c116b94..000000000 Binary files a/borsh-ts/test/fuzz/corpus/d2897d4dc13f861fb5e7caf8e5b7e1c9962a36c8489ada9cb0f798c1ec967eb7 and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/dfbc571f6a049f8f66f2fcb510fffc51f5c78078db2a2fb5cf19b0bd840291ee b/borsh-ts/test/fuzz/corpus/dfbc571f6a049f8f66f2fcb510fffc51f5c78078db2a2fb5cf19b0bd840291ee deleted file mode 100644 index 9e07e17d6..000000000 Binary files a/borsh-ts/test/fuzz/corpus/dfbc571f6a049f8f66f2fcb510fffc51f5c78078db2a2fb5cf19b0bd840291ee and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/e08ccfae0c2fd6432c8e1bf841050f0b2d78fa519ac76f178db0757d1bd3e96e b/borsh-ts/test/fuzz/corpus/e08ccfae0c2fd6432c8e1bf841050f0b2d78fa519ac76f178db0757d1bd3e96e deleted file mode 100644 index 212ab60fe..000000000 Binary files a/borsh-ts/test/fuzz/corpus/e08ccfae0c2fd6432c8e1bf841050f0b2d78fa519ac76f178db0757d1bd3e96e and /dev/null differ diff --git a/borsh-ts/test/fuzz/corpus/ecd71b60d1820dbbcb06d1f981ab86d16876888bb7ba665637c5717c0a8916b2 b/borsh-ts/test/fuzz/corpus/ecd71b60d1820dbbcb06d1f981ab86d16876888bb7ba665637c5717c0a8916b2 deleted file mode 100644 index 82dc8f8e8..000000000 Binary files a/borsh-ts/test/fuzz/corpus/ecd71b60d1820dbbcb06d1f981ab86d16876888bb7ba665637c5717c0a8916b2 and /dev/null differ diff --git a/borsh-ts/test/fuzz/transaction-example/enums.d.ts b/borsh-ts/test/fuzz/transaction-example/enums.d.ts deleted file mode 100644 index 4d0a3dae9..000000000 --- a/borsh-ts/test/fuzz/transaction-example/enums.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -export declare abstract class Enum { - enum: string; - constructor(properties: any); -} -export declare abstract class Assignable { - constructor(properties: any); -} diff --git a/borsh-ts/test/fuzz/transaction-example/enums.js b/borsh-ts/test/fuzz/transaction-example/enums.js deleted file mode 100644 index 68d950cb3..000000000 --- a/borsh-ts/test/fuzz/transaction-example/enums.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class Enum { - constructor(properties) { - if (Object.keys(properties).length !== 1) { - throw new Error('Enum can only take single value'); - } - Object.keys(properties).map((key) => { - this[key] = properties[key]; - this.enum = key; - }); - } -} -exports.Enum = Enum; -class Assignable { - constructor(properties) { - Object.keys(properties).map((key) => { - this[key] = properties[key]; - }); - } -} -exports.Assignable = Assignable; diff --git a/borsh-ts/test/fuzz/transaction-example/key_pair.d.ts b/borsh-ts/test/fuzz/transaction-example/key_pair.d.ts deleted file mode 100644 index cf7a473d2..000000000 --- a/borsh-ts/test/fuzz/transaction-example/key_pair.d.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Assignable } from './enums'; -export declare type Arrayish = string | ArrayLike; -export interface Signature { - signature: Uint8Array; - publicKey: PublicKey; -} -/** All supported key types */ -export declare enum KeyType { - ED25519 = 0 -} -/** - * PublicKey representation that has type and bytes of the key. - */ -export declare class PublicKey extends Assignable { - keyType: KeyType; - data: Uint8Array; - static from(value: string | PublicKey): PublicKey; - static fromString(encodedKey: string): PublicKey; - toString(): string; -} -export declare abstract class KeyPair { - abstract sign(message: Uint8Array): Signature; - abstract verify(message: Uint8Array, signature: Uint8Array): boolean; - abstract toString(): string; - abstract getPublicKey(): PublicKey; - /** - * @param curve Name of elliptical curve, case-insensitive - * @returns Random KeyPair based on the curve - */ - static fromRandom(curve: string): KeyPair; - static fromString(encodedKey: string): KeyPair; -} -/** - * This class provides key pair functionality for Ed25519 curve: - * generating key pairs, encoding key pairs, signing and verifying. - */ -export declare class KeyPairEd25519 extends KeyPair { - readonly publicKey: PublicKey; - readonly secretKey: string; - /** - * Construct an instance of key pair given a secret key. - * It's generally assumed that these are encoded in base58. - * @param {string} secretKey - */ - constructor(secretKey: string); - /** - * Generate a new random keypair. - * @example - * const keyRandom = KeyPair.fromRandom(); - * keyRandom.publicKey - * // returns [PUBLIC_KEY] - * - * keyRandom.secretKey - * // returns [SECRET_KEY] - */ - static fromRandom(): KeyPairEd25519; - sign(message: Uint8Array): Signature; - verify(message: Uint8Array, signature: Uint8Array): boolean; - toString(): string; - getPublicKey(): PublicKey; -} diff --git a/borsh-ts/test/fuzz/transaction-example/key_pair.js b/borsh-ts/test/fuzz/transaction-example/key_pair.js deleted file mode 100644 index 16182d5e0..000000000 --- a/borsh-ts/test/fuzz/transaction-example/key_pair.js +++ /dev/null @@ -1,125 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const tweetnacl_1 = __importDefault(require("tweetnacl")); -const serialize_1 = require("./serialize"); -const enums_1 = require("./enums"); -/** All supported key types */ -var KeyType; -(function (KeyType) { - KeyType[KeyType["ED25519"] = 0] = "ED25519"; -})(KeyType = exports.KeyType || (exports.KeyType = {})); -function key_type_to_str(keyType) { - switch (keyType) { - case KeyType.ED25519: return 'ed25519'; - default: throw new Error(`Unknown key type ${keyType}`); - } -} -function str_to_key_type(keyType) { - switch (keyType.toLowerCase()) { - case 'ed25519': return KeyType.ED25519; - default: throw new Error(`Unknown key type ${keyType}`); - } -} -/** - * PublicKey representation that has type and bytes of the key. - */ -class PublicKey extends enums_1.Assignable { - static from(value) { - if (typeof value === 'string') { - return PublicKey.fromString(value); - } - return value; - } - static fromString(encodedKey) { - const parts = encodedKey.split(':'); - if (parts.length === 1) { - return new PublicKey({ keyType: KeyType.ED25519, data: serialize_1.base_decode(parts[0]) }); - } - else if (parts.length === 2) { - return new PublicKey({ keyType: str_to_key_type(parts[0]), data: serialize_1.base_decode(parts[1]) }); - } - else { - throw new Error('Invalid encoded key format, must be :'); - } - } - toString() { - return `${key_type_to_str(this.keyType)}:${serialize_1.base_encode(this.data)}`; - } -} -exports.PublicKey = PublicKey; -class KeyPair { - /** - * @param curve Name of elliptical curve, case-insensitive - * @returns Random KeyPair based on the curve - */ - static fromRandom(curve) { - switch (curve.toUpperCase()) { - case 'ED25519': return KeyPairEd25519.fromRandom(); - default: throw new Error(`Unknown curve ${curve}`); - } - } - static fromString(encodedKey) { - const parts = encodedKey.split(':'); - if (parts.length === 1) { - return new KeyPairEd25519(parts[0]); - } - else if (parts.length === 2) { - switch (parts[0].toUpperCase()) { - case 'ED25519': return new KeyPairEd25519(parts[1]); - default: throw new Error(`Unknown curve: ${parts[0]}`); - } - } - else { - throw new Error('Invalid encoded key format, must be :'); - } - } -} -exports.KeyPair = KeyPair; -/** - * This class provides key pair functionality for Ed25519 curve: - * generating key pairs, encoding key pairs, signing and verifying. - */ -class KeyPairEd25519 extends KeyPair { - /** - * Construct an instance of key pair given a secret key. - * It's generally assumed that these are encoded in base58. - * @param {string} secretKey - */ - constructor(secretKey) { - super(); - const keyPair = tweetnacl_1.default.sign.keyPair.fromSecretKey(serialize_1.base_decode(secretKey)); - this.publicKey = new PublicKey({ keyType: KeyType.ED25519, data: keyPair.publicKey }); - this.secretKey = secretKey; - } - /** - * Generate a new random keypair. - * @example - * const keyRandom = KeyPair.fromRandom(); - * keyRandom.publicKey - * // returns [PUBLIC_KEY] - * - * keyRandom.secretKey - * // returns [SECRET_KEY] - */ - static fromRandom() { - const newKeyPair = tweetnacl_1.default.sign.keyPair(); - return new KeyPairEd25519(serialize_1.base_encode(newKeyPair.secretKey)); - } - sign(message) { - const signature = tweetnacl_1.default.sign.detached(message, serialize_1.base_decode(this.secretKey)); - return { signature, publicKey: this.publicKey }; - } - verify(message, signature) { - return tweetnacl_1.default.sign.detached.verify(message, signature, this.publicKey.data); - } - toString() { - return `ed25519:${this.secretKey}`; - } - getPublicKey() { - return this.publicKey; - } -} -exports.KeyPairEd25519 = KeyPairEd25519; diff --git a/borsh-ts/test/fuzz/transaction-example/serialize.d.ts b/borsh-ts/test/fuzz/transaction-example/serialize.d.ts deleted file mode 100644 index 6db96b581..000000000 --- a/borsh-ts/test/fuzz/transaction-example/serialize.d.ts +++ /dev/null @@ -1,41 +0,0 @@ -/// -import BN from 'bn.js'; -export declare function base_encode(value: Uint8Array | string): string; -export declare function base_decode(value: string): Uint8Array; -export declare type Schema = Map; -export declare class BorshError extends Error { - originalMessage: string; - fieldPath: string[]; - constructor(message: string); - addToFieldPath(fieldName: string): void; -} -export declare class BinaryWriter { - buf: Buffer; - length: number; - constructor(); - maybe_resize(): void; - write_u8(value: number): void; - write_u32(value: number): void; - write_u64(value: BN): void; - write_u128(value: BN): void; - private write_buffer; - write_string(str: string): void; - write_fixed_array(array: Uint8Array): void; - write_array(array: any[], fn: any): void; - toArray(): Uint8Array; -} -export declare class BinaryReader { - buf: Buffer; - offset: number; - constructor(buf: Buffer); - read_u8(): number; - read_u32(): number; - read_u64(): BN; - read_u128(): BN; - private read_buffer; - read_string(): string; - read_fixed_array(len: number): Uint8Array; - read_array(fn: any): any[]; -} -export declare function serialize(schema: Schema, obj: any): Uint8Array; -export declare function deserialize(schema: Schema, classType: any, buffer: Buffer): any; diff --git a/borsh-ts/test/fuzz/transaction-example/serialize.js b/borsh-ts/test/fuzz/transaction-example/serialize.js deleted file mode 100644 index 8084fc574..000000000 --- a/borsh-ts/test/fuzz/transaction-example/serialize.js +++ /dev/null @@ -1,16 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -const bs58_1 = __importDefault(require("bs58")); -function base_encode(value) { - if (typeof (value) === 'string') { - value = Buffer.from(value, 'utf8'); - } - return bs58_1.default.encode(Buffer.from(value)); -} -exports.base_encode = base_encode; -function base_decode(value) { - return Buffer.from(bs58_1.default.decode(value)); -} -exports.base_decode = base_decode; diff --git a/borsh-ts/test/fuzz/transaction-example/signer.d.ts b/borsh-ts/test/fuzz/transaction-example/signer.d.ts deleted file mode 100644 index 36775b637..000000000 --- a/borsh-ts/test/fuzz/transaction-example/signer.d.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Signature, KeyPair, PublicKey } from './key_pair'; -import { KeyStore } from './key_stores'; -/** - * General signing interface, can be used for in memory signing, RPC singing, external wallet, HSM, etc. - */ -export declare abstract class Signer { - /** - * Creates new key and returns public key. - */ - abstract createKey(accountId: string, networkId?: string): Promise; - /** - * Returns public key for given account / network. - * @param accountId accountId to retrieve from. - * @param networkId The targeted network. (ex. default, betanet, etc…) - */ - abstract getPublicKey(accountId?: string, networkId?: string): Promise; - /** - * Signs given message, by first hashing with sha256. - * @param message message to sign. - * @param accountId accountId to use for signing. - * @param networkId The targeted network. (ex. default, betanet, etc…) - */ - abstract signMessage(message: Uint8Array, accountId?: string, networkId?: string): Promise; -} -/** - * Signs using in memory key store. - */ -export declare class InMemorySigner extends Signer { - readonly keyStore: KeyStore; - constructor(keyStore: KeyStore); - /** - * Creates a single account Signer instance with account, network and keyPair provided. - * - * Intended to be useful for temporary keys (e.g. claiming a Linkdrop). - * - * @param networkId The targeted network. (ex. default, betanet, etc…) - * @param accountId The NEAR account to assign the key pair to - * @param keyPair The keyPair to use for signing - */ - static fromKeyPair(networkId: string, accountId: string, keyPair: KeyPair): Promise; - /** - * Creates a public key for the account given - * @param accountId The NEAR account to assign a public key to - * @param networkId The targeted network. (ex. default, betanet, etc…) - * @returns {Promise} - */ - createKey(accountId: string, networkId: string): Promise; - /** - * Gets the existing public key for a given account - * @param accountId The NEAR account to assign a public key to - * @param networkId The targeted network. (ex. default, betanet, etc…) - * @returns {Promise} Returns the public key or null if not found - */ - getPublicKey(accountId?: string, networkId?: string): Promise; - /** - * @param message A message to be signed, typically a serialized transaction - * @param accountId the NEAR account signing the message - * @param networkId The targeted network. (ex. default, betanet, etc…) - * @returns {Promise} - */ - signMessage(message: Uint8Array, accountId?: string, networkId?: string): Promise; - toString(): string; -} diff --git a/borsh-ts/test/fuzz/transaction-example/signer.js b/borsh-ts/test/fuzz/transaction-example/signer.js deleted file mode 100644 index 933db3add..000000000 --- a/borsh-ts/test/fuzz/transaction-example/signer.js +++ /dev/null @@ -1,82 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const js_sha256_1 = __importDefault(require("js-sha256")); -const key_pair_1 = require("./key_pair"); -const key_stores_1 = require("./key_stores"); -/** - * General signing interface, can be used for in memory signing, RPC singing, external wallet, HSM, etc. - */ -class Signer { -} -exports.Signer = Signer; -/** - * Signs using in memory key store. - */ -class InMemorySigner extends Signer { - constructor(keyStore) { - super(); - this.keyStore = keyStore; - } - /** - * Creates a single account Signer instance with account, network and keyPair provided. - * - * Intended to be useful for temporary keys (e.g. claiming a Linkdrop). - * - * @param networkId The targeted network. (ex. default, betanet, etc…) - * @param accountId The NEAR account to assign the key pair to - * @param keyPair The keyPair to use for signing - */ - static async fromKeyPair(networkId, accountId, keyPair) { - const keyStore = new key_stores_1.InMemoryKeyStore(); - await keyStore.setKey(networkId, accountId, keyPair); - return new InMemorySigner(keyStore); - } - /** - * Creates a public key for the account given - * @param accountId The NEAR account to assign a public key to - * @param networkId The targeted network. (ex. default, betanet, etc…) - * @returns {Promise} - */ - async createKey(accountId, networkId) { - const keyPair = key_pair_1.KeyPair.fromRandom('ed25519'); - await this.keyStore.setKey(networkId, accountId, keyPair); - return keyPair.getPublicKey(); - } - /** - * Gets the existing public key for a given account - * @param accountId The NEAR account to assign a public key to - * @param networkId The targeted network. (ex. default, betanet, etc…) - * @returns {Promise} Returns the public key or null if not found - */ - async getPublicKey(accountId, networkId) { - const keyPair = await this.keyStore.getKey(networkId, accountId); - if (keyPair === null) { - return null; - } - return keyPair.getPublicKey(); - } - /** - * @param message A message to be signed, typically a serialized transaction - * @param accountId the NEAR account signing the message - * @param networkId The targeted network. (ex. default, betanet, etc…) - * @returns {Promise} - */ - async signMessage(message, accountId, networkId) { - const hash = new Uint8Array(js_sha256_1.default.sha256.array(message)); - if (!accountId) { - throw new Error('InMemorySigner requires provided account id'); - } - const keyPair = await this.keyStore.getKey(networkId, accountId); - if (keyPair === null) { - throw new Error(`Key for ${accountId} not found in ${networkId}`); - } - return keyPair.sign(hash); - } - toString() { - return `InMemorySigner(${this.keyStore})`; - } -} -exports.InMemorySigner = InMemorySigner; diff --git a/borsh-ts/test/fuzz/transaction-example/transaction.d.ts b/borsh-ts/test/fuzz/transaction-example/transaction.d.ts deleted file mode 100644 index bedf27f31..000000000 --- a/borsh-ts/test/fuzz/transaction-example/transaction.d.ts +++ /dev/null @@ -1,106 +0,0 @@ -/// -import BN from 'bn.js'; -import { Enum, Assignable } from './enums'; -import { KeyType, PublicKey } from './key_pair'; -import { Signer } from './signer'; -export declare class FunctionCallPermission extends Assignable { - allowance?: BN; - receiverId: string; - methodNames: string[]; -} -export declare class FullAccessPermission extends Assignable { -} -export declare class AccessKeyPermission extends Enum { - functionCall: FunctionCallPermission; - fullAccess: FullAccessPermission; -} -export declare class AccessKey extends Assignable { - nonce: number; - permission: AccessKeyPermission; -} -export declare function fullAccessKey(): AccessKey; -export declare function functionCallAccessKey(receiverId: string, methodNames: string[], allowance?: BN): AccessKey; -export declare class IAction extends Assignable { -} -export declare class CreateAccount extends IAction { -} -export declare class DeployContract extends IAction { - code: Uint8Array; -} -export declare class FunctionCall extends IAction { - methodName: string; - args: Uint8Array; - gas: BN; - deposit: BN; -} -export declare class Transfer extends IAction { - deposit: BN; -} -export declare class Stake extends IAction { - stake: BN; - publicKey: PublicKey; -} -export declare class AddKey extends IAction { - publicKey: PublicKey; - accessKey: AccessKey; -} -export declare class DeleteKey extends IAction { - publicKey: PublicKey; -} -export declare class DeleteAccount extends IAction { - beneficiaryId: string; -} -export declare function createAccount(): Action; -export declare function deployContract(code: Uint8Array): Action; -/** - * Constructs {@link Action} instance representing contract method call. - * - * @param methodName the name of the method to call - * @param args arguments to pass to method. Can be either plain JS object which gets serialized as JSON automatically - * or `Uint8Array` instance which represents bytes passed as is. - * @param gas max amount of gas that method call can use - * @param deposit amount of NEAR (in yoctoNEAR) to send together with the call - */ -export declare function functionCall(methodName: string, args: Uint8Array | object, gas: BN, deposit: BN): Action; -export declare function transfer(deposit: BN): Action; -export declare function stake(stake: BN, publicKey: PublicKey): Action; -export declare function addKey(publicKey: PublicKey, accessKey: AccessKey): Action; -export declare function deleteKey(publicKey: PublicKey): Action; -export declare function deleteAccount(beneficiaryId: string): Action; -export declare class Signature extends Assignable { - keyType: KeyType; - data: Uint8Array; -} -export declare class Transaction extends Assignable { - signerId: string; - publicKey: PublicKey; - nonce: number; - receiverId: string; - actions: Action[]; - blockHash: Uint8Array; - encode(): Uint8Array; - static decode(bytes: Buffer): Transaction; -} -export declare class SignedTransaction extends Assignable { - transaction: Transaction; - signature: Signature; - encode(): Uint8Array; - static decode(bytes: Buffer): SignedTransaction; -} -/** - * Contains a list of the valid transaction Actions available with this API - */ -export declare class Action extends Enum { - createAccount: CreateAccount; - deployContract: DeployContract; - functionCall: FunctionCall; - transfer: Transfer; - stake: Stake; - addKey: AddKey; - deleteKey: DeleteKey; - deleteAccount: DeleteAccount; -} -export declare const SCHEMA: Map; -export declare function createTransaction(signerId: string, publicKey: PublicKey, receiverId: string, nonce: number, actions: Action[], blockHash: Uint8Array): Transaction; -export declare function signTransaction(transaction: Transaction, signer: Signer, accountId?: string, networkId?: string): Promise<[Uint8Array, SignedTransaction]>; -export declare function signTransaction(receiverId: string, nonce: number, actions: Action[], blockHash: Uint8Array, signer: Signer, accountId?: string, networkId?: string): Promise<[Uint8Array, SignedTransaction]>; diff --git a/borsh-ts/test/fuzz/transaction-example/transaction.js b/borsh-ts/test/fuzz/transaction-example/transaction.js deleted file mode 100644 index a70bcaba7..000000000 --- a/borsh-ts/test/fuzz/transaction-example/transaction.js +++ /dev/null @@ -1,234 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const js_sha256_1 = __importDefault(require("js-sha256")); -const enums_1 = require("./enums"); -const serialize_1 = require("./serialize"); -const key_pair_1 = require("./key_pair"); -class FunctionCallPermission extends enums_1.Assignable { -} -exports.FunctionCallPermission = FunctionCallPermission; -class FullAccessPermission extends enums_1.Assignable { -} -exports.FullAccessPermission = FullAccessPermission; -class AccessKeyPermission extends enums_1.Enum { -} -exports.AccessKeyPermission = AccessKeyPermission; -class AccessKey extends enums_1.Assignable { -} -exports.AccessKey = AccessKey; -function fullAccessKey() { - return new AccessKey({ nonce: 0, permission: new AccessKeyPermission({ fullAccess: new FullAccessPermission({}) }) }); -} -exports.fullAccessKey = fullAccessKey; -function functionCallAccessKey(receiverId, methodNames, allowance) { - return new AccessKey({ nonce: 0, permission: new AccessKeyPermission({ functionCall: new FunctionCallPermission({ receiverId, allowance, methodNames }) }) }); -} -exports.functionCallAccessKey = functionCallAccessKey; -class IAction extends enums_1.Assignable { -} -exports.IAction = IAction; -class CreateAccount extends IAction { -} -exports.CreateAccount = CreateAccount; -class DeployContract extends IAction { -} -exports.DeployContract = DeployContract; -class FunctionCall extends IAction { -} -exports.FunctionCall = FunctionCall; -class Transfer extends IAction { -} -exports.Transfer = Transfer; -class Stake extends IAction { -} -exports.Stake = Stake; -class AddKey extends IAction { -} -exports.AddKey = AddKey; -class DeleteKey extends IAction { -} -exports.DeleteKey = DeleteKey; -class DeleteAccount extends IAction { -} -exports.DeleteAccount = DeleteAccount; -function createAccount() { - return new Action({ createAccount: new CreateAccount({}) }); -} -exports.createAccount = createAccount; -function deployContract(code) { - return new Action({ deployContract: new DeployContract({ code }) }); -} -exports.deployContract = deployContract; -/** - * Constructs {@link Action} instance representing contract method call. - * - * @param methodName the name of the method to call - * @param args arguments to pass to method. Can be either plain JS object which gets serialized as JSON automatically - * or `Uint8Array` instance which represents bytes passed as is. - * @param gas max amount of gas that method call can use - * @param deposit amount of NEAR (in yoctoNEAR) to send together with the call - */ -function functionCall(methodName, args, gas, deposit) { - const anyArgs = args; - const isUint8Array = anyArgs.byteLength !== undefined && anyArgs.byteLength === anyArgs.length; - const serializedArgs = isUint8Array ? args : Buffer.from(JSON.stringify(args)); - return new Action({ functionCall: new FunctionCall({ methodName, args: serializedArgs, gas, deposit }) }); -} -exports.functionCall = functionCall; -function transfer(deposit) { - return new Action({ transfer: new Transfer({ deposit }) }); -} -exports.transfer = transfer; -function stake(stake, publicKey) { - return new Action({ stake: new Stake({ stake, publicKey }) }); -} -exports.stake = stake; -function addKey(publicKey, accessKey) { - return new Action({ addKey: new AddKey({ publicKey, accessKey }) }); -} -exports.addKey = addKey; -function deleteKey(publicKey) { - return new Action({ deleteKey: new DeleteKey({ publicKey }) }); -} -exports.deleteKey = deleteKey; -function deleteAccount(beneficiaryId) { - return new Action({ deleteAccount: new DeleteAccount({ beneficiaryId }) }); -} -exports.deleteAccount = deleteAccount; -class Signature extends enums_1.Assignable { -} -exports.Signature = Signature; -class Transaction extends enums_1.Assignable { - encode() { - return serialize_1.serialize(exports.SCHEMA, this); - } - static decode(bytes) { - return serialize_1.deserialize(exports.SCHEMA, Transaction, bytes); - } -} -exports.Transaction = Transaction; -class SignedTransaction extends enums_1.Assignable { - encode() { - return serialize_1.serialize(exports.SCHEMA, this); - } - static decode(bytes) { - return serialize_1.deserialize(exports.SCHEMA, SignedTransaction, bytes); - } -} -exports.SignedTransaction = SignedTransaction; -/** - * Contains a list of the valid transaction Actions available with this API - */ -class Action extends enums_1.Enum { -} -exports.Action = Action; -exports.SCHEMA = new Map([ - [Signature, { kind: 'struct', fields: [ - ['keyType', 'u8'], - ['data', [64]] - ] }], - [SignedTransaction, { kind: 'struct', fields: [ - ['transaction', Transaction], - ['signature', Signature] - ] }], - [Transaction, { kind: 'struct', fields: [ - ['signerId', 'string'], - ['publicKey', key_pair_1.PublicKey], - ['nonce', 'u64'], - ['receiverId', 'string'], - ['blockHash', [32]], - ['actions', [Action]] - ] }], - [key_pair_1.PublicKey, { kind: 'struct', fields: [ - ['keyType', 'u8'], - ['data', [32]] - ] }], - [AccessKey, { kind: 'struct', fields: [ - ['nonce', 'u64'], - ['permission', AccessKeyPermission], - ] }], - [AccessKeyPermission, { kind: 'enum', field: 'enum', values: [ - ['functionCall', FunctionCallPermission], - ['fullAccess', FullAccessPermission], - ] }], - [FunctionCallPermission, { kind: 'struct', fields: [ - ['allowance', { kind: 'option', type: 'u128' }], - ['receiverId', 'string'], - ['methodNames', ['string']], - ] }], - [FullAccessPermission, { kind: 'struct', fields: [] }], - [Action, { kind: 'enum', field: 'enum', values: [ - ['createAccount', CreateAccount], - ['deployContract', DeployContract], - ['functionCall', FunctionCall], - ['transfer', Transfer], - ['stake', Stake], - ['addKey', AddKey], - ['deleteKey', DeleteKey], - ['deleteAccount', DeleteAccount], - ] }], - [CreateAccount, { kind: 'struct', fields: [] }], - [DeployContract, { kind: 'struct', fields: [ - ['code', ['u8']] - ] }], - [FunctionCall, { kind: 'struct', fields: [ - ['methodName', 'string'], - ['args', ['u8']], - ['gas', 'u64'], - ['deposit', 'u128'] - ] }], - [Transfer, { kind: 'struct', fields: [ - ['deposit', 'u128'] - ] }], - [Stake, { kind: 'struct', fields: [ - ['stake', 'u128'], - ['publicKey', key_pair_1.PublicKey] - ] }], - [AddKey, { kind: 'struct', fields: [ - ['publicKey', key_pair_1.PublicKey], - ['accessKey', AccessKey] - ] }], - [DeleteKey, { kind: 'struct', fields: [ - ['publicKey', key_pair_1.PublicKey] - ] }], - [DeleteAccount, { kind: 'struct', fields: [ - ['beneficiaryId', 'string'] - ] }], -]); -function createTransaction(signerId, publicKey, receiverId, nonce, actions, blockHash) { - return new Transaction({ signerId, publicKey, nonce, receiverId, actions, blockHash }); -} -exports.createTransaction = createTransaction; -/** - * Signs a given transaction from an account with given keys, applied to the given network - * @param transaction The Transaction object to sign - * @param signer The {Signer} object that assists with signing keys - * @param accountId The human-readable NEAR account name - * @param networkId The targeted network. (ex. default, betanet, etc…) - */ -async function signTransactionObject(transaction, signer, accountId, networkId) { - const message = serialize_1.serialize(exports.SCHEMA, transaction); - const hash = new Uint8Array(js_sha256_1.default.sha256.array(message)); - const signature = await signer.signMessage(message, accountId, networkId); - const signedTx = new SignedTransaction({ - transaction, - signature: new Signature({ keyType: transaction.publicKey.keyType, data: signature.signature }) - }); - return [hash, signedTx]; -} -async function signTransaction(...args) { - if (args[0].constructor === Transaction) { - const [transaction, signer, accountId, networkId] = args; - return signTransactionObject(transaction, signer, accountId, networkId); - } - else { - const [receiverId, nonce, actions, blockHash, signer, accountId, networkId] = args; - const publicKey = await signer.getPublicKey(accountId, networkId); - const transaction = createTransaction(accountId, publicKey, receiverId, nonce, actions, blockHash); - return signTransactionObject(transaction, signer, accountId, networkId); - } -} -exports.signTransaction = signTransaction; diff --git a/borsh-ts/test/serialize.test.js b/borsh-ts/test/serialize.test.js deleted file mode 100644 index 1aa0b0f14..000000000 --- a/borsh-ts/test/serialize.test.js +++ /dev/null @@ -1,22 +0,0 @@ -const borsh = require('../../lib/index'); - -class Assignable { - constructor(properties) { - Object.keys(properties).map((key) => { - this[key] = properties[key]; - }); - } -} - -class Test extends Assignable { } - -test('serialize object', async () => { - const value = new Test({ x: 255, y: 20, z: '123', q: [1, 2, 3] }); - const schema = new Map([[Test, { kind: 'struct', fields: [['x', 'u8'], ['y', 'u64'], ['z', 'string'], ['q', [3]]] }]]); - const buf = borsh.serialize(schema, value); - const newValue = borsh.deserialize(schema, Test, buf); - expect(newValue.x).toEqual(255); - expect(newValue.y.toString()).toEqual('20'); - expect(newValue.z).toEqual('123'); - expect(newValue.q).toEqual(new Uint8Array([1, 2, 3])); -}); \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index b6b9ea962..06bd1aa93 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,143 +1,207 @@ - + - + - - + + gtag("config", "UA-148219145-1"); + - - + + - + Borsh - + - - - - - -
- -
-
- -
-
-
-
- -

Borsh, binary serializer for security-critical projects.

-

Borsh stands for Binary Object Representation Serializer for Hashing. It is meant to be - used in security-critical projects - as it prioritizes consistency, safety, speed; and comes with a strict specification. It - optimizes for the following qualities - in the decreasing priority: -

-
-
+
+
+
+
+
+
+
+ +

+ Borsh, binary serializer for security-critical projects. +

+

+ Borsh stands for Binary Object Representation Serializer for + Hashing. It is meant to be used in security-critical + projects as it prioritizes consistency, safety, speed; and + comes with a strict specification. It optimizes for the + following qualities in the decreasing priority: +

+
-
-
-
-
-
Consistency
-
Consistency means there is a bijective mapping between objects and - their binary representations. - There is no two binary representations that deserialize into the same object. - This is extremely useful for applications that use binary representation to compute - hash; -
+
+
+
+
+
+
Consistency
+
+ Consistency means there is a bijective mapping between + objects and their binary representations. There is no two + binary representations that deserialize into the same + object. This is extremely useful for applications that use + binary representation to compute hash; +
-
Safety
-
- Borsh implementations use safe coding practices. In Rust, Borsh uses almost only safe code, - with one exception to avoid exhaustion attack; -
+
Safety
+
+ Borsh implementations use safe coding practices. In Rust, + Borsh uses almost only safe code, with one exception to + avoid exhaustion attack; +
-
Specification
-
- Borsh comes with a full specification that can be used for implementations in other - languages; -
-
Speed
-
- In Rust, Borsh achieves high performance by opting out from Serde - which makes it faster - than bincode in some cases; which also reduces the code - size; -
-
-
- -
+
Specification
+
+ Borsh comes with a full specification that can be used for + implementations in other languages; +
+
Speed
+
+ In Rust, Borsh achieves high performance by opting out from + Serde which makes it faster + than + bincode in + some cases; which also reduces the code size; +
+ +
+
-
-
-
-
-

Example

+
+
+
+
+

Example

+
-
- -
-

+              
+

 use borsh::{BorshSerialize, BorshDeserialize};
 
 #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)]
@@ -157,253 +221,342 @@ 

Example

assert_eq!(a, decoded_a); }
-
-
-

Opting out from Serde allows borsh to have some features that currently are not available for serde-compatible serializers. - Currently we support two features: borsh_init and borsh_skip (the former one not available in Serde). See - https://github.com/nearprotocol/borsh -

-
-
+
+
+

+ Opting out from Serde allows borsh to have some features that + currently are not available for serde-compatible serializers. + Currently we support two features: borsh_init and + borsh_skip (the former one not available in + Serde). See + https://github.com/nearprotocol/borsh +

+
+
-
-
+
+
+
+
+

Benchmarks

+

+ We measured the following benchmarks on objects that + blockchain projects care about the most: blocks, block + headers, transactions, accounts. We took object structure from + the + nearprotocol + blockchain. We used + Criterion + for building the following graphs. The benchmarks were run on + Google Cloud + n1-standard-2 (2 vCPUs, 7.5 GB memory). Note, size only roughly corresponds to the serialization + complexity which causes non-smoothness of the graph. +

+

+ See complete report + here. +

-
-

Benchmarks

-

We measured the following benchmarks on objects that blockchain projects care about the most: blocks, block headers, - transactions, accounts. We took object structure from the nearprotocol blockchain. - We used Criterion for building the following graphs. - The benchmarks were run on Google Cloud n1-standard-2 (2 vCPUs, 7.5 GB memory). - Note, size only roughly corresponds to the serialization complexity which causes non-smoothness of the graph. - -

-

- See complete report here. -

-
-
- Block header serialization speed vs block header size in bytes: - -
-
-
-
- Block header de-serialization speed vs block header size in bytes: - -
-
-
-
- Block serialization speed vs block size in bytes: - -
-
-
-
- Block de-serialization speed vs block size in bytes: - -
-
-
+
+ Block header serialization speed vs block header size in + bytes: + +
+
+
+ Block header de-serialization speed vs block header size in + bytes: + +
-
-
-
-
-
-

Specification

-

In short, Borsh is a non self-describing binary serialization format. It is designed to - serialize any objects to canonical and deterministic set of bytes.

- General principles: -
    -
  • integers are little endian;
  • -
  • sizes of dynamic containers are written before values as u32;
  • -
  • all unordered containers (hashmap/hashset) are ordered in lexicographic order by key (in - tie breaker case on value); -
  • -
  • structs are serialized in the order of fields in the struct;
  • -
  • enums are serialized with using u8 for the enum ordinal and then storing data inside the - enum value (if present). -
  • -
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Informal typeRust EBNF *Pseudocode
Integersinteger_type: ["u8" | "u16" | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" - | "i128" ] - little_endian(x)
Floatsfloat_type: ["f32" | "f64" ]err_if_nan(x)
little_endian(x as integer_type)
Unitunit_type: "()"We do not write anything
Fixed sized arraysarray_type: '[' ident ';' literal ']'for el in x
  repr(el as ident)
Dynamic sized arrayvec_type: "Vec<" ident '>'repr(len() as u32)
- for el in x
-   repr(el as ident) -
Structstruct_type: "struct" ident fieldsrepr(fields)
Fieldsfields: [named_fields | unnamed_fields]
Named fieldsnamed_fields: '{' ident_field0 ':' ident_type0 ',' ident_field1 ':' ident_type1 ',' - ... '}' - repr(ident_field0 as ident_type0)
- repr(ident_field1 as ident_type1)
- ... -
Unnamed fieldsunnamed_fields: '(' ident_type0 ',' ident_type1 ',' ... ')'repr(x.0 as type0)
repr(x.1 as type1)
...
Enumenum: 'enum' ident '{' variant0 ',' variant1 ',' ... '}'
- variant: ident [ fields ] ? -
Suppose X is the number of the variant that the enum takes.
- repr(X as u8)
- repr(x.X as fieldsX) -
HashMaphashmap: "HashMap<" ident0, ident1 ">" - repr(x.len() as u32)
- for (k, v) in x.sorted_by_key() {
-   repr(k as ident0)
-   repr(v as ident1)
- } -
HashSethashset: "HashSet<" ident ">" - repr(x.len() as u32)
- for el in x.sorted() {
-  repr(el as ident)
- } -
Optionoption_type: "Option<" ident '>' if x.is_some() {
-   repr(1 as u8)
-   repr(x.unwrap() as ident)
- } else {
-   repr(0 as u8)
- } -
Stringstring_type: "String" encoded = utf8_encoding(x) as Vec<u8>
- repr(encoded.len() as u32)
- repr(encoded as Vec<u8>) -
-
+
+ Block serialization speed vs block size in bytes: + +
+
+
+ Block de-serialization speed vs block size in bytes: + +
+
+
-
- +
+
+
+
+

Specification

+

+ In short, Borsh is a non self-describing binary serialization + format. It is designed to serialize any objects to canonical + and deterministic set of bytes. +

+ General principles: +
    +
  • integers are little endian;
  • +
  • + sizes of dynamic containers are written before values as + u32; +
  • +
  • + all unordered containers (hashmap/hashset) are ordered in + lexicographic order by key (in tie breaker case on value); +
  • +
  • + structs are serialized in the order of fields in the struct; +
  • +
  • + enums are serialized with using u8 for the enum ordinal and + then storing data inside the enum value (if present). +
  • +
+
-
-
-
-

Borsch or Borscht is an extremely tasty sour soup common in Eastern Europe and Northern Asia. - The primary ingredients are beetroots or tomatoes that give the dish its distinctive red color.

- -

The similarity between the name of the serializer and the fact that many members of the development team - are extreme fans of this savory dish is entirely coincidental.

-
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Informal type + Rust EBNF + + * + Pseudocode
Integers + integer_type: ["u8" | "u16" | "u32" | "u64" | "u128" | + "i8" | "i16" | "i32" | "i64" | "i128" ] + little_endian(x)
Floatsfloat_type: ["f32" | "f64" ]err_if_nan(x)
little_endian(x as integer_type)
Unitunit_type: "()"We do not write anything
Fixed sized arraysarray_type: '[' ident ';' literal ']'for el in x
  repr(el as ident)
Dynamic sized arrayvec_type: "Vec<" ident '>' + repr(len() as u32)
+ for el in x
+   repr(el as ident) +
Structstruct_type: "struct" ident fieldsrepr(fields)
Fieldsfields: [named_fields | unnamed_fields]
Named fields + named_fields: '{' ident_field0 ':' ident_type0 ',' + ident_field1 ':' ident_type1 ',' ... '}' + + repr(ident_field0 as ident_type0)
+ repr(ident_field1 as ident_type1)
+ ... +
Unnamed fields + unnamed_fields: '(' ident_type0 ',' ident_type1 ',' ... + ')' + repr(x.0 as type0)
repr(x.1 as type1)
...
Enum + enum: 'enum' ident '{' variant0 ',' variant1 ',' ... + '}'
+ variant: ident [ fields ] ? +
+ Suppose X is the number of the variant that the enum + takes.
+ repr(X as u8)
+ repr(x.X as fieldsX) +
HashMaphashmap: "HashMap<" ident0, ident1 ">" + repr(x.len() as u32)
+ for (k, v) in x.sorted_by_key() {
+   repr(k as ident0)
+   repr(v as ident1)
+ } +
HashSethashset: "HashSet<" ident ">" + repr(x.len() as u32)
+ for el in x.sorted() {
+  repr(el as ident)
+ } +
Optionoption_type: "Option<" ident '>' + if x.is_some() {
+   repr(1 as u8)
+   repr(x.unwrap() as ident)
+ } else {
+   repr(0 as u8)
+ } +
Stringstring_type: "String" + encoded = utf8_encoding(x) as Vec<u8>
+ repr(encoded.len() as u32)
+ repr(encoded as Vec<u8>) +
+
+
+
+
+
+
+
+
+

+ Borsch or Borscht + is an extremely tasty sour soup common in Eastern Europe and + Northern Asia. The primary ingredients are beetroots or + tomatoes that give the dish its distinctive red color. +

-
-
-
- Ukrainian Borscht -
-
+

+ The similarity between the name of the serializer and the fact + that many members of the development team are extreme fans of + this savory dish is entirely coincidental. +

+
+
+
+
+ Ukrainian Borscht +
+
-
+
-
-
+
+
- + - - - - - - + + + + + + diff --git a/lib/index.d.ts b/lib/index.d.ts deleted file mode 100644 index b798d1360..000000000 --- a/lib/index.d.ts +++ /dev/null @@ -1,39 +0,0 @@ -/// -import BN from 'bn.js'; -export declare type Schema = Map; -export declare class BorshError extends Error { - originalMessage: string; - fieldPath: string[]; - constructor(message: string); - addToFieldPath(fieldName: string): void; -} -export declare class BinaryWriter { - buf: Buffer; - length: number; - constructor(); - maybeResize(): void; - writeU8(value: number): void; - writeU32(value: number): void; - writeU64(value: BN): void; - writeU128(value: BN): void; - private writeBuffer; - writeString(str: string): void; - writeFixedArray(array: Uint8Array): void; - writeArray(array: any[], fn: any): void; - toArray(): Uint8Array; -} -export declare class BinaryReader { - buf: Buffer; - offset: number; - constructor(buf: Buffer); - readU8(): number; - readU32(): number; - readU64(): BN; - readU128(): BN; - private readBuffer; - readString(): string; - readFixedArray(len: number): Uint8Array; - readArray(fn: any): any[]; -} -export declare function serialize(schema: Schema, obj: any): Uint8Array; -export declare function deserialize(schema: Schema, classType: any, buffer: Buffer): any; diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index 8aa0286a9..000000000 --- a/lib/index.js +++ /dev/null @@ -1,331 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.deserialize = exports.serialize = exports.BinaryReader = exports.BinaryWriter = exports.BorshError = void 0; -const bn_js_1 = __importDefault(require("bn.js")); -// TODO: Make sure this polyfill not included when not required -const encoding = __importStar(require("text-encoding-utf-8")); -const TextDecoder = (typeof global.TextDecoder !== 'function') ? encoding.TextDecoder : global.TextDecoder; -const textDecoder = new TextDecoder('utf-8', { fatal: true }); -const INITIAL_LENGTH = 1024; -class BorshError extends Error { - constructor(message) { - super(message); - this.fieldPath = []; - this.originalMessage = message; - } - addToFieldPath(fieldName) { - this.fieldPath.splice(0, 0, fieldName); - // NOTE: Modifying message directly as jest doesn't use .toString() - this.message = this.originalMessage + ': ' + this.fieldPath.join('.'); - } -} -exports.BorshError = BorshError; -/// Binary encoder. -class BinaryWriter { - constructor() { - this.buf = Buffer.alloc(INITIAL_LENGTH); - this.length = 0; - } - maybeResize() { - if (this.buf.length < 16 + this.length) { - this.buf = Buffer.concat([this.buf, Buffer.alloc(INITIAL_LENGTH)]); - } - } - writeU8(value) { - this.maybeResize(); - this.buf.writeUInt8(value, this.length); - this.length += 1; - } - writeU32(value) { - this.maybeResize(); - this.buf.writeUInt32LE(value, this.length); - this.length += 4; - } - writeU64(value) { - this.maybeResize(); - this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray('le', 8))); - } - writeU128(value) { - this.maybeResize(); - this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray('le', 16))); - } - writeBuffer(buffer) { - // Buffer.from is needed as this.buf.subarray can return plain Uint8Array in browser - this.buf = Buffer.concat([Buffer.from(this.buf.subarray(0, this.length)), buffer, Buffer.alloc(INITIAL_LENGTH)]); - this.length += buffer.length; - } - writeString(str) { - this.maybeResize(); - const b = Buffer.from(str, 'utf8'); - this.writeU32(b.length); - this.writeBuffer(b); - } - writeFixedArray(array) { - this.writeBuffer(Buffer.from(array)); - } - writeArray(array, fn) { - this.maybeResize(); - this.writeU32(array.length); - for (const elem of array) { - this.maybeResize(); - fn(elem); - } - } - toArray() { - return this.buf.subarray(0, this.length); - } -} -exports.BinaryWriter = BinaryWriter; -function handlingRangeError(target, propertyKey, propertyDescriptor) { - const originalMethod = propertyDescriptor.value; - propertyDescriptor.value = function (...args) { - try { - return originalMethod.apply(this, args); - } - catch (e) { - if (e instanceof RangeError) { - const code = e.code; - if (['ERR_BUFFER_OUT_OF_BOUNDS', 'ERR_OUT_OF_RANGE'].indexOf(code) >= 0) { - throw new BorshError('Reached the end of buffer when deserializing'); - } - } - throw e; - } - }; -} -class BinaryReader { - constructor(buf) { - this.buf = buf; - this.offset = 0; - } - readU8() { - const value = this.buf.readUInt8(this.offset); - this.offset += 1; - return value; - } - readU32() { - const value = this.buf.readUInt32LE(this.offset); - this.offset += 4; - return value; - } - readU64() { - const buf = this.readBuffer(8); - return new bn_js_1.default(buf, 'le'); - } - readU128() { - const buf = this.readBuffer(16); - return new bn_js_1.default(buf, 'le'); - } - readBuffer(len) { - if ((this.offset + len) > this.buf.length) { - throw new BorshError(`Expected buffer length ${len} isn't within bounds`); - } - const result = this.buf.slice(this.offset, this.offset + len); - this.offset += len; - return result; - } - readString() { - const len = this.readU32(); - const buf = this.readBuffer(len); - try { - // NOTE: Using TextDecoder to fail on invalid UTF-8 - return textDecoder.decode(buf); - } - catch (e) { - throw new BorshError(`Error decoding UTF-8 string: ${e}`); - } - } - readFixedArray(len) { - return new Uint8Array(this.readBuffer(len)); - } - readArray(fn) { - const len = this.readU32(); - const result = Array(); - for (let i = 0; i < len; ++i) { - result.push(fn()); - } - return result; - } -} -__decorate([ - handlingRangeError -], BinaryReader.prototype, "readU8", null); -__decorate([ - handlingRangeError -], BinaryReader.prototype, "readU32", null); -__decorate([ - handlingRangeError -], BinaryReader.prototype, "readU64", null); -__decorate([ - handlingRangeError -], BinaryReader.prototype, "readU128", null); -__decorate([ - handlingRangeError -], BinaryReader.prototype, "readString", null); -__decorate([ - handlingRangeError -], BinaryReader.prototype, "readFixedArray", null); -__decorate([ - handlingRangeError -], BinaryReader.prototype, "readArray", null); -exports.BinaryReader = BinaryReader; -function capitalizeFirstLetter(string) { - return string.charAt(0).toUpperCase() + string.slice(1); -} -function serializeField(schema, fieldName, value, fieldType, writer) { - try { - // TODO: Handle missing values properly (make sure they never result in just skipped write) - if (typeof fieldType === 'string') { - writer[`write${capitalizeFirstLetter(fieldType)}`](value); - } - else if (fieldType instanceof Array) { - if (typeof fieldType[0] === 'number') { - if (value.length !== fieldType[0]) { - throw new BorshError(`Expecting byte array of length ${fieldType[0]}, but got ${value.length} bytes`); - } - writer.writeFixedArray(value); - } - else { - writer.writeArray(value, (item) => { serializeField(schema, fieldName, item, fieldType[0], writer); }); - } - } - else if (fieldType.kind !== undefined) { - switch (fieldType.kind) { - case 'option': { - if (value === null) { - writer.writeU8(0); - } - else { - writer.writeU8(1); - serializeField(schema, fieldName, value, fieldType.type, writer); - } - break; - } - default: throw new BorshError(`FieldType ${fieldType} unrecognized`); - } - } - else { - serializeStruct(schema, value, writer); - } - } - catch (error) { - if (error instanceof BorshError) { - error.addToFieldPath(fieldName); - } - throw error; - } -} -function serializeStruct(schema, obj, writer) { - const structSchema = schema.get(obj.constructor); - if (!structSchema) { - throw new BorshError(`Class ${obj.constructor.name} is missing in schema`); - } - if (structSchema.kind === 'struct') { - structSchema.fields.map(([fieldName, fieldType]) => { - serializeField(schema, fieldName, obj[fieldName], fieldType, writer); - }); - } - else if (structSchema.kind === 'enum') { - const name = obj[structSchema.field]; - for (let idx = 0; idx < structSchema.values.length; ++idx) { - const [fieldName, fieldType] = structSchema.values[idx]; - if (fieldName === name) { - writer.writeU8(idx); - serializeField(schema, fieldName, obj[fieldName], fieldType, writer); - break; - } - } - } - else { - throw new BorshError(`Unexpected schema kind: ${structSchema.kind} for ${obj.constructor.name}`); - } -} -/// Serialize given object using schema of the form: -/// { class_name -> [ [field_name, field_type], .. ], .. } -function serialize(schema, obj) { - const writer = new BinaryWriter(); - serializeStruct(schema, obj, writer); - return writer.toArray(); -} -exports.serialize = serialize; -function deserializeField(schema, fieldName, fieldType, reader) { - try { - if (typeof fieldType === 'string') { - return reader[`read${capitalizeFirstLetter(fieldType)}`](); - } - if (fieldType instanceof Array) { - if (typeof fieldType[0] === 'number') { - return reader.readFixedArray(fieldType[0]); - } - return reader.readArray(() => deserializeField(schema, fieldName, fieldType[0], reader)); - } - return deserializeStruct(schema, fieldType, reader); - } - catch (error) { - if (error instanceof BorshError) { - error.addToFieldPath(fieldName); - } - throw error; - } -} -function deserializeStruct(schema, classType, reader) { - const structSchema = schema.get(classType); - if (!structSchema) { - throw new BorshError(`Class ${classType.name} is missing in schema`); - } - if (structSchema.kind === 'struct') { - const result = {}; - for (const [fieldName, fieldType] of schema.get(classType).fields) { - result[fieldName] = deserializeField(schema, fieldName, fieldType, reader); - } - return new classType(result); - } - if (structSchema.kind === 'enum') { - const idx = reader.readU8(); - if (idx >= structSchema.values.length) { - throw new BorshError(`Enum index: ${idx} is out of range`); - } - const [fieldName, fieldType] = structSchema.values[idx]; - const fieldValue = deserializeField(schema, fieldName, fieldType, reader); - return new classType({ [fieldName]: fieldValue }); - } - throw new BorshError(`Unexpected schema kind: ${structSchema.kind} for ${classType.constructor.name}`); -} -/// Deserializes object from bytes using schema. -function deserialize(schema, classType, buffer) { - const reader = new BinaryReader(buffer); - const result = deserializeStruct(schema, classType, reader); - if (reader.offset < buffer.length) { - throw new BorshError(`Unexpected ${buffer.length - reader.offset} bytes after deserialized data`); - } - return result; -} -exports.deserialize = deserialize; diff --git a/package.json b/package.json deleted file mode 100644 index 342a2bc9f..000000000 --- a/package.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "borsh", - "version": "0.3.0", - "description": "Binary Object Representation Serializer for Hashing", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "scripts": { - "build": "tsc -p ./tsconfig.json", - "test": "jest test --runInBand", - "fuzz": "jsfuzz borsh-ts/test/fuzz/borsh-roundtrip.js borsh-ts/test/fuzz/corpus/", - "dev": "yarn build -w", - "pretest": "yarn build", - "lint": "eslint borsh-ts/**/*.ts", - "fix": "eslint borsh-ts/**/*.ts --fix" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/nearprotocol/borsh.git" - }, - "keywords": [ - "serializer", - "binary", - "serializer", - "deserializer", - "consistency", - "determenistic" - ], - "author": "Near Inc", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/nearprotocol/borsh/issues" - }, - "homepage": "https://github.com/nearprotocol/borsh#readme", - "devDependencies": { - "@types/babel__core": "^7.1.2", - "@types/babel__template": "^7.0.2", - "@types/node": "^12.7.3", - "@typescript-eslint/eslint-plugin": "^2.18.0", - "@typescript-eslint/parser": "^2.18.0", - "eslint": "^6.5.1", - "jest": "^26.0.1", - "jsfuzz": "^1.0.14", - "typescript": "^3.6.2", - "bs58": "^4.0.0", - "js-sha256": "^0.9.0" - }, - "dependencies": { - "@types/bn.js": "^4.11.5", - "bn.js": "^5.0.0", - "text-encoding-utf-8": "^1.0.2" - } -} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index fe2ec2d13..000000000 --- a/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "esModuleInterop": true, - "lib": [ - "es2015", - "esnext", - "dom" - ], - "module": "commonjs", - "target": "esnext", - "moduleResolution": "node", - "outDir": "./lib", - "declaration": true, - "preserveSymlinks": true, - "preserveWatchOutput": true, - "pretty": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "noImplicitAny": false, - "noImplicitReturns": true, - "experimentalDecorators": true, - "noUnusedLocals": true - }, - "files": ["./borsh-ts/index.ts"] -} -