简体   繁体   English

尝试使用 Anchor 在 Devnet 上初始化 VRF 时我的事务失败(0x0 错误)

[英]My transaction fails when trying to Init VRF on Devnet using Anchor (0x0 Error)

I'm trying to use a VRF for Solana to generate random numbers, I'm using CPI to do this.我正在尝试为 Solana 使用 VRF 来生成随机数,我正在使用 CPI 来执行此操作。 When running the test on Localhost it works fine and generates the numbers.在 Localhost 上运行测试时,它可以正常工作并生成数字。

However when I switch to Devnet it fails with the error:但是,当我切换到 Devnet 时,它会因错误而失败:

Transaction simulation failed Custom Error 0x0交易模拟失败自定义错误 0x0

I'm using Orao-VRF: Github我正在使用 Orao-VRF: Github

My lib.rs code:我的 lib.rs 代码:

use anchor_lang::prelude::*;
use orao_solana_vrf::network_state_account_address;
use orao_solana_vrf::program::OraoVrf;
use orao_solana_vrf::randomness_account_address;
use orao_solana_vrf::state::NetworkState;
use orao_solana_vrf::CONFIG_ACCOUNT_SEED;
use orao_solana_vrf::RANDOMNESS_ACCOUNT_SEED;
use std::mem::size_of;

declare_id!("6ag7tVY7RizWm4xZr7Vv3N4yGio5mqS6H9VFAUFvuMQt");

#[program]
pub mod cflip {
    use orao_solana_vrf::cpi::accounts::Request;

    use super::*;

    pub fn spin_and_pull_the_trigger(
        ctx: Context<SpinAndPullTheTrigger>,
        force: [u8; 32],
    ) -> Result<()> {
        // Zero seed is illegal in VRF
        if force == [0_u8; 32] {
            return Err(Error::YouMustSpinTheCylinder.into());
        }

        // Request randomness.
        let cpi_program = ctx.accounts.vrf.to_account_info();
        let cpi_accounts = Request {
            payer: ctx.accounts.player.to_account_info(),
            network_state: ctx.accounts.config.to_account_info(),
            treasury: ctx.accounts.treasury.to_account_info(),
            request: ctx.accounts.random.to_account_info(),
            system_program: ctx.accounts.system_program.to_account_info(),
        };
        let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
        orao_solana_vrf::cpi::request(cpi_ctx, force)?;

        fn get_random(randomness: &[u8; 64]) -> u8 {
            // use only first 8 bytes for simplicyty
            let value = &randomness[0..size_of::<u64>()];
            return value[0];
        }

        Ok(())
    }
}

#[derive(Accounts)]
#[instruction(force: [u8; 32])]
pub struct SpinAndPullTheTrigger<'info> {
    #[account(mut)]
    player: Signer<'info>,
    /// CHECK:
    #[account(
        mut,
        seeds = [RANDOMNESS_ACCOUNT_SEED.as_ref(), &force],
        bump,
        seeds::program = orao_solana_vrf::ID
    )]
    random: AccountInfo<'info>,
    /// CHECK:
    #[account(mut)]
    treasury: AccountInfo<'info>,
    #[account(
        mut,
        seeds = [CONFIG_ACCOUNT_SEED.as_ref()],
        bump,
        seeds::program = orao_solana_vrf::ID
    )]
    config: Account<'info, NetworkState>,
    vrf: Program<'info, OraoVrf>,
    system_program: Program<'info, System>,
}

#[error_code]
pub enum Error {
    #[msg("The player is already dead")]
    PlayerDead,
    #[msg("Unable to serialize a randomness request")]
    RandomnessRequestSerializationError,
    #[msg("Player must spin the cylinder")]
    YouMustSpinTheCylinder,
    #[msg("The cylinder is still spinning")]
    TheCylinderIsStillSpinning,
}

/// Helper that builds the instruction.
#[cfg(feature = "sdk")]
pub fn spin_and_pull_the_trigger<'a>(
    cflip: &'a anchor_client::Program,
    vrf: &anchor_client::Program,
) -> std::result::Result<anchor_client::RequestBuilder<'a>, anchor_client::ClientError> {
    let seed = rand::random();

    // vrf accounts
    let network_state_address = network_state_account_address();
    let request_address = randomness_account_address(&seed);

    let vrf_config = vrf.account::<NetworkState>(network_state_address)?.config;

    Ok(cflip
        .request()
        .accounts(crate::accounts::SpinAndPullTheTrigger {
            player: cflip.payer(),
            treasury: vrf_config.treasury,
            random: request_address,
            config: network_state_address,
            vrf: orao_solana_vrf::id(),
            system_program: anchor_client::solana_sdk::system_program::ID,
        })
        .args(crate::instruction::SpinAndPullTheTrigger { force: seed }))
}

