Expand description
§ORAO VRF Callback
A crate to interact with the orao-vrf-cb
smart contract on the Solana network.
Provides an interface to request verifiable randomness (Ed25519 Signature) on the Solana network and receive a CPI callback upon fulfill.
§Crate features
-
sdk
(default) — use this feature to build an off-chain client -
cpi
— use this feature to integrate your program with the oracle[dependencies.orao-solana-vrf-cb] version = "..." default-features = false features = ["cpi"]
§Integration
The integration process consists of the following steps:
- Write and deploy a client program. It must be able to invoke either
Request
orRequestAlt
instruction via CPI. It might define a callback — in fact any program instruction could be called. - Register your program as a VRF client by sending the
Register
instruction. - Fund a new client created on a previous step (just transfer some SOL to the
Client
PDA). - Now you are ready to perform a
Request
/RequestAlt
instruction CPI.
§Callback functionality
§Side Note
Due to historical reasons callback functionality is split in two parts with slightly different capabilities:
Callback
— normal callbackCallbackAlt
— ALT here stands for Address Lookup Tables. This type of callback is able to use Solana’s feature that allows developers to create a collection of related addresses to efficiently load more addresses in a single transaction. This is only possible for a request-level callback (see bellow).For the same reason there are two kinds of request accounts:
RequestAccount
— request account created by theRequest
instruction.RequestAltAccount
— request account created by theRequestAlt
instruction.
§Account Order Convention
There is a convention that RequestAlt
instruction follows:
If
n
is the number of Lookup Tables used by a callback then the firstn
accounts in theContext::remaining_accounts
list must be the corresponding Lookup Table accounts.
Namely the instruction accepts the RequestAltParams::num_lookup_tables
parameter
and expects the extended list of accounts (see the “Accounts” section in RequestAlt
docs)
There is a helper function that simplifies preparing Lookup Table accounts
for the RequestAlt
instruction that is parse_lookup_tables
so you are
encouraged to use it to prepare the CPI call. You also may follow the same
convention if you are using the Anchor Framework:
let mut cpi_call_remaining_accounts = ctx
.remaining_accounts
.get(..num_lookup_tables as usize)
.expect("call does not follow the convention")
.to_vec();
let lookup_tables = orao_vrf_cb::utils::parse_lookup_tables(&cpi_call_remaining_accounts)?;
// 1. prepare the callback using `CallbackAlt::compile_accounts`
// and `lookup_tables` obtained above
// 2. extend cpi_call_remaining_accounts with writable accounts if necessary
let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts)
.with_signer(signers_seeds)
.with_remaining_accounts(cpi_call_remaining_accounts);
orao_vrf_cb::cpi::request_alt(
cpi_ctx,
RequestAltParams::new(seed)
.with_callback(Some(callback))
.with_num_lookup_tables(num_lookup_tables),
)?;
§Callback
A callback is an instruction invoked via CPI as soon as the randomness request is fulfilled.
Note that callbacks are optional. You can go without a callback giving None
during the
client registration. Also note, that there are two levels of callbacks:
- Client-level callback — defined either upon or after the client registration.
This callback will be used for every
Request
(notRequestAlt
) of this client if not overridden by the Request-level callback. Effective client level callback could be observed in theClient::callback
field of the Client PDA and could be updated using theSetCallback
instruction. - Request-level callback — sets a callback for the current request
Request
orRequestAlt
(overrides the Client-level callback).
§Callback rules
-
callback instruction will be called as an instruction of the registered program
-
callback instruction will be called with the following list of accounts:
- The
Client
PDA (signer). - The state PDA (writable) (see
Client::state
). - The
NetworkState
PDA (read-only). - The corresponding
RequestAccount
PDA (read-only). - [ … zero or more remaining accounts (see bellow) ]
- The
§Remaining accounts of a callback
Use the following helpers to add remaining accounts to the callback:
- for a normal
Callback
— useCallback::with_remaining_account
andCallback::with_remaining_accounts
helpers. Or just directly extend theCallback::remaining_accounts
field. - for a
CallbackAlt
— first create a vec ofRemainingAccount
s and then use theCallbackAlt::compile_accounts
helper.
There exists three kinds of remaining accounts:
- Arbitrary read-only account — it is possible to give an arbitrary
read-only account to a callback. Use the
RemainingAccount::readonly
constructor to build one. - Arbitrary writable account — it is possible to give an arbitrary
writable account as long as it is authorized by the caller - i.e.
if it is given as writable to the corresponding
Request
/RequestAlt
orRegister
instruction. Use theRemainingAccount::arbitrary_writable
constructor. - Writable PDA — it is always possible to give a writable account as long
as it is a PDA of the client program - just provide the proper seeds so
that VRF is able to verify the address. Use the
RemainingAccount::writable
constructor.
§Callback faults
If Callback invocation is somehow fails then it is considered as a client misbehavior - well-written client’s callback should never fail.
There are two kinds of callback faults possible:
- On-chain fail — callback failed after the instruction was accepted by the network. This faulty call is visible on-chain and the logs could be easily inspected.
- Off-chain fail — callback failed before the instruction was accepted
by the network. This faulty call is not visible on-chain and appears as
a request that not get fulfilled (in fact it will be fulfilled after the
callback_deadline
reached). We’re working on making it easier to debug such a case.
In any case the oracle will continue trying to fulfill such a client’s request
with increasing interval but eventually will fulfill it without invoking the
Callback at all (see NetworkConfiguration::callback_deadline
).
§Clients
Any program may register any number of clients as long as unique state PDA is used for every registration. Every registered client maintains a SOL balance used to pay request fee and rent (note that the rent is reimbursed upon the fulfill).
It is trivial to fund a client — you should transfer some SOL to its address.
The Withdraw
instruction should be used to withdraw client funds but note
that you couldn’t withdraw past the Client
PDA rent.
The client ownership might be transferred using the Transfer
instruction.
Re-exports§
pub use constants::*;
pub use instructions::*;
Modules§
- accounts
- An Anchor generated module, providing a set of structs
mirroring the structs deriving
Accounts
, where each field is aPubkey
. This is useful for specifying accounts for a client. - constants
- error
- events
- instruction
- An Anchor generated module containing the program’s set of
instructions, where each method handler in the
#[program]
mod is associated with a struct defining the input arguments to the method. These should be used directly, when one wants to serialize Anchor instruction data, for example, when speciying instructions on a client. - instructions
- orao_
vrf_ cb - program
- Module representing the program.
- sdk
sdk
- Off-chain client module
- state
- utils
Constants§
- ID_
CONST - Const version of
ID
Statics§
- ID
- The static program ID
Functions§
- check_
id - Confirms that a given pubkey is equivalent to the program ID
- entry
- The Anchor codegen exposes a programming model where a user defines
a set of methods inside of a
#[program]
module in a way similar to writing RPC request handlers. The macro then generates a bunch of code wrapping these user defined methods into something that can be executed on Solana. - id
- Returns the program ID
- id_
const - Const version of
ID
- majority
- Helper that returns the majority for the given total value.
- quorum
- Helper that checks for Byzantine quorum.
- xor_
array - Helper that XORes
r
intol
.