doc comments

doc comments
This commit is contained in:
Conner Gallagher 2022-11-30 20:34:00 -07:00
parent 872375877d
commit 0107e1354f
12 changed files with 262 additions and 30 deletions

View File

@ -26,9 +26,11 @@ import { TransactionObject } from '../transaction';
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
/**
* @class AggregatorAccount
* Account type holding a data feed's update configuration, job accounts, and its current result.
*
* Data: {@linkcode types.AggregatorAccountData}
* HistoryBuffer?: Array<{@linkcode types.AggregatorHistoryRow}>
*
* An aggregator account belongs to a single {@linkcode QueueAccount} but can later be transferred by the aggregator's authority. In order for an {@linkcode OracleAccount} to respond to an aggregator's update request, the aggregator must initialize a {@linkcode PermissionAccount} and {@linkcode LeaseAccount}. These will need to be recreated when transferring queues.
*
* Optionally, An aggregator can be pushed onto a {@linkcode CrankAccount} in order to be updated

View File

@ -0,0 +1,239 @@
import * as types from '../generated';
import * as anchor from '@project-serum/anchor';
import { Account, OnAccountChangeCallback } from './account';
import * as errors from '../errors';
import { SwitchboardProgram } from '../program';
import {
Commitment,
Keypair,
PublicKey,
SystemProgram,
TransactionInstruction,
TransactionSignature,
} from '@solana/web3.js';
import { TransactionObject } from '../transaction';
import { AggregatorAccount } from './aggregatorAccount';
export interface AggregatorHistoryInit {
/** Aggregator account to add a history buffer for. */
aggregatorAccount: AggregatorAccount;
/** Maximum number of samples to store in a round robin history buffer. */
maxSamples: number;
/** Alternative keypair that is the authority for the aggregatorAccount and authorized to add a historyBuffer. */
aggregatorAuthority?: Keypair;
/** Existing keypair to create the history buffer for. Must be a fresh keypair not tied to an existing on-chain account. */
keypair?: Keypair;
}
/**
* Account type representing a round robin buffer of historical samples.
*
* Data: Array<{@linkcode types.AggregatorHistoryRow}>
*/
export class AggregatorHistoryBuffer extends Account<
Array<types.AggregatorHistoryRow>
> {
static accountName = 'AggregatorHistoryBuffer';
public size = 28;
/**
* Decode an aggregators history buffer and return an array of historical samples
* @params historyBuffer the historyBuffer AccountInfo stored on-chain
* @return the array of {@linkcode types.AggregatorHistoryRow} samples
*/
public static decode(
historyBuffer: Buffer
): Array<types.AggregatorHistoryRow> {
const ROW_SIZE = 28;
if (historyBuffer.length < 12) {
return [];
}
const insertIdx = historyBuffer.readUInt32LE(8) * ROW_SIZE;
const front: Array<types.AggregatorHistoryRow> = [];
const tail: Array<types.AggregatorHistoryRow> = [];
for (let i = 12; i < historyBuffer.length; i += ROW_SIZE) {
if (i + ROW_SIZE > historyBuffer.length) {
break;
}
const row = types.AggregatorHistoryRow.fromDecoded(
types.AggregatorHistoryRow.layout().decode(historyBuffer, i)
);
if (row.timestamp.eq(new anchor.BN(0))) {
break;
}
if (i <= insertIdx) {
tail.push(row);
} else {
front.push(row);
}
}
return front.concat(tail);
}
/**
* Return an aggregator's assigned history buffer or undefined if it doesn't exist.
*/
static fromAggregator(
program: SwitchboardProgram,
aggregator: types.AggregatorAccountData
): AggregatorHistoryBuffer | undefined {
if (aggregator.historyBuffer.equals(aggregator.historyBuffer)) {
return undefined;
}
return new AggregatorHistoryBuffer(program, aggregator.historyBuffer);
}
/**
* Decode an aggregators history buffer and return an array of historical samples
* @params historyBuffer the historyBuffer AccountInfo stored on-chain
* @return the array of {@linkcode types.AggregatorHistoryRow} samples
*/
public decode(historyBuffer: Buffer): Array<types.AggregatorHistoryRow> {
return AggregatorHistoryBuffer.decode(historyBuffer);
}
static getHistoryBufferSize(maxSamples: number): number {
return 8 + 4 + maxSamples * 28;
}
/**
* Fetch an aggregators history buffer and return an array of historical samples
* @params aggregator the pre-loaded aggregator state
* @return the array of {@linkcode types.AggregatorHistoryRow} samples
*/
public async loadData(): Promise<Array<types.AggregatorHistoryRow>> {
if (PublicKey.default.equals(this.publicKey)) {
return [];
}
const bufferAccountInfo = await this.program.connection.getAccountInfo(
this.publicKey
);
if (bufferAccountInfo === null) {
throw new errors.AccountNotFoundError(this.publicKey);
}
return AggregatorHistoryBuffer.decode(bufferAccountInfo.data);
}
/**
* Invoke a callback each time an AggregatorAccount's data has changed on-chain.
* @param callback - the callback invoked when the aggregator state changes
* @param commitment - optional, the desired transaction finality. defaults to 'confirmed'
* @returns the websocket subscription id
*/
public onChange(
callback: OnAccountChangeCallback<Array<types.AggregatorHistoryRow>>,
commitment: Commitment = 'confirmed'
): number {
return this.program.connection.onAccountChange(
this.publicKey,
accountInfo => {
callback(this.decode(accountInfo.data));
},
commitment
);
}
/**
* Create a history buffer for an aggregator and store the last N samples in a round robin history buffer.
* @param program The SwitchboardProgram.
* @param payer The account that will pay for the new account.
* @param params history buffer configuration parameters.
* @return {@linkcode TransactionObject} that will create the AggregatorHistoryBuffer.
*
* Basic usage example:
*
* ```ts
* import {AggregatorAccount,AggregatorHistoryBuffer} from '@switchboard-xyz/solana.js';
* const aggregatorAccount = new AggregatorAccount(program, aggregatorKey);
* const aggregator = await aggregatorAccount.loadData();
* const [addHistoryTxn, historyBuffer] = await AggregatorHistoryBuffer.createInstructions(program, payer, {
* aggregatorAccount,
* maxSamples: 10000,
* });
* const aggregatorHistorySignature = await program.signAndSendAll(aggregatorHistoryTxn);
* const history = await historyBuffer.loadData();
* ```
*/
public static async createInstructions(
program: SwitchboardProgram,
payer: PublicKey,
params: AggregatorHistoryInit
): Promise<[TransactionObject, AggregatorHistoryBuffer]> {
const buffer = params.keypair ?? Keypair.generate();
const ixns: TransactionInstruction[] = [];
const signers: Keypair[] = params.aggregatorAuthority
? [params.aggregatorAuthority, buffer]
: [buffer];
const size = AggregatorHistoryBuffer.getHistoryBufferSize(
params.maxSamples
);
ixns.push(
SystemProgram.createAccount({
fromPubkey: payer,
newAccountPubkey: buffer.publicKey,
space: size,
lamports: await program.connection.getMinimumBalanceForRentExemption(
size
),
programId: program.programId,
}),
types.aggregatorSetHistoryBuffer(
program,
{ params: {} },
{
aggregator: params.aggregatorAccount.publicKey,
authority: params.aggregatorAuthority
? params.aggregatorAuthority.publicKey
: payer,
buffer: buffer.publicKey,
}
)
);
return [
new TransactionObject(payer, ixns, signers),
new AggregatorHistoryBuffer(program, buffer.publicKey),
];
}
/**
* Create a history buffer for an aggregator and store the last N samples in a round robin history buffer.
* @param program The SwitchboardProgram.
* @param payer The account that will pay for the new account.
* @param params history buffer configuration parameters.
* @return {@linkcode TransactionObject} that will create the AggregatorHistoryBuffer.
*
* Basic usage example:
*
* ```ts
* import {AggregatorAccount,AggregatorHistoryBuffer} from '@switchboard-xyz/solana.js';
* const aggregatorAccount = new AggregatorAccount(program, aggregatorKey);
* const aggregator = await aggregatorAccount.loadData();
* const [addHistorySignature, historyBuffer] = await AggregatorHistoryBuffer.create(program, {
* aggregatorAccount,
* maxSamples: 10000,
* });
* const history = await historyBuffer.loadData();
* ```
*/
public static async create(
program: SwitchboardProgram,
params: AggregatorHistoryInit
): Promise<[TransactionSignature, AggregatorHistoryBuffer]> {
const [transaction, account] =
await AggregatorHistoryBuffer.createInstructions(
program,
program.walletPubkey,
params
);
const txnSignature = await program.signAndSend(transaction);
return [txnSignature, account];
}
}

