rust - 将 Solana 空投到特定帐户

标签 rust blockchain solana solana-cli anchor-solana

我想将 sols 空投到特定账户,让我的智能合约触发 anchor 测试。每当我运行测试时,我都会遇到错误 Error: Account BdFchxtKbEaWtsbuFX2nbKyZCjhz5LN8vyPukQzJQrME has insufficient funds for spend (1.30250136 SOL) + fee (0.000945 SOL) There was a problem deploying: Output { status: ExitStatus(ExitStatus(256)), stdout: "", stderr: "" }.

错误是不言自明的,但我如何向该特定帐户空投代币,我可以运行 solana airdrop 5但随后它将其空投到另一个帐户 GgRbD2AdibdAtBrQMJJEooco9gKt48Sd98Gn7vZQ1nJK。

我什至尝试使用 solana transfer BdFchxtKbEaWtsbuFX2nbKyZCjhz5LN8vyPukQzJQrME 5 --allow-unfunded-recipient 将代币从一个账户转移到另一个账户但交易只是挂起。

下面是我在 Rust 中使用 Anchor 的智能合约:

use anchor_lang::prelude::*;
use anchor_lang::solana_program::system_program;

declare_id!("BNDCEb5uXCuWDxJW9BGmbfvR1JBMAKckfhYrEKW2Bv1W");

#[program]
pub mod solana_twitter {
    use super::*;
    pub fn send_tweet(ctx: Context<SendTweet>, topic: String, content: String) -> ProgramResult {
        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>,
    #[account(address = system_program::ID)]
    pub system_program: AccountInfo<'info>,
}

#[account]
pub struct Tweet {
    pub author: Pubkey,
    pub timestamp: i64,
    pub topic: String,
    pub content: String,
}

#[error]
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,
}

下面是我在 Typescript 中的测试:

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";
import * as bs58 from "bs58";

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);

        // Ensure it has the right data.
        assert.equal(tweetAccount.author.toBase58(), program.provider.wallet.publicKey.toBase58());
        assert.equal(tweetAccount.topic, 'veganism');
        assert.equal(tweetAccount.content, 'Hummus, am I right?');
        assert.ok(tweetAccount.timestamp);
    });

    it('can send a new tweet without a topic', async () => {
        // Call the "SendTweet" instruction.
        const tweet = anchor.web3.Keypair.generate();
        await program.rpc.sendTweet('', 'gm', {
            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);

        // Ensure it has the right data.
        assert.equal(tweetAccount.author.toBase58(), program.provider.wallet.publicKey.toBase58());
        assert.equal(tweetAccount.topic, '');
        assert.equal(tweetAccount.content, 'gm');
        assert.ok(tweetAccount.timestamp);
    });

    it('can send a new tweet from a different author', async () => {
        // Generate another user and airdrop them some SOL.
        const otherUser = anchor.web3.Keypair.generate();
        const signature = await program.provider.connection.requestAirdrop(otherUser.publicKey, 1000000000);
        await program.provider.connection.confirmTransaction(signature);

        // Call the "SendTweet" instruction on behalf of this other user.
        const tweet = anchor.web3.Keypair.generate();
        await program.rpc.sendTweet('veganism', 'Yay Tofu!', {
            accounts: {
                tweet: tweet.publicKey,
                author: otherUser.publicKey,
                systemProgram: anchor.web3.SystemProgram.programId,
            },
            signers: [otherUser, tweet],
        });

        // Fetch the account details of the created tweet.
        const tweetAccount = await program.account.tweet.fetch(tweet.publicKey);

        // Ensure it has the right data.
        assert.equal(tweetAccount.author.toBase58(), otherUser.publicKey.toBase58());
        assert.equal(tweetAccount.topic, 'veganism');
        assert.equal(tweetAccount.content, 'Yay Tofu!');
        assert.ok(tweetAccount.timestamp);
    });

    it('cannot provide a topic with more than 50 characters', async () => {
        try {
            const tweet = anchor.web3.Keypair.generate();
            const topicWith51Chars = 'x'.repeat(51);
            await program.rpc.sendTweet(topicWith51Chars, 'Hummus, am I right?', {
                accounts: {
                    tweet: tweet.publicKey,
                    author: program.provider.wallet.publicKey,
                    systemProgram: anchor.web3.SystemProgram.programId,
                },
                signers: [tweet],
            });
        } catch (error) {
            assert.equal(error.msg, 'The provided topic should be 50 characters long maximum.');
            return;
        }

        assert.fail('The instruction should have failed with a 51-character topic.');
    });

    it('cannot provide a content with more than 280 characters', async () => {
        try {
            const tweet = anchor.web3.Keypair.generate();
            const contentWith281Chars = 'x'.repeat(281);
            await program.rpc.sendTweet('veganism', contentWith281Chars, {
                accounts: {
                    tweet: tweet.publicKey,
                    author: program.provider.wallet.publicKey,
                    systemProgram: anchor.web3.SystemProgram.programId,
                },
                signers: [tweet],
            });
        } catch (error) {
            assert.equal(error.msg, 'The provided content should be 280 characters long maximum.');
            return;
        }

        assert.fail('The instruction should have failed with a 281-character content.');
    });

    it('can fetch all tweets', async () => {
        const tweetAccounts = await program.account.tweet.all();
        assert.equal(tweetAccounts.length, 3);
    });

    it('can filter tweets by author', async () => {
        const authorPublicKey = program.provider.wallet.publicKey
        const tweetAccounts = await program.account.tweet.all([
            {
                memcmp: {
                    offset: 8, // Discriminator.
                    bytes: authorPublicKey.toBase58(),
                }
            }
        ]);

        assert.equal(tweetAccounts.length, 2);
        assert.ok(tweetAccounts.every(tweetAccount => {
            return tweetAccount.account.author.toBase58() === authorPublicKey.toBase58()
        }))
    });

    it('can filter tweets by topics', async () => {
        const tweetAccounts = await program.account.tweet.all([
            {
                memcmp: {
                    offset: 8 + // Discriminator.
                        32 + // Author public key.
                        8 + // Timestamp.
                        4, // Topic string prefix.
                    bytes: bs58.encode(Buffer.from('veganism')),
                }
            }
        ]);

        assert.equal(tweetAccounts.length, 2);
        assert.ok(tweetAccounts.every(tweetAccount => {
            return tweetAccount.account.topic === 'veganism'
        }))
    });
});

