[英]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.