View File

@ -25,8 +25,9 @@ import { PermissionAccount } from './permissionAccount';
import { QueueAccount } from './queueAccount';
/**
* @class BufferRelayerAccount
* Account type holding a buffer of data sourced from the buffers sole {@linkcode JobAccount}. A buffer relayer has no consensus mechanism and relies on trusting an {@linkcode OracleAccount} to respond honestly. A buffer relayer has a max capacity of 500 bytes.
*
* Data: {@linkcode types.BufferRelayerAccountData}
*/
export class BufferRelayerAccount extends Account<types.BufferRelayerAccountData> {
static accountName = 'BufferRelayerAccountData';

View File

@ -18,8 +18,10 @@ import { AggregatorAccount } from './aggregatorAccount';
import { QueueAccount } from './queueAccount';
/**
* @class CrankAccount
* Account holding a priority queue of aggregators and their next available update time. This is a scheduling mechanism to ensure {@linkcode AggregatorAccount}'s are updated as close as possible to their specified update interval.
*
* Data: {@linkcode types.CrankAccountData}
* Buffer: Array<{@linkcode types.CrankRow}>
*/
export class CrankAccount extends Account<types.CrankAccountData> {
static accountName = 'CrankAccountData';

View File

@ -14,8 +14,9 @@ import { Account } from './account';
import { TransactionObject } from '../transaction';
/**
* @class JobAccount
* Account type storing a list of SwitchboardTasks {@linkcode OracleJob.ITask} dictating how to source data off-chain.
*
* Data: {@linkcode types.JobAccountData}
*/
export class JobAccount extends Account<types.JobAccountData> {
static accountName = 'JobAccountData';

View File

@ -17,8 +17,9 @@ import { TransactionObject } from '../transaction';
import { BN } from 'bn.js';
/**
* @class LeaseAccount
* Account type representing an {@linkcode AggregatorAccount}'s pre-funded escrow used to reward {@linkcode OracleAccount}'s for responding to open round requests.
*
* Data: {@linkcode types.LeaseAccountData}
*/
export class LeaseAccount extends Account<types.LeaseAccountData> {
static accountName = 'LeaseAccountData';

View File

@ -16,10 +16,11 @@ import * as spl from '@solana/spl-token';
import { TransactionObject } from '../transaction';
/**
* @class OracleAccount
* Account type holding an oracle's configuration including the authority and the reward/slashing wallet along with a set of metrics tracking its reliability.
*
* An oracle is a server that sits between the internet and a blockchain and facilitates the flow of information and is rewarded for responding with the honest majority.
*
* Data: {@linkcode types.OracleAccountData}
*/
export class OracleAccount extends Account<types.OracleAccountData> {
static accountName = 'OracleAccountData';

View File

@ -30,10 +30,11 @@ export type PermissionSetParams =
};
/**
* @class PermissionAccount
* Account type dictating the level of permissions between a granter and a grantee.
*
* A {@linkcode QueueAccount} acts as the granter where the queue authority assigns or revokes a grantee's {@linkcode types.SwitchboardPermission}. A grantee can be one of the following: {@linkcode AggregatorAccount}, {@linkcode BufferRelayerAccount}, or {@linkcode VrfAccount}.
*
* Data: {@linkcode types.PermissionAccountData}
*/
export class PermissionAccount extends Account<types.PermissionAccountData> {
static accountName = 'PermissionAccountData';

View File

@ -13,8 +13,9 @@ import {
import { TransactionObject } from '../transaction';
/**
* @class ProgramStateAccount
* Account type representing Switchboard global program state.
*
* Data: {@linkcode types.SbState}
*/
export class ProgramStateAccount extends Account<types.SbState> {
static accountName = 'SbState';

View File

@ -29,10 +29,12 @@ import { PermissionAccount } from './permissionAccount';
import { VrfAccount, VrfInitParams } from './vrfAccount';
/**
* @class QueueAccount
* Account type representing an oracle queue's configuration along with a buffer account holding a list of oracles that are actively heartbeating.
*
* A QueueAccount is responsible for allocating update requests to it's round robin queue of {@linkcode OracleAccount}'s.
*
* Data: {@linkcode types.OracleQueueAccountData}
* Buffer: Array<PublicKey>
*/
export class QueueAccount extends Account<types.OracleQueueAccountData> {
static accountName = 'OracleQueueAccountData';

View File

@ -162,9 +162,6 @@ export function fromDecoded(obj: any): types.LanesKind {
if ('AD' in obj) {
return new AD();
}
if ('BCD' in obj) {
return new BCD();
}
throw new Error('Invalid enum object');
}
@ -186,9 +183,6 @@ export function fromJSON(obj: types.LanesJSON): types.LanesKind {
case 'AD': {
return new AD();
}
case 'BCD': {
return new BCD();
}
}
}

View File

@ -324,26 +324,13 @@ export { Error };
* having to know details about the data layout of the
* `FieldElement2625x4`.
*/
export type LanesKind =
| Lanes.C
| Lanes.D
| Lanes.AB
| Lanes.AC
| Lanes.CD
| Lanes.AD
| Lanes.BC
| Lanes.ABCD;
export type LanesKind = Lanes.C | Lanes.D | Lanes.AB | Lanes.AC | Lanes.AD;
export type LanesJSON =
| Lanes.CJSON
| Lanes.DJSON
| Lanes.ABJSON
| Lanes.ACJSON
| Lanes.CDJSON
| Lanes.ADJSON
| Lanes.BCJSON
| Lanes.ABCDJSON;
export { Shuffle };
| Lanes.ADJSON;
/**
* The `Shuffle` enum represents a shuffle of a `FieldElement2625x4`.