更新 简单地空投到特定帐户有帮助,solana airdrop 3 <Account Address> .另一个相关问题是我的本地集群挂了,为了解决这个问题,我按照以下步骤操作:

  1. 检查本地链是否正在运行 ps au
  2. 终止本地 solana-test-validator 进程
  3. 清理工作区 cargo clean
  4. 删除了 node_modules rm -rf node_modules
  5. 重新安装节点模块 yarn install
  6. 重新运行测试 anchor 测试

最佳答案

首先,尝试确保您的 anchor.toml 的提供者部分像这样设置为测试网

[provider]
cluster = "testnet"
wallet = "/home/yourname/.config/solana/id.json"

此外,使用此命令为测试网设置集群

solana config set --url https://api.testnet.solana.com

检查您的 solana 运行节点中的事件帐户

solana address

它应该显示你的运行节点事件帐户公钥

另外,检查账户余额

solana balance

如果您没有足够的 sol 来运行测试或部署(测试后),您可以通过运行来空投 sol

solana airdrop 2

重点是尝试一次(多次)空投 2 sol

现在您可以再次运行 anchor 测试(在 anchor 构建之后)

关于rust - 将 Solana 空投到特定帐户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70630107/

相关文章:

javascript - 为什么 bitcore-lib 无法正确解码我的比特币交易十六进制?

blockchain - : in memory , 存储在文件或数据库中的实际区 block 链状态数据在哪里?

macos - Rust、OpenSSL、solana-test-validator 库未加载问题

solana - 错误 : 403 Forbidden: Call type exceeds Solana 1. 9.13 版本限制最大帐户大小

solana - 如何使用交易哈希(签名)确认 Solana 上是否发生了交易

string - 是否有 UTF-16 字符串类型的 Rust 库? (用于编写 Javascript 解释器)

rust - 如何在不使用 tokio_proto crate 的情况下从 tokio TCP 连接读取数据?

rust - Rust 中星号的用法是什么?

module - 如何跨模块文件使用宏?

database - 如何使用 LevelDB 访问 GoEthereum Transaction Trie