I am having trouble resolving the error.
I am now trying to get a list of product data stored in a map in vector form.
#[near_bindgen]
#[derive(Serialize, Deserialize, Debug, BorshDeserialize, BorshSerialize)]
#[serde(crate = "near_sdk::serde")]
pub struct Room {
room_id: U64,
name: String,
image: String,
description: String,
location: String,
price: U128,
owner: AccountId,
}
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize)]
pub struct Rooms {
pub rooms: UnorderedMap<U64, Room>,
}
impl Default for Rooms {
fn default() -> Self {
Self {
rooms: UnorderedMap::new(b"r".to_vec()),
}
}
}
#[near_bindgen]
impl Rooms {
pub fn set_room(
&mut self,
name: String,
image: String,
description: String,
location: String,
price: U128,
) -> U64 {
let timestamp = env::block_timestamp();
let convert_timestamp: U64 = timestamp.into();
let account_id = env::signer_account_id();
self.rooms.insert(
&convert_timestamp.clone(),
&Room {
room_id: convert_timestamp,
name,
image,
description,
location,
price,
owner: account_id,
},
);
convert_timestamp
}
pub fn get_room(&self, room_id: U64) -> Room {
self.rooms.get(&room_id).expect("No Room")
}
pub fn get_rooms(&self) -> Vec<Room> {
Vec::from_iter(self.rooms.values())
}
}
The error occurs when I call get_rooms.
$ near view dev-1658072311649-16892075058144 get_rooms
View call: dev-1658072311649-16892075058144.get_rooms()
An error occured
Error: Querying [object Object] failed: wasm execution failed with error: FunctionCallError(HostError(GuestPanic { panic_msg: "Cannot deserialize element" })).
{
"block_hash": "54p5pS8xrzi7GWzv5YcgpNT33f7RqYdR7sUzHaTdzsqf",
"block_height": 95181885,
"error": "wasm execution failed with error: FunctionCallError(HostError(GuestPanic { panic_msg: \"Cannot deserialize element\" }))",
"logs": []
}
at JsonRpcProvider.query (/Users/user/.config/yarn/global/node_modules/near-api-js/lib/providers/json-rpc-provider.js:123:19)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Account.viewFunction (/Users/user/.config/yarn/global/node_modules/near-api-js/lib/account.js:366:24)
at async exports.callViewFunction (/Users/user/.config/yarn/global/node_modules/near-cli/index.js:98:48)
at async Object.handler (/Users/user/.config/yarn/global/node_modules/near-cli/utils/exit-on-error.js:52:9)
TypedError: Querying [object Object] failed: wasm execution failed with error: FunctionCallError(HostError(GuestPanic { panic_msg: "Cannot deserialize element" })).
{
"block_hash": "54p5pS8xrzi7GWzv5YcgpNT33f7RqYdR7sUzHaTdzsqf",
"block_height": 95181885,
"error": "wasm execution failed with error: FunctionCallError(HostError(GuestPanic { panic_msg: \"Cannot deserialize element\" }))",
"logs": []
}
at JsonRpcProvider.query (/Users/user/.config/yarn/global/node_modules/near-api-js/lib/providers/json-rpc-provider.js:123:19)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Account.viewFunction (/Users/user/.config/yarn/global/node_modules/near-api-js/lib/account.js:366:24)
at async exports.callViewFunction (/Users/user/.config/yarn/global/node_modules/near-cli/index.js:98:48)
at async Object.handler (/Users/user/.config/yarn/global/node_modules/near-cli/utils/exit-on-error.js:52:9) {
type: 'UntypedError',
context: undefined
}
Why do I get an error about serialization only when I get the product information as a vector?
All other functions work fine.
If you know the cause and solution, I would like to know.
I just tested your code and it worked fine for me. You can try calling the method in dev-1658147947569-44192518546131.
Make sure you are using the latest near-sdk (4.0), and that you are importing everything from the right place:
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::{near_bindgen, env, AccountId, collections::{UnorderedMap}};
use near_sdk::json_types::{U64, U128};
use near_sdk::serde::{Serialize, Deserialize};
Related
For the given structs:
#[derive(BorshDeserialize, BorshSerialize)]
struct MarketOption {
proposal_id: u64,
}
#[derive(BorshDeserialize, BorshSerialize)]
struct Market {
description: String,
market_options: Vector<MarketOption>,
}
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize)]
pub struct MarketFactory {
markets: HashMap<String, Market>,
}
First, to initialize storage:
#[near_bindgen]
impl MarketFactory {
#[init]
pub fn new(dao_account_id: AccountId) -> Self {
Self {
markets: HashMap::default(), // <== IS THIS CORRECT? This should be populated in the future
}
}
Then, when getting the data, I'm looking to insert into markets with an empty Vector:
pub fn create_market(&mut self, description: String, market_options: Vector<String>) -> String {
let market_id = self.get_random_market_id();
self.markets.insert(
market_id,
Market {
description,
market_options: Vector::new(b"m"),
},
);
self.process_market_options(&market_id, market_options);
And then, process each market_options to get an ID u64 which should be pushed into Market.market_options:
self.markets
.entry(market_id). // <== GET the MARKET
.market_options // <== GET its market_options, NOT WORKING
.push(MarketOption { proposal_id: id }); // <== PUSH an ID that comes from a promise
Also, should I use HashMap or LookupMap? Vector or Vec?
#[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.
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
I am trying to run the following code in Anchor Solana, with program in rust as follows:
use anchor_lang::prelude::*;
declare_id!("RnbXAWg5mCvmSafjd1CnYaz32qLgZHdeHK6xzHDi1yU");
#[program]
pub mod sol_proj_1 {
use super::*;
pub fn initialize(ctx: Context<Initialize>, data: u64) -> ProgramResult {
let my_account = &mut ctx.accounts.my_account;
my_account.data = data;
println!("hello there!");
Ok(())
}
pub fn update(ctx: Context<Update>, data: u64) -> ProgramResult {
let my_account = &mut ctx.accounts.my_account;
my_account.data = data;
Ok(())
}
}
// #[derive(Accounts)]
// pub struct Initialize {}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init, payer = user, space = 8 + 8)]
pub my_account: Account<'info, MyAccount>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Update<'info> {
#[account(mut)]
pub my_account: Account<'info, MyAccount>,
}
#[account]
pub struct MyAccount {
pub data: u64,
}
The test program is as follow:
import * as anchor from '#project-serum/anchor';
import { Program } from '#project-serum/anchor';
import { SolProj1 } from '../target/types/sol_proj_1';
const assert = require("assert");
describe('sol_proj_1', () => {
// Configure the client to use the local cluster.
const provider = anchor.Provider.local();
anchor.setProvider(provider);
// The Account to create.
const myAccount = anchor.web3.Keypair.generate();
const program = anchor.workspace.SolProj1 as Program<SolProj1>;
it('Is initialized!', async () => {
// Add your test here.
const tx = await program.rpc.initialize(new anchor.BN(1234), {
accounts: {
myAccount: myAccount.publicKey,
user: provider.wallet.publicKey,
systemProgram: program.programId,
},
signers: [myAccount],
});
/
console.log("Your transaction signature", tx);
});
});
With error when I run the following command
Anchor test
1) sol_proj_1
Is initialized!:
Error: failed to send transaction: invalid transaction: Transaction failed to sanitize accounts offsets correctly
at Connection.sendEncodedTransaction (node_modules/#solana/web3.js/src/connection.ts:3740:13)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at Connection.sendRawTransaction (node_modules/#solana/web3.js/src/connection.ts:3700:20)
at sendAndConfirmRawTransaction (node_modules/#solana/web3.js/src/util/send-and-confirm-raw-transaction.ts:27:21)
at Provider.send (node_modules/#project-serum/anchor/src/provider.ts:118:18)
at Object.rpc [as initialize] (node_modules/#project-serum/anchor/src/program/namespace/rpc.ts:25:23)
I tried the following
change the program ownership as I found that this can cause the issue but that did not work.
I also added entries in Anchor.toml, the tests are running on localhost
I found that empty wallet may also cause this issue but I have airdrop 100 sols in it
The Rust code deploys correctly but the test is failing the 'sanitizationfailure' is listed as follow "Transaction failed to sanitize accounts offsets correctly implies that account locks are not taken for this TX, and should not be unlocked." I couldn't find any info how to take out the locks
source: https://docs.rs/solana-sdk/1.9.2/solana_sdk/transaction/enum.TransactionError.html
Any help is appreciated!
The only thing I can see obvious is maybe the way you're passing in the system program from the frontend. You're passing in your program's id, when you should be passing the in system program id. So instead, try:
const tx = await program.rpc.initialize(new anchor.BN(1234), {
accounts: {
myAccount: myAccount.publicKey,
user: provider.wallet.publicKey,
systemProgram: SystemProgram.programId,
},
signers: [myAccount],
});
I had this error before and have solved.
In my case, I find that the Program_Id in Anchor.toml is different from lib.rs, they should be the same.
Program_Id is generated by running "anchor deploy" in terminal.
Anchor.toml
[programs.localnet]
solana_app = "<Program_ID>"
lib.rs
declare_id!("<Program_ID>");
Running "anchor deploy" in terminal.
And copy the program id in Anchor.toml and lib.rs
I´m writing a smart contract with rust in near protocol. I have the following struct for the main contract:
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
pub struct Contract {
pub total_transactions: u64,
pub owner_id: AccountId,
pub transactions_per_account: LookupMap<AccountId, UnorderedSet<TransactionId>>,
pub transaction_by_id: LookupMap<TransactionId, Transaction>,
pub transaction_metadata_by_id: UnorderedMap<TransactionId, TransactionMetadata>,
}
I have already written a function to initialize the contract as the following:
#[derive(BorshSerialize)]
pub enum StorageKey {
TransactionsPerAccount,
TransactionById,
TransactionMetadataById,
}
#[near_bindgen]
impl Contract {
#[init]
pub fn new(owner_id: AccountId) -> Self {
let this = Self {
total_transactions: 0,
owner_id,
transactions_per_account: LookupMap::new(StorageKey::TransactionsPerAccount.try_to_vec().unwrap()),
transaction_by_id: LookupMap::new(StorageKey::TransactionById.try_to_vec().unwrap()),
transaction_metadata_by_id: UnorderedMap::new(
StorageKey::TransactionMetadataById.try_to_vec().unwrap(),
),
};
//return the Contract object
this
}
}
But there the UnorderedSet that is inside the LookupMap transactions_per_account is not initialize because it is supposed that there will be an UnorderedSet that corresponds to each user, so it should be created when a user log in for first time and creates an account:
I tried to write that function as the following:
#[payable]
pub fn create_transaction( //implement storage management for transactions
&mut self,
seller_id: AccountId,
buyer_id: AccountId,
price: Price,
nft_id: TokenId,
nft_contract_id: AccountId,
) -> Transaction {
let sender = env::predecessor_account_id();
let transaction = Transaction {
transaction_id: self.total_transactions,
creator_id: sender.clone(),
seller_id: seller_id.clone(),
buyer_id: buyer_id.clone(),
price: price,
nft_id: nft_id.clone(),
nft_contract_id: nft_contract_id.clone(),
amount_in_escrow: false,
token_in_escrow: false,
transaction_status: TransactionStatus::Pending,
};
//let account_as_key = transaction.creator_id.try_to_vec().unwrap();
// update number of transactions
self.total_transactions += 1;
let unordered_set = self.transactions_per_account.get(&transaction.creator_id);
match unordered_set {
Some(mut set) => {
set.insert(&transaction.transaction_id);
},
None => {
let mut set = UnorderedSet::new(&*transaction.creator_id.try_to_vec().unwrap());
set.insert(&transaction.transaction_id);
self.transactions_per_account.insert(&transaction.creator_id, &set);
},
}
self.transaction_by_id.insert(&transaction.transaction_id, &transaction);
transaction
}
Cargo check let it pass with no error but when trying to compile I got the following error:
error[E0277]: the trait bound `UnorderedSet<u64>: Serialize` is not satisfied
--> src/lib.rs:133:1
|
133 | #[near_bindgen]
| ^^^^^^^^^^^^^^^ the trait `Serialize` is not implemented for `UnorderedSet<u64>`
|
note: required by a bound in `to_vec`
--> /home/walquer/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.78/src/ser.rs:2193:17
|
2193 | T: ?Sized + Serialize,
| ^^^^^^^^^ required by this bound in `to_vec`
= note: this error originates in the attribute macro `near_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0277`.
I believe the error is caused by a erroneous initialization of the UnorderedSet collection that was defined inside the struct that do have the serialize trait.
Can someone tell me what im missing?
I've recently started learning Rust, and I'm currently trying to create a small API; I've made my own struct for an API Response and enum for an Error:
// API Response Structure
pub struct ApiResponse {
pub body: JsonValue,
pub status: Status,
}
// Enum for my "custom errors"
#[derive(Debug, Snafu, Clone, Serialize)]
pub enum Errors {
#[snafu(display("Unable to retrieve the specified entry."))]
NotFound,
#[snafu(display("Internal Server Error, unable to process the data."))]
ISE,
}
Then I've implemented the Responder<'_> trait for my API Response struct:
impl<'r> Responder<'r> for ApiResponse {
fn respond_to(self, req: &Request) -> Result<Response<'r>, Status> {
Response::build_from(self.body.respond_to(req).unwrap())
.status(self.status)
.header(ContentType::JSON)
.ok()
}
}
However, when I try to use the mentioned, it would seem as I cannot have my function return a Result<JsonValue, Errors>. I'm not quite sure about this issue, nor am I that experienced with Rust, so any documentation/pointers will be greatly appreciated.
Here's the function which returns the Response type.
#[put("/users/<user_id>", format = "json", data = "<new_user>")]
pub fn update_user(
conn: DbConnection,
user_id: i32,
new_user: Json<NewUser>,
) -> Result<JsonValue, ApiResponse> {
match users::table.find(user_id).load::<User>(&*conn) {
Ok(result) => {
if result.len() < 1 {
let response = ApiResponse {
body: json!({
"message": Errors::NotFound
}),
status: Status::NotFound
};
return Err(response)
}
},
Err(e) => {
let response = ApiResponse {
body: json!({
"message": Errors::ISE
}),
status: Status::InternalServerError
};
return Err(response);
},
}
match diesel::update(users::table.filter(id.eq(user_id)))
.set((
user_name.eq(new_user.user_name.to_string()),
age.eq(new_user.age),
gender.eq(new_user.gender.to_string()),
))
.get_result::<User>(&*conn)
{
Ok(result) => Ok(json!(result)),
Err(_) => {
let res = ApiResponse {
body: json!({
"message": Errors::ISE
}),
status: Status::InternalServerError
};
return Err(res);
},
}
}
Side-note: Please keep in mind that I'm still a beginner with Rust, and my error handling / code in general is not the best.
Edit: I forgot to include the error stack:
error[E0277]: the trait bound `std::result::Result<rocket_contrib::json::JsonValue, api_cont::ApiResponse>: rocket::response::Responder<'_>` is not satisfied
--> src/routes.rs:72:6
|
72 | ) -> Result<JsonValue, ApiResponse> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `rocket::response::Responder<'_>` is not implemented for `std::result::Result<rocket_contrib::json::JsonValue, api_cont::ApiResponse>`
|
::: /home/kenneth/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.4.4/src/handler.rs:202:20
|
202 | pub fn from<T: Responder<'r>>(req: &Request, responder: T) -> Outcome<'r> {
| ------------- required by this bound in `rocket::handler::<impl rocket::Outcome<rocket::Response<'r>, rocket::http::Status, rocket::Data>>::from`
|
= help: the following implementations were found:
<std::result::Result<R, E> as rocket::response::Responder<'r>>
<std::result::Result<R, E> as rocket::response::Responder<'r>>
I've run into this error as well.
The following is mentioned in the API Docs:
A type implementing Responder should implement the Debug trait when possible. This is because the Responder implementation for Result requires its Err type to implement Debug. Therefore, a type implementing Debug can more easily be composed.
That means you must implement Debug, as you use ApiResponse as an Err type.
#[derive(Debug)]
pub struct ApiResponse {
pub body: JsonValue,
pub status: Status,
}