# `0.10.2` -> `1.0.0` `nearcore` upgrade *migration guide*

The link to `nearcore` pr is [chore: update borsh dependency](https://github.com/near/nearcore/pull/9432)  

Steps:

## 1. update dependencies in `nearcore` workspace `Cargo.toml`

First we update to `1.0.0-alpha.5` version, which contains [deprecation](https://github.com/near/borsh-rs/pull/206) of `BorshSerialize::try_to_vec` method.

```diff
diff --git a/Cargo.toml b/Cargo.toml
index f38e88411..1587f4131 100644
--- a/Cargo.toml
+++ b/Cargo.toml
-borsh = { version = "0.10.2", features = ["rc"] }
+borsh = { version = "=1.0.0-alpha.5", features = ["derive", "rc"] }
```

## 2. We receive a great number of deprecation warnings of `borsh::BorshSerialize::try_to_vec` method (`near-primitives-core` and other packages):

```bash
warning: use of deprecated method `borsh::BorshSerialize::try_to_vec`: use `borsh::to_vec(&object)` instead
   --> core/primitives-core/src/account.rs:246:25
    |
246 |         let bytes = acc.try_to_vec().unwrap();
    |                         ^^^^^^^^^^
    |
    = note: `#[warn(deprecated)]` on by default
```

We choose to fix it at once, as this method is [removed](https://github.com/near/borsh-rs/pull/221) in `1.0.0-alpha.5` -> `1.0.0` transition completely 
with following diff:

```diff
diff --git a/core/primitives-core/src/account.rs b/core/primitives-core/src/account.rs
index 50a3a340d..380bf4494 100644
--- a/core/primitives-core/src/account.rs
+++ b/core/primitives-core/src/account.rs
@@ -236,3 +236,2 @@ pub struct FunctionCallPermission {
 mod tests {
-    use borsh::BorshSerialize;
 
@@ -245,3 +244,3 @@ mod tests {
         let acc = Account::new(1_000_000, 1_000_000, CryptoHash::default(), 100);
-        let bytes = acc.try_to_vec().unwrap();
+        let bytes = borsh::to_vec(&acc).unwrap();
         assert_eq!(hash(&bytes).to_string(), "EVk5UaxBe8LQ8r8iD5EAxVBs6TJcMDKqyH7PBuho6bBJ");
@@ -257,3 +256,3 @@ mod tests {
         };
-        let mut old_bytes = &old_account.try_to_vec().unwrap()[..];
+        let mut old_bytes = &borsh::to_vec(&old_account).unwrap()[..];
         let new_account = <Account as BorshDeserialize>::deserialize(&mut old_bytes).unwrap();
@@ -264,3 +263,3 @@ mod tests {
         assert_eq!(new_account.version, AccountVersion::V1);
-        let mut new_bytes = &new_account.try_to_vec().unwrap()[..];
+        let mut new_bytes = &borsh::to_vec(&new_account).unwrap()[..];
         let deserialized_account =
...
...
...
```

As `nearcore` has a considerable number of occurencies of usage of `borsh::BorshSerialize::try_to_vec` method,
which are tedious to replace manually, [ast-grep](https://github.com/ast-grep/ast-grep) tool may help to
do the refactoring automatically:

```bash
sg -p '$A.try_to_vec()' -l rs -r 'borsh::to_vec(&$A)'  # preview changes
sg -p '$A.try_to_vec()' -l rs -r 'borsh::to_vec(&$A)' -A # apply changes without preview
```

## 3. next we encounter error in `near-primitives` package:

```bash
 1  error[E0433]: failed to resolve: could not find `maybestd` in `borsh`                   ▐
  --> core/primitives/src/receipt.rs:1:19                                                   ▐
   |                                                                                        ▐
 1 | use crate::borsh::maybestd::collections::HashMap;                                      ▐
   |                   ^^^^^^^^ could not find `maybestd` in `borsh`                        ▐
```

`maybestd` [has moved](https://github.com/near/borsh-rs/pull/171) 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-primitives` crate is not supposed to be used in `no_std` context, we can
replace import with standard collections `HashMap`:

```diff
diff --git a/core/primitives/src/receipt.rs b/core/primitives/src/receipt.rs
index 30af36fb9..d5a6632ed 100644
--- a/core/primitives/src/receipt.rs
+++ b/core/primitives/src/receipt.rs
@@ -1,11 +1,11 @@
-use crate::borsh::maybestd::collections::HashMap;
+use std::collections::HashMap;
```

Otherwise, we would've imported from `hashbrown`:

```diff
-use crate::borsh::maybestd::collections::HashMap;
+#[cfg(feature = "std")]
+use std::collections::HashMap;
+#[cfg(not(feature = "std"))]
+use hashbrown::HashMap;
```

## 4. next we encounter a bunch of similar errors in `near-primitives` with `#[borsh_init(...)]`:

```bash
 1  error: cannot find attribute `borsh_init` in this scope                                 ▐
    --> core/primitives/src/block_header.rs:267:3                                           ▐
     |                                                                                      ▐
 267 | #[borsh_init(init)]                                                                  ▐
     |   ^^^^^^^^^^ help: a derive helper attribute with a similar name exists: `borsh_skip`▐
```

The syntax of this attribute [has changed](https://github.com/near/borsh-rs/pull/187). We change all of these occurencies according to
`#[borsh(init=<initialization_method>)]` syntax. The following diff is shortened to first and last
occurencies:

```diff
diff --git a/core/primitives/src/block_header.rs b/core/primitives/src/block_header.rs
index 38491b52c..84ab48238 100644
--- a/core/primitives/src/block_header.rs
+++ b/core/primitives/src/block_header.rs
@@ -266,3 +266,3 @@ impl ApprovalMessage {
 #[derive(BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq)]
-#[borsh_init(init)]
+#[borsh(init=init)]
 pub struct BlockHeaderV1 {
...
diff --git a/core/primitives/src/transaction.rs b/core/primitives/src/transaction.rs
index 912120b56..2de7a1d52 100644
--- a/core/primitives/src/transaction.rs
+++ b/core/primitives/src/transaction.rs
@@ -58,3 +58,3 @@ impl Transaction {
 )]
-#[borsh_init(init)]
+#[borsh(init=init)]
 pub struct SignedTransaction {
```

## 5. next we encounter a large number of similar syntax errors in `near-primitives` package

```bash
 1  error: cannot find attribute `borsh_skip` in this scope                   ▐
    --> core/primitives/src/transaction.rs:196:7                              ▐
     |                                                                        ▐
 196 |     #[borsh_skip]                                                      ▐
     |       ^^^^^^^^^^                                                       ▐
                                                                              ▐
```

We change all of these occurencies according to [new](https://github.com/near/borsh-rs/pull/192)
`#[borsh(skip)]` syntax. The following diff is shortened to first and last
occurencies:

```diff
diff --git a/core/primitives/src/block_header.rs b/core/primitives/src/block_header.rs
index 84ab48238..6514f8222 100644
--- a/core/primitives/src/block_header.rs
+++ b/core/primitives/src/block_header.rs
@@ -279,3 +279,3 @@ pub struct BlockHeaderV1 {
     /// Cached value of hash for this block.
-    #[borsh_skip]
+    #[borsh(skip)]
     pub hash: CryptoHash,
...
diff --git a/core/primitives/src/transaction.rs b/core/primitives/src/transaction.rs
index 2de7a1d52..f3ac54ba8 100644
--- a/core/primitives/src/transaction.rs
+++ b/core/primitives/src/transaction.rs
@@ -62,5 +62,5 @@ pub struct SignedTransaction {
     pub signature: Signature,
-    #[borsh_skip]
+    #[borsh(skip)]
     hash: CryptoHash,
-    #[borsh_skip]
+    #[borsh(skip)]
     size: u64,
...
```



## 6. next we encounter 2 errors in `near-primitives` package similar to those in point 3.:

```bash
 1  error[E0433]: failed to resolve: could not find `maybestd` in `borsh`
    --> core/primitives/src/action/delegate.rs:119:41
     |
 119 |         fn deserialize_reader<R: borsh::maybestd::io::Read>(
     |                                         ^^^^^^^^ could not find `maybestd` in `borsh`
                                                                                             
 2  error[E0433]: failed to resolve: could not find `maybestd` in `borsh`
    --> core/primitives/src/action/delegate.rs:121:50
     |
 121 |         ) -> ::core::result::Result<Self, borsh::maybestd::io::Error> {
     |                                                  ^^^^^^^^ could not find `maybestd` i
 n `borsh`
```

As `near-primitives` crate is not supposed to be used in `no_std` context, we can
replace import with `std::io`:

```diff
diff --git a/core/primitives/src/action/delegate.rs b/core/primitives/src/action/delegate.rs
index 25db73022..ebd009a44 100644
--- a/core/primitives/src/action/delegate.rs
+++ b/core/primitives/src/action/delegate.rs
@@ -14,3 +14,3 @@ use near_primitives_core::types::{AccountId, Nonce};
 use serde::{Deserialize, Serialize};
-use std::io::{Error, ErrorKind};
+use std::io::{Error, ErrorKind, Read};
 
@@ -118,5 +118,5 @@ mod private_non_delegate_action {
     impl borsh::de::BorshDeserialize for NonDelegateAction {
-        fn deserialize_reader<R: borsh::maybestd::io::Read>(
+        fn deserialize_reader<R: Read>(
             rd: &mut R,
-        ) -> ::core::result::Result<Self, borsh::maybestd::io::Error> {
+        ) -> ::core::result::Result<Self, Error> {
             match u8::deserialize_reader(rd)? {
```


Otherwise, if we intended to support [both `std` and `no_std`](https://github.com/near/borsh-rs/pull/212), we would've imported from `borsh::io`:

```diff
+use borsh::io::{Error, ErrorKind, Read};
```

## 7. next we encounter an error with `BorshDeserialize` trait derivation:

```bash
 1  error[E0277]: the trait bound `&T: borsh::BorshDeserialize` is not satisfied
   --> core/primitives/src/signable_message.rs:58:26
    |
 58 | #[derive(BorshSerialize, BorshDeserialize)]
    |                          ^^^^^^^^^^^^^^^^ the trait `borsh::BorshDeserialize` is not implemented for `&T`
```
on

```rust
/// A wrapper around a message that should be signed using this scheme.
///
/// Only used for constructing a signature, not used to transmit messages. The
/// discriminant prefix is implicit and should be known by the receiver based on
/// the context in which the message is received.
#[derive(BorshSerialize, BorshDeserialize)]
pub struct SignableMessage<'a, T> {
    pub discriminant: MessageDiscriminant,
    pub msg: &'a T,
}
```

On version change `0.10.3` -> `1.0.0-alpha.5` bounds derivation in `borsh` [has changed](https://github.com/near/borsh-rs/pull/178):
From bounds on the types of the fields:

```rust
impl<'a, T> borsh::de::BorshDeserialize for SignableMessage<'a, T>
where
    MessageDiscriminant: borsh::de::BorshDeserialize,
    &'a T: borsh::de::BorshDeserialize,
```

to bounds on type parameters, encountered in fields:

```rust
impl<'a, T> borsh::de::BorshDeserialize for SignableMessage<'a, T>
where
    T: borsh::de::BorshDeserialize,
```


We could potentially [patch the bounds](https://github.com/near/borsh-rs/pull/180) on struct to make it compile:

```rust
#[derive(BorshSerialize, BorshDeserialize)]
pub struct SignableMessage<'a, T> {
    pub discriminant: MessageDiscriminant,
    #[borsh(bound(deserialize="&'a T: borsh::de::BorshDeserialize"))]
    pub msg: &'a T,
}
```
which would transform into following bound on trait's implementation:

```rust
where
    &'a T: borsh::de::BorshDeserialize,
```

But the real issue here is that `borsh` doesn't have a generic implementation
of `BorshDeserialize` for `&'a T`, where `T: borsh::de::BorshDeserialize` (nor did it have it in 0.10.2 version),
and that the derived `BorshDeserialize` wasn't used (and it couldn't be for such a field's type).

So the right change is to remove `BorshDeserialize` derive from the struct:

```diff
diff --git a/core/primitives/src/signable_message.rs b/core/primitives/src/signable_message.rs
index efdd489ac..db97eb1fd 100644
--- a/core/primitives/src/signable_message.rs
+++ b/core/primitives/src/signable_message.rs
@@ -57,3 +57,3 @@ pub struct MessageDiscriminant {
 /// the context in which the message is received.
-#[derive(BorshSerialize, BorshDeserialize)]
+#[derive(BorshSerialize)]
 pub struct SignableMessage<'a, T> {
```


## 8. next we encounter an error in `near-network` package:

```rust
 1  error: You have to specify `#[borsh(use_discriminant=true)]` or `#[borsh(use_discriminant=false)]` for all enums with explicit discriminant                                                                                                                            ▐
   --> chain/network/src/types.rs:56:10                                                                                                                                                                                                                                    ▐
    |                                                                                                                                                                                                                                                                      ▐
 56 | pub enum ReasonForBan {                                                                                                                                                                                                                                              ▐
    |          ^^^^^^^^^^^^                                                                                                                                                                                                                                                ▐
```

```rust
#[derive(borsh::BorshSerialize, borsh::BorshDeserialize, Debug, Clone, PartialEq, Eq, Copy)]
pub enum ReasonForBan {
    None = 0,
    BadBlock = 1,
    BadBlockHeader = 2,
    HeightFraud = 3,
    BadHandshake = 4,
    BadBlockApproval = 5,
    Abusive = 6,
    InvalidSignature = 7,
    InvalidPeerId = 8,
    InvalidHash = 9,
    InvalidEdge = 10,
    InvalidDistanceVector = 11,
    Blacklisted = 14,
}
```

We fix it with `#[borsh(use_discriminant=false)]` to preserve the behaviour of borsh before 
1.0 release which serialized `ReasonForBan::Blacklisted` as 12 instead of 14 
(borsh 0.10 and older [ignored explicit discriminant values in enum definitions](https://github.com/near/borsh-rs/issues/137)):

```diff
diff --git a/chain/network/src/types.rs b/chain/network/src/types.rs
index b2dd97c32..ea2d67f2d 100644
--- a/chain/network/src/types.rs
+++ b/chain/network/src/types.rs
@@ -55,2 +55,3 @@ pub struct KnownProducer {
 #[derive(borsh::BorshSerialize, borsh::BorshDeserialize, Debug, Clone, PartialEq, Eq, Copy)]
+#[borsh(use_discriminant=false)]
 pub enum ReasonForBan {
```


## 9. change in behaviour, unit test error in ci in `near-primitives` package

Assertion fails:

```rust
    #[test]
    fn test_delegate_action_deserialization() {
        // Expected an error. Buffer is empty
        assert_eq!(
            NonDelegateAction::try_from_slice(Vec::new().as_ref()).map_err(|e| e.kind()),
            Err(ErrorKind::InvalidInput)
        );
```

```bash
--- STDERR:              near-primitives action::delegate::tests::test_delegate_action_deserialization ---
thread 'action::delegate::tests::test_delegate_action_deserialization' panicked at 'assertion failed: `(left == right)`
  left: `Err(InvalidData)`,
 right: `Err(InvalidInput)`', core/primitives/src/action/delegate.rs:172:9
 ```

 The `ErrorKind` in error in `borsh` [has changed](https://github.com/near/borsh-rs/pull/170), so we apply the following diff:

```diff
diff --git a/core/primitives/src/action/delegate.rs b/core/primitives/src/action/delegate.rs
index ebd009a44..80a0475b6 100644
--- a/core/primitives/src/action/delegate.rs
+++ b/core/primitives/src/action/delegate.rs
@@ -173,3 +173,3 @@ mod tests {
             NonDelegateAction::try_from_slice(Vec::new().as_ref()).map_err(|e| e.kind()),
-            Err(ErrorKind::InvalidInput)
+            Err(ErrorKind::InvalidData)
         );
```

And there's also a similar error in 

```bash
--- STDERR:              near-store tests::test_save_to_file ---
thread 'tests::test_save_to_file' panicked at 'assertion failed: `(left == right)`
  left: `InvalidInput`,
 right: `InvalidData`', core/store/src/lib.rs:1096:9  
```

with similar fix.

## 10. errors  similar to previous ones, in `near-store`, `near-network` and `near-state-viewer` packages

There was a bunch of `borsh::maybestd` imports, which got replaced by their direct from-`std` counterparts.

## 11. finally, we update `borsh` version to `1.0.0`:

```diff
diff --git a/Cargo.toml b/Cargo.toml
index f38e88411..1587f4131 100644
--- a/Cargo.toml
+++ b/Cargo.toml
-borsh = { version = "=1.0.0-alpha.5", features = ["derive", "rc"] }
+borsh = { version = "1.0.0", features = ["derive", "rc"] }
```