My test.ts code:我的 test.ts 代码:

import assert from "assert";
import * as anchor from "@project-serum/anchor";
import { Program, BN, Spl } from "@project-serum/anchor";
import {
    Keypair,
    PublicKey,
    SystemProgram,
    LAMPORTS_PER_SOL,
    SYSVAR_RENT_PUBKEY,
    SYSVAR_INSTRUCTIONS_PUBKEY,
    Ed25519Program,
} from "@solana/web3.js";
import { Orao, networkStateAccountAddress, randomnessAccountAddress } from "../js/dist";
import { Cflip } from "../target/types/cflip";
import nacl from "tweetnacl";

describe("cflip", () => {
    const provider = anchor.AnchorProvider.env();
    anchor.setProvider(provider);

    const program = anchor.workspace.Cflip as Program<Cflip>;
    const vrf = new Orao(provider);

    // This accounts are for test VRF.
    const treasury = Keypair.generate();
    const fulfillmentAuthority = Keypair.generate();

    // Initial force for russian-roulette
    let force = Keypair.generate().publicKey;

    // This helper will play a single round of russian-roulette.
    async function spinAndPullTheTrigger(force: Buffer) {
        const random = randomnessAccountAddress(force);

        await program.methods
            .spinAndPullTheTrigger([...force])
            .accounts({
                player: provider.wallet.publicKey,
                vrf: vrf.programId,
                config: networkStateAccountAddress(),
                treasury: treasury.publicKey,
                random,
                systemProgram: SystemProgram.programId,
            })
            .rpc();
    }

    // This helper will fulfill randomness for our test VRF.
    async function emulateFulfill(seed: Buffer) {
        let signature = nacl.sign.detached(seed, fulfillmentAuthority.secretKey);
        await vrf.methods
            .fulfill()
            .accounts({
                instructionAcc: SYSVAR_INSTRUCTIONS_PUBKEY,
                networkState: networkStateAccountAddress(),
                request: randomnessAccountAddress(seed),
            })
            .preInstructions([
                Ed25519Program.createInstructionWithPublicKey({
                    publicKey: fulfillmentAuthority.publicKey.toBytes(),
                    message: seed,
                    signature,
                }),
            ])
            .rpc();
    }


    before(async () => {
        await provider.connection.confirmTransaction(
            await provider.connection.requestAirdrop(treasury.publicKey, 1 * LAMPORTS_PER_SOL),
            "confirmed"
          );

        // Initialize test VRF
        const fee = 1 * LAMPORTS_PER_SOL;
        const fullfillmentAuthorities = [
            fulfillmentAuthority.publicKey,
        ];
        
        const configAuthority = Keypair.generate();

        await vrf.methods
            .initNetwork(
                new BN(fee),
                configAuthority.publicKey,
                fullfillmentAuthorities,
                null
            )
            .accounts({
                networkState: networkStateAccountAddress(),
                treasury: treasury.publicKey,
            })
            .rpc();
    });

    it("spin and pull the trigger", async () => {
        await spinAndPullTheTrigger(force.toBuffer());

        await emulateFulfill(force.toBuffer());
        const randomness = await vrf.getRandomness(force.toBuffer());

        console.log(randomness.randomness);
    });
});

From what I've gathered it's something to do with this before block in the tests file:从我收集到的内容来看,这与测试文件中的 before 块有关:

    before(async () => {
        await provider.connection.confirmTransaction(
            await provider.connection.requestAirdrop(treasury.publicKey, 1 * LAMPORTS_PER_SOL),
            "confirmed"
          );

        // Initialize test VRF
        const fee = 1 * LAMPORTS_PER_SOL;
        const fullfillmentAuthorities = [
            fulfillmentAuthority.publicKey,
        ];
        
        const configAuthority = Keypair.generate();

        await vrf.methods
            .initNetwork(
                new BN(fee),
                configAuthority.publicKey,
                fullfillmentAuthorities,
                null
            )
            .accounts({
                networkState: networkStateAccountAddress(),
                treasury: treasury.publicKey,
            })
            .rpc();
    });

