SOLANAの開発勉強シリーズ6
solana-twitterを作る*前編
正式な名称(アカウントやアドレス)の表記揺れあります
自分なりにわかりやすく、開発勉強日誌6の中で統一させてるつもりなので注意してください
めちゃくちゃ簡単なDApps(webとブロックチェーンが合体したやつ)を作っていく
1回自分でやってみればそこまで難しいものではないが、依存関係の衝突やOSの違いで、チュートリアルでもコピペで簡単に動くものがなかった。バージョンが違うとコマンドが対応してなかったり普通にする
ユウキさんがNOTEを書いてくれているの本当にありがたい!
下記のチュートリアルをやっていく
yarnをインストールしてない人はインストール
まず各種version確認(ターミナルで実行
anchor --version
solana --version
rustup --version
rustc --version
cargo --version
yarn --version
今回の実行環境(macOS
コピペで動くはずだけど、依存関係が大変だった
Windowsを使っている人は動かないかも
anchor-cli 0.26.0
solana-cli 1.18.24
rustup 1.27.1
rustc 1.81.0
cargo 1.81.0
yarn 1.22.22
各種インストールはsolana公式からどうぞ
solana config set --url localhost
solana address
solana-keygen new
cd desktop
anchor init solana-twitter
cd solana-twitter
anchor build
anchor buildを実行すると、deployフォルダにsolana_twitter.so、deployするプログラムのキーペアパス(秘密鍵)が作成される。このへんはsolanaは全てがアカウントだからと覚えてたら良い。そして、その辺をうまくやってくれるのがanchor
solana-test-validator
anchor deploy
anchor deployが完了した。
anchor build、anchor deployで作成した
solana_twitter.so(プログラムファイル)とsolana_twitter-keypair.json(秘密鍵)は
自分のウォレットを設定し作成した為、自分のウォレットが親、
solana_twitter.soが子供のような関係。
solanaは全てがアカウントなので、solana_twitter.soにもアドレスと秘密鍵がある。
権限は親である自分のウォレット(owner)にある。
solana_twitter.soと対話する(プログラムを実行する)には2箇所ある
アドレス欄をsolana_twitter.soのアドレスに変更する必要がある
anchor deployで実行した時表示されたProgram Id:がsolana_twitter.soのアドレス
/Users/###/Desktop/solana-twitter/programs/solana-twitter/src/lib.rs
/Users/###/Desktop/solana-twitter/Anchor.toml
上記2箇所をsolana_twitter.soのアドレスに変更する
変更したら再度build.deployを実行する
anchor build
anchor deploy
上記が完了したら、solana_twitter.soのテストをする
anchor run test
solana-twitter
Your transaction signature 5xXr4Y4s2x4mKPxuXaZrET4DvQi8kFZA4gFfY6U5GwaUC3zW8BeRNBJyfgJM2TC333333333333
✔ Is initialized! (609ms)
1 passing (612ms)
✨ Done in 2.51s.
上記まで完了したら、
solana-test-validator --reset
/Users/###/Desktop/solana-twitter/programs/solana-twitter/src/lib.rs
/Users/###/Desktop/solana-twitter/tests/solana-twitter.ts
2つのコードを書き換える
use anchor_lang::prelude::*;
declare_id!("#####solana_twitter.soのアドレスに書き換える######");
#[program]
pub mod solana_twitter {
use super::*;
pub fn send_tweet(ctx: Context<SendTweet>, topic: String, content: String) -> Result<()> {
let tweet: &mut Account<Tweet> = &mut ctx.accounts.tweet;
let author: &Signer = &ctx.accounts.author;
let clock: Clock = Clock::get().unwrap();
if topic.chars().count() > 50 {
return Err(ErrorCode::TopicTooLong.into())
}
if content.chars().count() > 280 {
return Err(ErrorCode::ContentTooLong.into())
}
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 = 32;
const TIMESTAMP_LENGTH: usize = 8;
const STRING_LENGTH_PREFIX: usize = 4; // Stores the size of the string.
const MAX_TOPIC_LENGTH: usize = 50; // 50 chars max.
const MAX_CONTENT_LENGTH: usize = 280; // 280 chars max.
impl Tweet {
const LEN: usize = DISCRIMINATOR_LENGTH
+ PUBLIC_KEY_LENGTH // Author.
+ TIMESTAMP_LENGTH // Timestamp.
+ STRING_LENGTH_PREFIX + MAX_TOPIC_LENGTH // Topic.
+ STRING_LENGTH_PREFIX + MAX_CONTENT_LENGTH // Content.
+ 6; // パディングを追加して392バイトに調整
}
// // ここで、MAX_TOPIC_LENGTHとMAX_CONTENT_LENGTHを確認してください。
// const MAX_TOPIC_LENGTH: usize = 50; // 50 chars max.
// const MAX_CONTENT_LENGTH: usize = 280; // 280 chars max.
#[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,
}
import * as anchor from '@project-serum/anchor';
import { Program } from '@project-serum/anchor';
import { SolanaTwitter } from '../target/types/solana_twitter';
import * as assert from "assert";
describe('solana-twitter', () => {
// Configure the client to use the local cluster.
// anchor.setProvider(anchor.Provider.env());
const program = anchor.workspace.SolanaTwitter as Program<SolanaTwitter>;
it('can send a new tweet', async () => {
// Call the "SendTweet" instruction.
const tweet = anchor.web3.Keypair.generate();
await program.rpc.sendTweet('veganism', 'Hummus, am I right?', {
accounts: {
tweet: tweet.publicKey,
author: program.provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
},
signers: [tweet],
});
// Fetch the account details of the created tweet.
const tweetAccount = await program.account.tweet.fetch(tweet.publicKey);
console.log(tweetAccount);
});
});
コードの書き換えが完了したら
anchor build
anchor deploy
anchor run test
yarn run v1.22.22
warning package.json: No license field
$ /Users/#####/Desktop/solana-twitter/node_modules/.bin/ts-mocha -p ./tsconfig.json -t 1000000 'tests/**/*.ts'
(node:60745) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
solana-twitter
{
author: PublicKey [PublicKey(自分のウォレットアドレスが表示される)] {
_bn: <BN: 5879add5713eb8d0442024908e261bacff4f58ac0defdeea5752db4ee9b39aa2>
},
timestamp: <BN: 66f940cb>,
topic: 'veganism',
content: 'Hummus, am I right?'
}
✔ can send a new tweet (467ms)
1 passing (470ms)
✨ Done in 1.70s.
ローカル環境での実行ですが、solscanのRPCを
Deploying workspace: h ttp://localhost:8899
上記のh ttp://localhost:8899を入力すると
mainnetの様にsolscanで確認できます
ここまでで前編は終了