rustnearprotocolnear

ExecutionError:Smart contract panicked:panicked at Cannot deserialize the contract state.:Custom kind:InvalidInput,error:"Unexpected length of input"


#[derive(BorshSerialize, BorshDeserialize)]
pub struct NotesDs {
    pub own: Vec<String>,
    pub shared: UnorderedMap<AccountId,Vec<String>>,
}

impl NotesDs{
    pub fn new() -> Self {
        assert!(env::state_read::<Self>().is_none(), "Already initialized");
        Self {
            own: Vec:: new(),
            shared: UnorderedMap::new(b"w".to_vec()),
        }
    }
}
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize)]
pub struct Note {
    pub note_list : UnorderedMap<AccountId,NotesDs>, 
}

impl Default for Note {
    fn default() -> Self {
        // Check incase the contract is not initialized
        env::panic(b"The contract is not initialized.")
    }
}

#[near_bindgen]
impl Note {
    /// Init attribute used for instantiation.
    #[init]
    pub fn new() -> Self {
        assert!(env::state_read::<Self>().is_none(), "Already initialized");
        Self {
            note_list: UnorderedMap::new(b"h".to_vec()),
        }
    }
    pub fn add_notes2(&mut self, status: String){
        if self.note_list.get(&env::predecessor_account_id()).is_none() {
            let mut temp = NotesDs:: new();
            let mut vec = Vec:: new();
            let mut vec2 = Vec:: new();
            vec.push(status.clone());
            temp.own = vec;
            temp.shared = vec2;
            self.note_list.insert(&env::predecessor_account_id(), &temp);
        }
        else {
            let mut temp1 = self.note_list.get(&env::predecessor_account_id()).unwrap();
            let mut vec1 = temp1.own;
            vec1.push(status.clone());
            temp1.own = vec1;
            self.note_list.insert(&env::predecessor_account_id(), &temp1);
        }      
    }
} 

I am getting the following error

 Failure [share.meghaha.testnet]: Error: {"index":0,"kind":{"ExecutionError":"Smart contract panicked: panicked at 'Cannot deserialize the contract state.: Custom { kind: InvalidInput, error: \"Unexpected length of input\" }', /home/meghaa105/.cargo/registry/src/github.com-1ecc6299db9ec823/near-sdk-3.1.0/src/environment/env.rs:786:46"}}
ServerTransactionError: {"index":0,"kind":{"ExecutionError":"Smart contract panicked: panicked at 'Cannot deserialize the contract state.: Custom { kind: InvalidInput, error: \"Unexpected length of input\" }', /home/meghaa105/.cargo/registry/src/github.com-1ecc6299db9ec823/near-sdk-3.1.0/src/environment/env.rs:786:46"}}
    at Object.parseResultError (/usr/lib/node_modules/near-cli/node_modules/near-api-js/lib/utils/rpc_errors.js:31:29) 
    at Account.signAndSendTransactionV2 (/usr/lib/node_modules/near-cli/node_modules/near-api-js/lib/account.js:160:36)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async scheduleFunctionCall (/usr/lib/node_modules/near-cli/commands/call.js:57:38)
    at async Object.handler (/usr/lib/node_modules/near-cli/utils/exit-on-error.js:52:9) {
  type: 'FunctionCallError',
  context: undefined,
  index: 0,
  kind: {
    ExecutionError: `Smart contract panicked: panicked at 'Cannot deserialize the contract state.: Custom { kind: InvalidInput, error: "Unexpected length of input" }', /home/meghaa105/.cargo/registry/src/github.com-1ecc6299db9ec823/near-sdk-3.1.0/src/environment/env.rs:786:46`
  },
  transaction_outcome: {
    block_hash: 'EesG3NjqXdbYZqEYE22nC12AYpU3gkC9uaC7rSjToGSA',
    id: '89g7HhiXgZFZRLntMzFCPk82TQ5m8diwW2nh6jVnEgKz',
    outcome: {
      executor_id: 'share.meghaha.testnet',
      gas_burnt: 2428050684172,
      logs: [],
      metadata: [Object],
      receipt_ids: [Array],
      status: [Object],
      tokens_burnt: '242805068417200000000'
    },
    proof: [ [Object], [Object] ]
  }
}

This error comes for the query
near calladd_notes2 '{"status" : "Trying out writing a smart contract" }'

I have even tried deleting and creating a new account with same or different names. I even tried redeploying the smart contract. Further, I also have added the serialize and deserialize dependencies. I don't know what is going wrong.


Solution

  • Edit: The original answer (which is marked correct) said that the standard Rust Vec can't be used in a NEAR contract. It can along with all the Rust types in https://docs.rs/borsh/0.2.9/borsh/ser/trait.BorshSerialize.html. The NEAR collections https://docs.rs/near-sdk/2.0.1/near_sdk/collections/index.html are recommended for bigger collections as they are more storage efficient, but have few features and are less familiar than Rust built ins.

    Something else must have fixed the issue. Usually "can't deserialize the contract state" in NEAR happens when new contract code is deployed on an existing contract and is not compatible with the data that has been previously stored by the contract.

    Original Answer

    The following code may help to resolve the error. NEAR has it's own datatypes that persist the state of the contract.

    near_sdk::collections::Vector is used in place of Vec.

    The code below replaces Vec with the persistent NEAR Vector:

    /// New imports...
    use near_sdk::collections::{ UnorderedMap, Vector };
    use near_sdk::{ BorshStorageKey };
    
    #[derive(BorshSerialize, BorshStorageKey)]
    enum StorageKeyNotes {
        MapKey,
        OwnKey,
        SharedKey
    }
    
    #[derive(BorshSerialize, BorshDeserialize)]
    pub struct NotesDs {
        pub own: Vector<String>,
        pub shared: UnorderedMap<AccountId, Vector<String>>,
    }
    
    impl NotesDs{
        pub fn new() -> Self {
            assert!(env::state_read::<Self>().is_none(), "Already initialized");
            let mut notesDs = Self {
                own: Vector::new(StorageKeyNotes::OwnKey),
                shared: UnorderedMap::<AccountId, Vector<String>>::new(StorageKeyNotes::MapKey)
            };
    
            notesDs
        }
    }
    #[near_bindgen]
    #[derive(BorshDeserialize, BorshSerialize)]
    pub struct Note {
        pub note_list : UnorderedMap<AccountId,NotesDs>, 
    }
    
    impl Default for Note {
        fn default() -> Self {
            // Check incase the contract is not initialized
            env::panic(b"The contract is not initialized.")
        }
    }
    
    #[near_bindgen]
    impl Note {
        /// Init attribute used for instantiation.
        #[init]
        pub fn new() -> Self {
            assert!(env::state_read::<Self>().is_none(), "Already initialized");
            Self {
                note_list: UnorderedMap::new(b"h".to_vec()),
            }
        }
        pub fn add_notes2(&mut self, status: String){
            if self.note_list.get(&env::predecessor_account_id()).is_none() {
                let mut temp = NotesDs:: new();
                let mut vec = Vector::new(StorageKeyNotes::OwnKey);
                let mut vec2 = Vector::new(StorageKeyNotes::SharedKey);
                vec.push(&status.clone());
                temp.own = vec;
                temp.shared.insert(&String::from("Max Power"), &vec2);
                self.note_list.insert(&env::predecessor_account_id(), &temp);
            }
            else {
                let mut temp1 = self.note_list.get(&env::predecessor_account_id()).unwrap();
                let mut vec1 = temp1.own;
                vec1.push(&status.clone());
                temp1.own = vec1;
                self.note_list.insert(&env::predecessor_account_id(), &temp1);
            }      
        }
    } 
    

    The code hasn't been tested on chain but could help with solving the error.

    For anybody searching for the similar error:

    Smart contract panicked: panicked at 'Cannot deserialize the contract
     state.: Custom { kind: InvalidData, error: "Not all bytes read" }
    

    It usually means that a new contract has been deployed that does not work with the data that a previous contract stored.

    See Not All Bytes Read Common Solutions