Quantcast
Channel: Recent Questions - Solana Stack Exchange
Viewing all articles
Browse latest Browse all 7925

Anchor / Solana: where to specify commitment level?

$
0
0

I am learning the basics of creating dApps using Solana/Anchor by following these series of articles. It is now outdated, but nonetheless, it's a great way to start.

So, straight to the question details. The contract looks like this:

use std::mem::size_of;use anchor_lang::prelude::*;declare_id!("B3W8FdURNLEEJncJNEFfu3Jfui7PTbpAcuXDnbA4Ctin");#[program]pub mod solana_twitter {    use super::*;    pub fn send_tweet(ctx: Context<SendTweet>, topic: String, content: String) -> Result<()> {        if topic.chars().count() > 50 {            return err!(ErrorCode::TopicTooLong);        }        if content.chars().count() > 280 {            return err!(ErrorCode::ContentTooLong);        }        let tweet = &mut ctx.accounts.tweet;        let author: &Signer = &ctx.accounts.author;        let clock: Clock = Clock::get().unwrap();        tweet.author = *author.key;        tweet.timestamp = clock.unix_timestamp;        tweet.topic = topic;        tweet.content = content;        Ok(())    }}#[derive(Accounts)]pub struct SendTweet<'info> {    #[account(init, payer = author, space = Tweet::LEN)]    pub tweet: Account<'info, Tweet>,    #[account(mut)]    pub author: Signer<'info>,    pub system_program: Program<'info, System>,}#[account]pub struct Tweet {    pub author: Pubkey,    pub timestamp: i64,    pub topic: String,    pub content: String,}const DISCRIMINATOR_LENGTH: usize = 8;const PUBLIC_KEY_LENGTH: usize = size_of::<Pubkey>();const TIMESTAMP_LENGTH: usize = size_of::<i64>();const STRING_LENGTH_PREFIX: usize = 4;const MAX_TOPIC_LENGTH: usize = 50 * STRING_LENGTH_PREFIX;const MAX_CONTENT_LENGTH: usize = 280 * 4;impl Tweet {    const LEN: usize = DISCRIMINATOR_LENGTH // Discriminator (present in all accounts by default)+ PUBLIC_KEY_LENGTH // Author.+ TIMESTAMP_LENGTH // Timestamp.+ STRING_LENGTH_PREFIX + MAX_TOPIC_LENGTH // Topic.+ STRING_LENGTH_PREFIX + MAX_CONTENT_LENGTH; // Content.}#[error_code]pub enum ErrorCode {    #[msg("The provided topic should be 50 characters long maximum.")]    TopicTooLong,    #[msg("The provided content should be 280 characters long maximum.")]    ContentTooLong,}

In episode 10, the author introduces commitment levels - and uses them to guarantee that our transaction performed successfully. He does that by using this code:

useWorkspace.js:

import { computed } from "vue";import { useAnchorWallet } from "solana-wallets-vue";import { Connection } from "@solana/web3.js";import { AnchorProvider, Program } from "@coral-xyz/anchor";import idl from "../../../target/idl/solana_twitter.json";let workspace = null;export const useWorkspace = () => workspace;const preflightCommitment = 'confirmed'const commitment = 'confirmed'export const initWorkspace = () => {  const wallet = useAnchorWallet();  const connection = new Connection("http://127.0.0.1:8899", commitment);  const provider = computed(() => new AnchorProvider(connection, wallet.value, { preflightCommitment, commitment }));  const program = computed(() => new Program(idl, provider.value));  workspace = {    wallet,    connection,    provider,    program,  };};

send-tweet.js:

import { web3 } from "@coral-xyz/anchor";import { useWorkspace } from "@/composables";import { Tweet } from "@/models";export const sendTweet = async (topic, content) => {  const { wallet, program, connection } = useWorkspace();  const tweet = web3.Keypair.generate();  const txSignature = await program.value.rpc.sendTweet(topic, content, {    accounts: {      author: wallet.value.publicKey,      tweet: tweet.publicKey,      systemProgram: web3.SystemProgram.programId,    },    signers: [tweet],  });  // fetch the newly created account  const tweetAccount = await program.value.account.tweet.fetch(tweet.publicKey);  return new Tweet(tweet.publicKey, tweetAccount);};

which is later utilized in App.vue:

<script setup>import { useRoute } from 'vue-router'import TheSidebar from './components/TheSidebar'import { PhantomWalletAdapter, SolflareWalletAdapter } from '@solana/wallet-adapter-wallets'import { initWallet } from 'solana-wallets-vue'import { initWorkspace } from '@/composables'const route = useRoute()const wallets = [    new PhantomWalletAdapter(),    new SolflareWalletAdapter(),]initWallet({ wallets, autoConnect: true })initWorkspace()</script>

The purpose of the code is to initialize the workspace consisting of connection, provider, wallet and program - and when user connects the wallet and tries to send a tweet - it must send the tweet using RPC API.

However, this code doesn't work. What DOES work, is the following send-tweet.js content:

import { web3 } from "@coral-xyz/anchor";import { useWorkspace } from "@/composables";import { Tweet } from "@/models";export const sendTweet = async (topic, content) => {  const { wallet, program, connection } = useWorkspace();  const tweet = web3.Keypair.generate();  const txSignature = await program.value.rpc.sendTweet(topic, content, {    accounts: {      author: wallet.value.publicKey,      tweet: tweet.publicKey,      systemProgram: web3.SystemProgram.programId,    },    signers: [tweet],    options: {      preflightCommitment: program.value.provider.opts.preflightCommitment,      commitment: program.value.provider.opts.commitment,    },  });  // wait on the blockchain reflection of the transaction   await connection.confirmTransaction(txSignature, program.value.provider.opts.commitment);  // fetch the newly created account  const tweetAccount = await program.value.account.tweet.fetch(tweet.publicKey);  return new Tweet(tweet.publicKey, tweetAccount);};

...where we manually specify commitments in both(!) options when calling program.value.rpc.sendTweet() and in connection.confirmTransaction(). If any of these is not specified, I'm getting this error:

Error: Simulation failed. Message: Transaction simulation failed: Blockhash not found.

This rises a couple of questions:

  1. Why do we need to specify commitment options in 4(!) places?
  2. If we already passed an AnchorProvider, with already set preflightCommitment and commitment properties, into our Program, why do we need to specify them again when sending a tweet? I mean, the program should already know the values of these properties!
  3. What is the perfect solution in this case, and that is the minimum subset of places where we must specify these properties?

Any help would be appreciated.


Viewing all articles
Browse latest Browse all 7925

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>