Any help would be massively appreciated.任何帮助将不胜感激。 Thank you.谢谢你。

VRF program on devnet is already initialized with our config, so you can't initialize it. devnet 上的 VRF 程序已经用我们的配置初始化了,所以你不能初始化它。 The emulateFulfill function will throw UnauthorizedFulfillmentAuthority exception because your fulfillmentAuthority key is not whitelisted. emulateFulfill function 将抛出UnauthorizedFulfillmentAuthority异常,因为您的fulfillmentAuthority 密钥未列入白名单。 Try something like this, don't forget to change the program ID with your own cflip program ID试试这样的,别忘了用自己的cflip程序ID改程序ID

import * as anchor from "@project-serum/anchor";
import { Program } from "@project-serum/anchor";
import {
    Keypair,
    PublicKey,
    SystemProgram,
} from "@solana/web3.js";
import { Orao, networkStateAccountAddress, randomnessAccountAddress } from "@orao-network/solana-vrf";
import { Cflip, IDL } from "../target/types/cflip";

describe("cflip", () => {
    const provider = anchor.AnchorProvider.env();
    anchor.setProvider(provider);

    const program = new Program<Cflip>(IDL, new PublicKey("2XeJv53N1UzbupYNDH9PDakRWQFS4VX4bJDPm8P5T64J"), provider);
    const vrf = new Orao(provider);

    // Initial force for russian-roulette
    let force = Keypair.generate().publicKey;

    // This helper will play a single round of russian-roulette.
    async function spinAndPullTheTrigger(force: Buffer) {
        const random = randomnessAccountAddress(force);
        const networkState = await vrf.getNetworkState()
        const treasury = networkState.config.treasury

    await program.methods
        .spinAndPullTheTrigger([...force])
        .accounts({
            player: provider.wallet.publicKey,
            vrf: vrf.programId,
            config: networkStateAccountAddress(),
            treasury,
            random,
            systemProgram: SystemProgram.programId,
        })
        .rpc();
}

it("spin and pull the trigger", async () => {
    await spinAndPullTheTrigger(force.toBuffer());

    // Await fulfilled randomness (default commitment is "finalized"):
    const randomness = await vrf.waitFulfilled(force.toBuffer());
    console.log("Your randomness is " + randomness.fulfilled());
    });
});

What is your Anchor.toml?你的 Anchor.toml 是什么? Also i think you use the SDK not the CPI, it would be more helpful if you posted more code.另外我认为您使用的是 SDK 而不是 CPI,如果您发布更多代码会更有帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 初始令牌帐户错误 - “错误处理指令 0:自定义程序错误:0x0” - Init Token Account error - "Error processing Instruction 0: custom program error: 0x0" 交易模拟失败:错误处理指令0:自定义程序错误:0x0 - Transaction simulation failed: Error processing Instruction 0: custom program error: 0x0 Solana 锚点错误:发送交易失败:交易无效:交易未能正确清理账户偏移 - Solana Anchor Error: failed to send transaction: invalid transaction: Transaction failed to sanitize accounts offsets correctly 为什么在使用请求时解析我的日期成功,而在使用reqwests时解析失败? - Why parsing my date succeeds when using request, but fails when using reqwests? 我的锚点测试在 test.js 中不起作用,无效参数错误 - My anchor test is not working in test.js, invalid argument error 尝试打开具体错误类型时,为什么我的错误在静态生存期内必须有效? - Why must my error be valid for the static lifetime when trying to switch on a concrete error type? 使用本地用户时,Windows 10 上的 Cargo 因“虚假网络错误:操作超时”而失败 - Cargo fails with “spurious network error: The operation timed out” on Windows 10 when using a local user 尝试在Windows上编译时出错 - Error when trying to compile on Windows 使用rust-websocket时如何处理错误,以便仅该连接失败而不是整个程序失败? - How do I handle an error when using rust-websocket so that only that connection fails and not the entire program? 通过 system_instruction::create_account(带锚框架的链上程序)创建新帐户时,Solana CPI(运行时)调用失败 - Solana CPI (runtime) invoke fails when creating a new account by system_instruction::create_account (on-chain program with anchor framework)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM