The link to near-sdk-rs
pr is chore: borsh version update
Steps:
First we update to 1.0.0-alpha.5
version, which contains deprecation of BorshSerialize::try_to_vec
method.
We enable derive
feature by default, and make unstable__schema
feature optional, enabled
depending on whether abi
feature of near-sdk
package is enabled or not.
diff --git a/near-sdk/Cargo.toml b/near-sdk/Cargo.toml
index a015a64..e6099d4 100644
--- a/near-sdk/Cargo.toml
+++ b/near-sdk/Cargo.toml
@@ -26,3 +26,3 @@ near-sys = { path = "../near-sys", version = "0.2" }
base64 = "0.13"
-borsh = { version = "0.9", features = ["const-generics"] }
+borsh = { version = "=1.0.0-alpha.5", features = ["derive"] }
bs58 = "0.4"
@@ -35,3 +35,4 @@ once_cell = { version = "1.17", default-features = false }
@@ -58,3 +59,3 @@ unstable = []
legacy = []
-abi = ["near-abi", "schemars", "near-sdk-macros/abi"]
+abi = ["borsh/unstable__schema", "near-abi", "schemars", "near-sdk-macros/abi"]
unit-testing = ["near-vm-logic", "near-primitives-core", "near-primitives", "near-crypto"]
2. We receive a great number of deprecation warnings of borsh::BorshSerialize::try_to_vec
method (near-sdk
package):
2 warning: use of deprecated method `borsh::BorshSerialize::try_to_vec`: use `borsh::to_vec(&object)` instead
--> near-sdk/src/store/lazy/mod.rs:43:28
|
43 | let serialized = value.try_to_vec().unwrap_or_else(|_| env::panic_str(ERR_VALUE_SERIALIZATION));
| ^^^^^^^^^^
|
= note: `#[warn(deprecated)]` on by default
We choose to fix it at once, as this method is removed in 1.0.0-alpha.5
-> 1.0.0
transition completely
with following diff:
diff --git a/near-sdk/src/store/lazy/mod.rs b/near-sdk/src/store/lazy/mod.rs
index 7df7ee4..42112ea 100644
--- a/near-sdk/src/store/lazy/mod.rs
+++ b/near-sdk/src/store/lazy/mod.rs
@@ -8,3 +8,3 @@ mod impls;
-use borsh::{BorshDeserialize, BorshSerialize};
+use borsh::{BorshDeserialize, BorshSerialize, to_vec};
use once_cell::unsync::OnceCell;
@@ -42,3 +42,3 @@ where
{
- let serialized = value.try_to_vec().unwrap_or_else(|_| env::panic_str(ERR_VALUE_SERIALIZATION));
+ let serialized = to_vec(value).unwrap_or_else(|_| env::panic_str(ERR_VALUE_SERIALIZATION));
env::storage_write(key, &serialized);
...
...
where value
is &T
, where T: BorshSerialize
.
To prevent compilation errors in the future, we grep for schema_container
string.
schema_container
was changed from being a BorshSchema
trait method to being a function, external
to the trait in chore!: make BorshSchema::{add_definition,schema_container} free-standing funcs
We fix code, generated with near_bindgen
procedural macro, with following diff:
diff --git a/near-sdk-macros/src/core_impl/abi/abi_generator.rs b/near-sdk-macros/src/core_impl/abi/abi_generator.rs
index cbe659a..994e63c 100644
--- a/near-sdk-macros/src/core_impl/abi/abi_generator.rs
+++ b/near-sdk-macros/src/core_impl/abi/abi_generator.rs
@@ -239,21 +239,21 @@ impl ImplItemMethodInfo {
}
}
}
fn generate_schema(ty: &Type, serializer_type: &SerializerType) -> TokenStream2 {
match serializer_type {
SerializerType::JSON => quote! {
gen.subschema_for::<#ty>()
},
SerializerType::Borsh => quote! {
- <#ty as ::near_sdk::borsh::BorshSchema>::schema_container()
+ ::near_sdk::borsh::schema_container_of::<#ty>()
},
}
}
fn generate_abi_type(ty: &Type, serializer_type: &SerializerType) -> TokenStream2 {
let schema = generate_schema(ty, serializer_type);
match serializer_type {
SerializerType::JSON => quote! {
::near_sdk::__private::AbiType::Json {
type_schema: #schema,
1 error: You have to specify `#[borsh(use_discriminant=true)]` or `#[borsh(use_discriminant=false)]` for all enums with explicit discriminant
--> near-sdk/src/types/public_key.rs:8:10
|
8 | pub enum CurveType {
| ^^^^^^^^^
on
/// PublicKey curve
#[derive(Debug, Clone, Copy, PartialOrd, Ord, Eq, PartialEq, BorshDeserialize, BorshSerialize)]
#[repr(u8)]
pub enum CurveType {
ED25519 = 0,
SECP256K1 = 1,
}
We fix it with #[borsh(use_discriminant=true)]
, which will behave the same as #[borsh(use_discriminant=false)]
in this particular case, where false
preserves the behaviour of borsh before 1.0 release
(borsh 0.10 and older ignored explicit discriminant values in enum definitions):
diff --git a/near-sdk/src/types/public_key.rs b/near-sdk/src/types/public_key.rs
index 30ebd43..b539ddd 100644
--- a/near-sdk/src/types/public_key.rs
+++ b/near-sdk/src/types/public_key.rs
@@ -7,2 +7,3 @@ use std::convert::TryFrom;
#[repr(u8)]
+#[borsh(use_discriminant=true)]
pub enum CurveType {
@@ -144,4 +145,4 @@ impl serde::Serialize for PublicKey {
1 error[E0432]: unresolved import `borsh::maybestd`
--> near-sdk/src/types/public_key.rs:1:13
|
1 | use borsh::{maybestd::io, BorshDeserialize, BorshSerialize};
| ^^^^^^^^ could not find `maybestd` in `borsh`
2 error[E0432]: unresolved import `borsh::maybestd`
--> near-sdk/src/types/account_id.rs:1:13
|
1 | use borsh::{maybestd::io, BorshDeserialize, BorshSchema, BorshSerialize};
| ^^^^^^^^ could not find `maybestd` in `borsh`
// near-sdk/src/types/public_key.rs
impl BorshDeserialize for PublicKey {
fn deserialize(buf: &mut &[u8]) -> io::Result<Self> {
<Vec<u8> as BorshDeserialize>::deserialize(buf).and_then(|s| {
Self::try_from(s).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
})
}
}
maybestd
has moved to a __private
package in borsh
, and is not supposed to be
accessed directly now besides from within code, derived in borsh
traits implementations.
As near-sdk
crate is not supposed to be used in no_std
context, we can
replace imports with std::io
:
diff --git a/near-sdk/src/types/account_id.rs b/near-sdk/src/types/account_id.rs
index a338b5c..7876d77 100644
--- a/near-sdk/src/types/account_id.rs
+++ b/near-sdk/src/types/account_id.rs
@@ -1,5 +1,5 @@
-use borsh::{maybestd::io, BorshDeserialize, BorshSchema, BorshSerialize};
+use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use serde::{de, Deserialize, Serialize};
use std::convert::TryFrom;
-use std::fmt;
+use std::{fmt, io};
diff --git a/near-sdk/src/types/public_key.rs b/near-sdk/src/types/public_key.rs
index 10175a0..4280f70 100644
--- a/near-sdk/src/types/public_key.rs
+++ b/near-sdk/src/types/public_key.rs
@@ -1,4 +1,4 @@
-use borsh::{maybestd::io, BorshDeserialize, BorshSerialize};
+use borsh::{BorshDeserialize, BorshSerialize};
use bs58::decode::Error as B58Error;
-use std::convert::TryFrom;
+use std::{convert::TryFrom, io};
Otherwise, if we intended to support both std
and no_std
, we would've imported from borsh::io
:
-use borsh::{maybestd::io, BorshDeserialize, BorshSerialize};
+use borsh::{BorshDeserialize, BorshSerialize};
+use borsh::io;
1 error: cannot find attribute `borsh_skip` in this scope
--> near-sdk/src/store/lookup_map/mod.rs:89:7
|
89 | #[borsh_skip]
| ^^^^^^^^^^
We change all of these occurencies according to new
#[borsh(skip)]
syntax. The following diff is shortened to first and last
occurencies:
diff --git a/near-sdk/src/collections/lazy_option.rs b/near-sdk/src/collections/lazy_option.rs
index 04e79fb..f4ea0dc 100644
--- a/near-sdk/src/collections/lazy_option.rs
+++ b/near-sdk/src/collections/lazy_option.rs
@@ -19,3 +19,3 @@ pub struct LazyOption<T> {
storage_key: Vec<u8>,
- #[borsh_skip]
+ #[borsh(skip)]
el: PhantomData<T>,
...
diff --git a/near-sdk/src/store/lookup_set/mod.rs b/near-sdk/src/store/lookup_set/mod.rs
index 762956a..b2d1ac0 100644
--- a/near-sdk/src/store/lookup_set/mod.rs
+++ b/near-sdk/src/store/lookup_set/mod.rs
@@ -54,3 +54,3 @@ where
- #[borsh_skip]
+ #[borsh(skip)]
hasher: PhantomData<fn() -> (T, H)>,
They're fixed in a similar way as in 5.
8. next there's a bunch of similar errors due to BorshDeserialize
trait signature change (near-sdk
package):
1 error[E0046]: not all trait items implemented, missing: `deserialize_reader`
--> near-sdk/src/store/vec/mod.rs:138:1
|
138 | impl<T> BorshDeserialize for Vector<T>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `deserialize_reader` in implementation
= help: implement the missing item: `fn deserialize_reader<R>(_: &mut R) -> std::result::Result<Self, std::io::Error> where R: std::io::Read { todo!() }
The signature of trait has changed on 0.9.3 -> 0.10.0 transition in implement deserialize_reader. We fix it the following way:
diff --git a/near-sdk/src/store/free_list/mod.rs b/near-sdk/src/store/free_list/mod.rs
index 43d8908..20a1cc7 100644
--- a/near-sdk/src/store/free_list/mod.rs
+++ b/near-sdk/src/store/free_list/mod.rs
@@ -47,7 +47,7 @@ where
{
- fn deserialize(buf: &mut &[u8]) -> Result<Self, std::io::Error> {
+ fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> Result<Self, std::io::Error> {
Ok(Self {
- first_free: BorshDeserialize::deserialize(buf)?,
- occupied_count: BorshDeserialize::deserialize(buf)?,
- elements: BorshDeserialize::deserialize(buf)?,
+ first_free: BorshDeserialize::deserialize_reader(reader)?,
+ occupied_count: BorshDeserialize::deserialize_reader(reader)?,
+ elements: BorshDeserialize::deserialize_reader(reader)?,
})
diff --git a/near-sdk/src/store/unordered_map/mod.rs b/near-sdk/src/store/unordered_map/mod.rs
index 5decc60..d82a8aa 100644
--- a/near-sdk/src/store/unordered_map/mod.rs
+++ b/near-sdk/src/store/unordered_map/mod.rs
@@ -117,6 +117,6 @@ where
{
- fn deserialize(buf: &mut &[u8]) -> Result<Self, std::io::Error> {
+ fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> Result<Self, std::io::Error> {
Ok(Self {
- keys: BorshDeserialize::deserialize(buf)?,
- values: BorshDeserialize::deserialize(buf)?,
+ keys: BorshDeserialize::deserialize_reader(reader)?,
+ values: BorshDeserialize::deserialize_reader(reader)?,
})
diff --git a/near-sdk/src/store/vec/mod.rs b/near-sdk/src/store/vec/mod.rs
index 9d19614..94127ba 100644
--- a/near-sdk/src/store/vec/mod.rs
+++ b/near-sdk/src/store/vec/mod.rs
@@ -141,6 +141,6 @@ where
{
- fn deserialize(buf: &mut &[u8]) -> Result<Self, std::io::Error> {
+ fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> Result<Self, std::io::Error> {
Ok(Self {
- len: BorshDeserialize::deserialize(buf)?,
- values: BorshDeserialize::deserialize(buf)?,
+ len: BorshDeserialize::deserialize_reader(reader)?,
+ values: BorshDeserialize::deserialize_reader(reader)?,
})
diff --git a/near-sdk/src/types/account_id.rs b/near-sdk/src/types/account_id.rs
index 7876d77..3da417a 100644
--- a/near-sdk/src/types/account_id.rs
+++ b/near-sdk/src/types/account_id.rs
@@ -88,4 +88,4 @@ impl<'de> Deserialize<'de> for AccountId {
impl BorshDeserialize for AccountId {
- fn deserialize(buf: &mut &[u8]) -> io::Result<Self> {
- <String as BorshDeserialize>::deserialize(buf).and_then(|s| {
+ fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
+ <String as BorshDeserialize>::deserialize_reader(reader).and_then(|s| {
Self::try_from(s).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
diff --git a/near-sdk/src/types/public_key.rs b/near-sdk/src/types/public_key.rs
index 4280f70..b539ddd 100644
--- a/near-sdk/src/types/public_key.rs
+++ b/near-sdk/src/types/public_key.rs
@@ -145,4 +145,4 @@ impl serde::Serialize for PublicKey {
impl BorshDeserialize for PublicKey {
- fn deserialize(buf: &mut &[u8]) -> io::Result<Self> {
- <Vec<u8> as BorshDeserialize>::deserialize(buf).and_then(|s| {
+ fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
+ <Vec<u8> as BorshDeserialize>::deserialize_reader(reader).and_then(|s| {
Self::try_from(s).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
diff --git a/near-sdk/src/collections/unordered_map/mod.rs b/near-sdk/src/collections/unordered_map/mod.rs
index d3ba8d5..aab31a4 100644
--- a/near-sdk/src/collections/unordered_map/mod.rs
+++ b/near-sdk/src/collections/unordered_map/mod.rs
@@ -512,5 +512,5 @@ mod tests {
impl BorshDeserialize for DeserializeCounter {
- fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> {
+ fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
DES_COUNT.fetch_add(1, Ordering::SeqCst);
- u64::deserialize(buf).map(DeserializeCounter)
+ u64::deserialize_reader(reader).map(DeserializeCounter)
}
6 error[E0277]: the trait bound `T: Default` is not satisfied
--> near-sdk/src/store/vec/mod.rs:145:21
|
145 | values: BorshDeserialize::deserialize_reader(reader)?,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `T`
|
note: required for `IndexMap<T>` to implement `BorshDeserialize`
--> near-sdk/src/store/index_map.rs:12:26
|
12 | #[derive(BorshSerialize, BorshDeserialize)]
| ^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
13 | pub(crate) struct IndexMap<T>
| ^^^^^^^^^^^
= note: this error originates in the derive macro `BorshDeserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider further restricting this bound
|
140 | T: BorshSerialize + std::default::Default,
| +++++++++++++++++++++++
where IndexMap<T>
looks like the following:
#[derive(BorshSerialize, BorshDeserialize)]
pub(crate) struct IndexMap<T>
where
T: BorshSerialize,
{
pub(crate) prefix: Box<[u8]>,
/// Cache for loads and intermediate changes to the underlying index map.
/// The cached entries are wrapped in a [`Box`] to avoid existing pointers from being
/// invalidated.
///
/// Note: u32 indices are used over usize to have consistent functionality across architectures.
/// Some functionality would be different from tests to Wasm if exceeding 32-bit length.
#[borsh(skip)]
pub(crate) cache: StableMap<u32, OnceCell<CacheEntry<T>>>,
}
On version change v0.9
-> v1.0.0-alpha.5
bounds derivation in borsh
has changed:
From bounds on the types of the fields:
// cd near-sdk; cargo expand ::store::index_map
impl<T> borsh::de::BorshDeserialize for IndexMap<T>
where
T: BorshSerialize,
Box<[u8]>: borsh::BorshDeserialize,
{
fn deserialize(
buf: &mut &[u8],
) -> ::core::result::Result<Self, borsh::maybestd::io::Error> {
Ok(Self {
prefix: borsh::BorshDeserialize::deserialize(buf)?,
cache: Default::default(),
})
}
}
to bounds on type parameters, encountered in fields. borsh::de::BorshDeserialize
bound
for parameters in non-skipped fields, core::default::Default
bound - otherwise:
impl<T> borsh::de::BorshDeserialize for IndexMap<T>
where
T: BorshSerialize,
T: core::default::Default,
{
fn deserialize_reader<R: borsh::__private::maybestd::io::Read>(
reader: &mut R,
) -> ::core::result::Result<Self, borsh::__private::maybestd::io::Error> {
Ok(Self {
prefix: borsh::BorshDeserialize::deserialize_reader(reader)?,
cache: core::default::Default::default(),
})
}
}
We can instruct borsh
to replace automatically derived bound with nothing, as StableMap
has a impl<K: Ord, V> Default for StableMap<K, V>
implementation of its own, as it will be used when deserializing skipped field, irrelevant of bounds on V
:
diff --git a/near-sdk/src/store/index_map.rs b/near-sdk/src/store/index_map.rs
index 834fc98..7d1df75 100644
--- a/near-sdk/src/store/index_map.rs
+++ b/near-sdk/src/store/index_map.rs
@@ -23,3 +23,3 @@ where
/// Some functionality would be different from tests to Wasm if exceeding 32-bit length.
- #[borsh(skip)]
+ #[borsh(skip, bound(deserialize = ""))]
pub(crate) cache: StableMap<u32, OnceCell<CacheEntry<T>>>,
which would transform into following bound on trait's implementation:
// line with `T: core::default::Default,` disappeared
impl<T> borsh::de::BorshDeserialize for IndexMap<T>
where
T: BorshSerialize,
{
...
Similar diffs were also applied here:
diff --git a/near-sdk/src/store/lookup_map/mod.rs b/near-sdk/src/store/lookup_map/mod.rs
index 0b20345..927b2d6 100644
--- a/near-sdk/src/store/lookup_map/mod.rs
+++ b/near-sdk/src/store/lookup_map/mod.rs
@@ -88,3 +88,3 @@ where
/// invalidated.
- #[borsh(skip)]
+ #[borsh(skip, bound(deserialize = ""))]
cache: StableMap<K, EntryAndHash<V, H::KeyType>>,
diff --git a/near-sdk/src/store/unordered_set/mod.rs b/near-sdk/src/store/unordered_set/mod.rs
index 4504580..77621b9 100644
--- a/near-sdk/src/store/unordered_set/mod.rs
+++ b/near-sdk/src/store/unordered_set/mod.rs
@@ -83,9 +83,11 @@ pub struct UnorderedSet<T, H = Sha256>
where
T: BorshSerialize + Ord,
H: ToKey,
{
+ #[borsh(bound(serialize = "", deserialize = ""))]
elements: FreeList<T>,
+ #[borsh(bound(serialize = "", deserialize = ""))]
index: LookupMap<T, FreeListIndex, H>,
}
4 error[E0053]: method `add_definitions_recursively` has an incompatible type for trait
--> near-sdk/src/promise.rs:232:22
|
232 | definitions: &mut HashMap<borsh::schema::Declaration, borsh::schema::Definition>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected `BTreeMap<String, Definition>`, found `HashMap<String, Definition>`
| help: change the parameter type to match the trait: `&mut BTreeMap<std::string::String, Definition>`
|
= note: expected signature `fn(&mut BTreeMap<std::string::String, Definition>)`
found signature `fn(&mut HashMap<std::string::String, Definition>)`
Signature in trait's method has changed:
diff --git a/near-sdk/src/promise.rs b/near-sdk/src/promise.rs
index f8afe56..a430568 100644
--- a/near-sdk/src/promise.rs
+++ b/near-sdk/src/promise.rs
@@ -2,3 +2,3 @@ use borsh::BorshSchema;
use std::cell::RefCell;
-use std::collections::HashMap;
+use std::collections::BTreeMap;
use std::io::{Error, Write};
@@ -231,3 +231,3 @@ impl BorshSchema for Promise {
fn add_definitions_recursively(
- definitions: &mut HashMap<borsh::schema::Declaration, borsh::schema::Definition>,
+ definitions: &mut BTreeMap<borsh::schema::Declaration, borsh::schema::Definition>,
) {
@@ -576,3 +576,3 @@ where
fn add_definitions_recursively(
- definitions: &mut HashMap<borsh::schema::Declaration, borsh::schema::Definition>,
+ definitions: &mut BTreeMap<borsh::schema::Declaration, borsh::schema::Definition>,
) {
11. next we encounter an error with both BorshSerialize
and BorshDeserialize
traits' derivation (near-contract-standards
package):
1 error: proc-macro derive panicked
--> near-contract-standards/src/fungible_token/core_impl.rs:27:10
|
27 | #[derive(BorshDeserialize, BorshSerialize)]
| ^^^^^^^^^^^^^^^^
|
= help: message: called `Result::unwrap()` on an `Err` value: CrateNotFound { crate_name: "borsh", path: "/home/user/Documents/code/near-sdk-rs/near-contract-standards/Cargo.toml" }
2 error: proc-macro derive panicked
--> near-contract-standards/src/fungible_token/core_impl.rs:27:28
|
27 | #[derive(BorshDeserialize, BorshSerialize)]
| ^^^^^^^^^^^^^^
|
= help: message: called `Result::unwrap()` on an `Err` value: CrateNotFound { crate_name: "borsh", path: "/home/user/Documents/code/near-sdk-rs/near-contract-standards/Cargo.toml" }
Thing is, borsh
has started getting into a panic
when using proc-macro-crate dependency for derives,
in the cases when borsh
is not imported as direct dependency in the crate, which attempts to use its derive macros.
near-contract-standards
wasn't importing borsh
directly, just using near-sdk
's reexports.
We may instruct BorshSerialize
and BorshDeserialize
derives to skip this check of direct import
and to use a reexported version of borsh
via following diff:
diff --git a/near-contract-standards/src/fungible_token/core_impl.rs b/near-contract-standards/src/fungible_token/core_impl.rs
index d61ee8e..cae776c 100644
--- a/near-contract-standards/src/fungible_token/core_impl.rs
+++ b/near-contract-standards/src/fungible_token/core_impl.rs
@@ -27,2 +27,3 @@ const ERR_TOTAL_SUPPLY_OVERFLOW: &str = "Total supply overflow";
#[derive(BorshDeserialize, BorshSerialize)]
+#[borsh(crate = "::near_sdk::borsh")]
pub struct FungibleToken {
diff --git a/near-sdk/Cargo.toml b/near-sdk/Cargo.toml
index a015a64..e6099d4 100644
--- a/near-sdk/Cargo.toml
+++ b/near-sdk/Cargo.toml
@@ -26,3 +26,3 @@ near-sys = { path = "../near-sys", version = "0.2" }
base64 = "0.13"
-borsh = { version = "=1.0.0-alpha.5", features = ["derive"] }
+borsh = { version = "1.0.0", features = ["derive"] }
bs58 = "0.4"