Skip to content

Commit

Permalink
chore: release 1.0.0 (#240)
Browse files Browse the repository at this point in the history
  • Loading branch information
dj8yfo authored Oct 6, 2023
1 parent 773827c commit 6e7fc28
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 28 deletions.
139 changes: 139 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,145 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.0.0](https://github.com/near/borsh-rs/compare/borsh-v0.10.3...borsh-v1.0.0) - 2023-10-03

> The year is 2653 and the best yet-to-be citizens of the Terran Federation are fighting
> and mostly just dying in a relentless interstellar war against the Arachnids.
> Yet the structure of our society has changed through the course of this confrontation.
>
> The members of the Arachnid brain caste and queens have infiltrated the circles of our
> most influential political and industrial leaders. Either directly, or via the Arachnid technology
> called "Brain Bugs". This tech alone can accomplish what the Arachnid starship paratroopers
> will not ever be capable to do.
>
> Simple, straightforward and performant serialization libraries can set us in course to remedy this dangerous
> stalemate situation by cleaning the minds of its users from even the tiniest of Brain Bugs.
Robert A. Heinlein, 1959 (a newspaper ad)
---

### [Thanks]

`borsh-rs` `1.0.0` release was first conceived and then brought into existence by minds of:

- Amirhossein Akhlaghpour @Mehrbod2002
- Benji Smith @Benjins
- dj8yf0μl @dj8yfo
- iho @iho
- Jacob Lindahl @encody
- Pavel Lazureykis @lazureykis
- Tomas Zemanovic @tzemanovic

Contributors, who imposed powerful impact on the past, present and future of this library are specially recognized:

- Michal Nazarewicz @mina86 - for revisiting `BorshSchema` feature, rethinking it, bringing up great ideas and coming up with the
fairly involved algorithm of `max_serialized_size` implementation.
- Alex Kladov @matklad - for maintaining a superhuman ability of context switching in under 2 minutes and scanning through 15k lines of code
in under 10 minutes, while leaving out under 1% relevant details.
- Marco Ieni @MarcoIeni - for developing [release-plz](https://github.com/MarcoIeni/release-plz) automation.
- Vlad Frolov @frol - for keeping an eye on the big picture and striking just the right balance between
performance and versatility, ease of use and extensibility and tons of other such hard to reconcile pairs.

### [Migration guides]

This section contains links to short documents, describing problems encountered during update of `borsh`
version to `v1.0.0` for related repositories.

- [v0.10.2 -> v1.0.0 for `nearcore`](./docs/migration_guides/v0.10.2_to_v1.0.0_nearcore.md)
- [v0.9.3 -> v1.0.0 for `near-sdk-rs`](./docs/migration_guides/v0.9_to_v1.0.0_near_sdk_rs.md)

### [Summary of changes]

- Library's structure was made more modular and optimized with respect to visibility
of its public/private constituents and ease of access to them.
- `borsh`'s traits derives and their attributes had their capabilities extended and unified,
both with respect to external interfaces and internal implementation. Please visit [borsh_derive](https://docs.rs/borsh-derive/1.0.0/borsh_derive/)
documentation pages if you're interested in more of the details.
- The consistency property of deserialization, declared in [Borsh Specification](https://borsh.io/), became an
opt-in feature `de_strict_order` for hash collections.
- Support of explicit enum discriminants was added to derives of `borsh` traits.
It has been added in somewhat limited form, only allowing the values of `u8` range literals.

```rust
use borsh::{BorshSerialize, BorshDeserialize, BorshSchema};

<<<<<<< borsh-v0.10.3
#[derive(BorshDeserialize, BorshSerialize, BorshSchema)]
pub enum CurveType {
ED25519 = 0, // 0 as u8 in enum tag
SECP256K1 = 2, // 1 as u8 in enum tag
}
=======
#[derive(BorshDeserialize, BorshSerialize, BorshSchema)]
#[borsh(use_discriminant=false)]
pub enum CurveType {
ED25519 = 0, // 0 as u8 in enum tag
SECP256K1 = 2, // 1 as u8 in enum tag
}
// vs
#[derive(BorshDeserialize, BorshSerialize, BorshSchema)]
#[borsh(use_discriminant=true)]
pub enum CurveType {
ED25519 = 0, // 0 as u8 in enum tag
SECP256K1 = 2, // 2 as u8 in enum tag
}
>>>>>>> borsh-v1.0.0
```
- [RUSTSEC-2023-0033](https://rustsec.org/advisories/RUSTSEC-2023-0033.html) has been resolved.
It has been resolved by forbidding collections with dynamic runtime length to contain zero-sized types
with runtime errors, happening on serialization or deserialization.
Arrays with non-`Copy` and non-`Clone` ZST singletons of length > 1 gracefully panic on deserialization,
not causing memory faults.

Using collections with dynamic runtime length ([tagged sequences](https://docs.rs/borsh/1.0.0/borsh/schema/enum.Definition.html#variant.Sequence)) for containing ZSTs was also deemed
wasteful of CPU cycles and a way to perform dos attacks.
Such a case is now flagged as error when using new [`BorshSchemaContainer::validate`](https://docs.rs/borsh/1.0.0/borsh/schema/struct.BorshSchemaContainer.html#method.validate) method for user-defined
types or instantiations of `BorshSchema`-supporting types with inappropriate parameters, defined by the library:

```rust
let schema = BorshSchemaContainer::for_type::<Vec<core::ops::RangeFull>>();
assert_eq!(
Err(
SchemaContainerValidateError::ZSTSequence("Vec<RangeFull>".to_string())
),
schema.validate()
);
```
- `BorshSchema` was extended with [`max_serialized_size`](https://docs.rs/borsh/1.0.0/borsh/fn.max_serialized_size.html) implementation, which now unlocks support of `borsh`
by a plethora of bounded types to express statically defined size limits of serialized representation of these types.
- schema [`BorshSchemaContainer`](https://docs.rs/borsh/1.0.0/borsh/schema/struct.BorshSchemaContainer.html#impl-BorshSchemaContainer-2) api was made future-proof.
- schema [`Definition`](https://docs.rs/borsh/1.0.0/borsh/schema/enum.Definition.html#) was extended with more variants, fields and details to uncover some of the
implied details of serialization format.
`BorshSchema` can now express a wider range of types. All types, which have `BorshSchema` defined by the library,
now have a `Definition`.
- schema `Declaration`-s were renamed to follow Rust-first rule and not be a mix of Rust types naming/syntax and syntax
from other languages.

```rust
use borsh::schema::BorshSchema;

<<<<<<< borsh-v0.10.3
assert_eq!("nil", <()>::declaration());
assert_eq!("string", <String>::declaration());
assert_eq!("Array<u64, 42>", <[u64; 42]>::declaration());
assert_eq!("Tuple<u8, bool, f32>", <(u8, bool, f32)>::declaration());
=======
assert_eq!("()", <()>::declaration());
assert_eq!("String", <String>::declaration());
assert_eq!("[u64; 42]", <[u64; 42]>::declaration());
assert_eq!("(u8, bool, f32)", <(u8, bool, f32)>::declaration());
>>>>>>> borsh-v1.0.0
```

### [Stability guarantee]

- `borsh`'s serialization format is guaranteed to NOT change throughout 1.x releases.
- `borsh`'s public APIs not gated by `unstable__schema` feature are guaranteed to NOT break
throughout 1.x releases.
- It's perceived, that new feature requests may potentially come for `BorshSchema` from outside of `near` ecosystem,
thus `borsh`'s public APIs gated by `unstable__schema` MAY break throughout 1.x releases.


## [1.0.0-alpha.6](https://github.com/near/borsh-rs/compare/borsh-v1.0.0-alpha.5...borsh-v1.0.0-alpha.6) - 2023-10-02

### Added
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ members = ["borsh", "borsh-derive", "fuzz/fuzz-run", "benchmarks"]

[workspace.package]
# shared version of all public crates in the workspace
version = "1.0.0-alpha.6"
version = "1.0.0"
rust-version = "1.66.0"
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn test_simple_struct() {
## 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=<your initilization method name>` and `borsh(skip)` (the former one not available in Serde).
Currently we support two features: `borsh(init=<your initialization method name>` 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:

Expand All @@ -65,7 +65,7 @@ impl Message {
}
```

`borsh(skip)` allows to skip serializing/deserializing fields, assuming they implement `Default` trait, similary to `#[serde(skip)]`.
`borsh(skip)` allows to skip serializing/deserializing fields, assuming they implement `Default` trait, similarly to `#[serde(skip)]`.

```rust
#[derive(BorshSerialize, BorshDeserialize)]
Expand Down
2 changes: 1 addition & 1 deletion borsh-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ where
Each of `declaration` and `definitions` nested sub-attributes takes literal string value, which is a syn's [ExprPath](syn::ExprPath).
Currently both `declaration` and `definitions` are required to be specifed at the same time.
Currently both `declaration` and `definitions` are required to be specified at the same time.
###### usage
Expand Down
2 changes: 1 addition & 1 deletion borsh/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ required-features = ["std", "unstable__schema"]
cfg_aliases = "0.1.0"

[dependencies]
borsh-derive = { path = "../borsh-derive", version = "1.0.0-alpha.6", optional = true }
borsh-derive = { path = "../borsh-derive", version = "~1.0.0", optional = true }

# hashbrown can be used in no-std context.
# NOTE: There is no reason to restrict use of older versions, but we don't want to get
Expand Down
21 changes: 7 additions & 14 deletions borsh/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! * `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<u64, String>`;
//! * `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.
//! * `BorshSchemaContainer` is used to store all declarations and definitions 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)]`.
Expand Down Expand Up @@ -42,15 +42,6 @@ pub type FieldName = String;
/// The type that we use to represent the definition of the Borsh type.
/// Description of data encoding on the wire.
///
/// Note: Since at the end of the day users can define arbitrary serialisation,
/// it’s not always possible to express using definitions how a type is encoded.
/// For example, let’s say programmer uses [varint] encoding for their data.
/// Such type cannot be fully expressed using `BorshSchema` (or at least not
/// easily). As a consequence, a tool which validates whether binary data
/// matches a schema wouldn’t be able to validate data including such types.
///
/// [varint]: https://en.wikipedia.org/wiki/Variable-length_quantity#Variants
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize, BorshSchemaMacro)]
pub enum Definition {
/// A fixed-size type, which is considered undivisible
Expand Down Expand Up @@ -121,6 +112,7 @@ pub enum Definition {
tag_width: u8,

/// Possible variants of the enumeration.
/// `VariantName` is metadata, not present in a type's serialized representation.
variants: Vec<(DiscriminantValue, VariantName, Declaration)>,
},

Expand Down Expand Up @@ -150,11 +142,12 @@ impl Definition {
/// The collection representing the fields of a struct.
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize, BorshSchemaMacro)]
pub enum Fields {
/// The struct with named fields.
/// The struct with named fields, structurally identical to a tuple.
/// `FieldName` is metadata, not present in a type's serialized representation.
NamedFields(Vec<(FieldName, Declaration)>),
/// The struct with unnamed fields, structurally identical to a tuple.
UnnamedFields(Vec<Declaration>),
/// The struct with no fields.
/// The struct with no fields, structurally identical to an empty tuple.
Empty,
}

Expand Down Expand Up @@ -268,8 +261,8 @@ pub fn add_definition(
/// 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.
/// Recursively, using DFS, add type definitions required for this type.
/// Type definition partially explains how to serialize/deserialize a type.
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>);

/// Get the name of the type without brackets.
Expand Down
8 changes: 1 addition & 7 deletions borsh/src/schema/container_ext/max_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,10 @@ const ONE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(1) };
impl BorshSchemaContainer {
/// Returns the largest possible size of a serialised object based solely on its type.
///
/// The function has limitations which may lead it to overestimate the size.
/// For example, hypothetical `IPv4Packet` would be encoded as at most ~64 KiB.
/// However, if it uses sequence schema, this function will claim that the
/// maximum size is ~4 GiB.
///
/// Even when if returned upper bound is correct, the theoretical value may be
/// *much* larger than any practical length. For example, maximum encoded
/// length of `String` is 4 GiB while in practice one may encounter strings of
/// at most dozen of characters. Depending on usage, caller should apply upper
/// bound on the result.
/// at most dozen of characters.
///
/// # Example
///
Expand Down
2 changes: 1 addition & 1 deletion borsh/src/schema/container_ext/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub enum Error {
/// Declared tag width is too small. Tags must be large enough to represent
/// possible length of sequence.
TagTooNarrow(Declaration),
/// only 0, 1, 2, 4 and 8 bytes long enum tags and sequences' `length_width` are alowed
/// only 0, 1, 2, 4 and 8 bytes long sequences' `length_width` are allowed
TagNotPowerOfTwo(Declaration),
/// Some of the declared types were lacking definition, which is considered
/// a container's validation error
Expand Down
2 changes: 1 addition & 1 deletion docs/migration_guides/v0.9_to_v1.0.0_near_sdk_rs.md
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ index 834fc98..7d1df75 100644
which would transform into following bound on trait's implementation:
```rust
// line with `T: core::default::Default,` dissappeared
// line with `T: core::default::Default,` disappeared
impl<T> borsh::de::BorshDeserialize for IndexMap<T>
where
T: BorshSerialize,
Expand Down

0 comments on commit 6e7fc28

Please sign in to comment.