feat: the web3.js getBlock APIs now accept `rewards` and `transactionDetails` config (#29000)
* Add `transactionDetails` and `rewards` params to `getBlock` API of web3.js * Add the same content to the legacy call …because it's such a PITA to share config between two methods and not have Typedoc throw a fit. * Add tests to exercise block deserialization in the case that `transactionDetails` is `none` or `accounts` * Extract the annotated account key parser into a separate struct * Parse the `getBlock()` responses differently depending on the mode
This commit is contained in:
parent
5850af5316
commit
b112d01a5d
|
@ -23,6 +23,7 @@ import {
|
|||
import type {Struct} from 'superstruct';
|
||||
import {Client as RpcWebSocketClient} from 'rpc-websockets';
|
||||
import RpcClient from 'jayson/lib/client/browser';
|
||||
import {JSONRPCError} from 'jayson';
|
||||
|
||||
import {AgentManager} from './agent-manager';
|
||||
import {EpochSchedule} from './epoch-schedule';
|
||||
|
@ -517,6 +518,18 @@ export type GetBalanceConfig = {
|
|||
export type GetBlockConfig = {
|
||||
/** The level of finality desired */
|
||||
commitment?: Finality;
|
||||
/**
|
||||
* Whether to populate the rewards array. If parameter not provided, the default includes rewards.
|
||||
*/
|
||||
rewards?: boolean;
|
||||
/**
|
||||
* Level of transaction detail to return, either "full", "accounts", "signatures", or "none". If
|
||||
* parameter not provided, the default detail level is "full". If "accounts" are requested,
|
||||
* transaction details only include signatures and an annotated list of accounts in each
|
||||
* transaction. Transaction metadata is limited to only: fee, err, pre_balances, post_balances,
|
||||
* pre_token_balances, and post_token_balances.
|
||||
*/
|
||||
transactionDetails?: 'accounts' | 'full' | 'none' | 'signatures';
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -527,6 +540,18 @@ export type GetVersionedBlockConfig = {
|
|||
commitment?: Finality;
|
||||
/** The max transaction version to return in responses. If the requested transaction is a higher version, an error will be returned */
|
||||
maxSupportedTransactionVersion?: number;
|
||||
/**
|
||||
* Whether to populate the rewards array. If parameter not provided, the default includes rewards.
|
||||
*/
|
||||
rewards?: boolean;
|
||||
/**
|
||||
* Level of transaction detail to return, either "full", "accounts", "signatures", or "none". If
|
||||
* parameter not provided, the default detail level is "full". If "accounts" are requested,
|
||||
* transaction details only include signatures and an annotated list of accounts in each
|
||||
* transaction. Transaction metadata is limited to only: fee, err, pre_balances, post_balances,
|
||||
* pre_token_balances, and post_token_balances.
|
||||
*/
|
||||
transactionDetails?: 'accounts' | 'full' | 'none' | 'signatures';
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1172,6 +1197,16 @@ export type BlockResponse = {
|
|||
blockTime: number | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* A processed block fetched from the RPC API where the `transactionDetails` mode is `accounts`
|
||||
*/
|
||||
export type AccountsModeBlockResponse = VersionedAccountsModeBlockResponse;
|
||||
|
||||
/**
|
||||
* A processed block fetched from the RPC API where the `transactionDetails` mode is `none`
|
||||
*/
|
||||
export type NoneModeBlockResponse = VersionedNoneModeBlockResponse;
|
||||
|
||||
/**
|
||||
* A block with parsed transactions
|
||||
*/
|
||||
|
@ -1208,6 +1243,33 @@ export type ParsedBlockResponse = {
|
|||
blockHeight: number | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* A block with parsed transactions where the `transactionDetails` mode is `accounts`
|
||||
*/
|
||||
export type ParsedAccountsModeBlockResponse = Omit<
|
||||
ParsedBlockResponse,
|
||||
'transactions'
|
||||
> & {
|
||||
transactions: Array<
|
||||
Omit<ParsedBlockResponse['transactions'][number], 'transaction'> & {
|
||||
transaction: Pick<
|
||||
ParsedBlockResponse['transactions'][number]['transaction'],
|
||||
'signatures'
|
||||
> & {
|
||||
accountKeys: ParsedMessageAccount[];
|
||||
};
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
/**
|
||||
* A block with parsed transactions where the `transactionDetails` mode is `none`
|
||||
*/
|
||||
export type ParsedNoneModeBlockResponse = Omit<
|
||||
ParsedBlockResponse,
|
||||
'transactions'
|
||||
>;
|
||||
|
||||
/**
|
||||
* A processed block fetched from the RPC API
|
||||
*/
|
||||
|
@ -1247,6 +1309,33 @@ export type VersionedBlockResponse = {
|
|||
blockTime: number | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* A processed block fetched from the RPC API where the `transactionDetails` mode is `accounts`
|
||||
*/
|
||||
export type VersionedAccountsModeBlockResponse = Omit<
|
||||
VersionedBlockResponse,
|
||||
'transactions'
|
||||
> & {
|
||||
transactions: Array<
|
||||
Omit<VersionedBlockResponse['transactions'][number], 'transaction'> & {
|
||||
transaction: Pick<
|
||||
VersionedBlockResponse['transactions'][number]['transaction'],
|
||||
'signatures'
|
||||
> & {
|
||||
accountKeys: ParsedMessageAccount[];
|
||||
};
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
/**
|
||||
* A processed block fetched from the RPC API where the `transactionDetails` mode is `none`
|
||||
*/
|
||||
export type VersionedNoneModeBlockResponse = Omit<
|
||||
VersionedBlockResponse,
|
||||
'transactions'
|
||||
>;
|
||||
|
||||
/**
|
||||
* A confirmed block on the ledger
|
||||
*
|
||||
|
@ -1980,6 +2069,18 @@ const ConfirmedTransactionResult = pick({
|
|||
}),
|
||||
});
|
||||
|
||||
const AnnotatedAccountKey = pick({
|
||||
pubkey: PublicKeyFromString,
|
||||
signer: boolean(),
|
||||
writable: boolean(),
|
||||
source: optional(union([literal('transaction'), literal('lookupTable')])),
|
||||
});
|
||||
|
||||
const ConfirmedTransactionAccountsModeResult = pick({
|
||||
accountKeys: array(AnnotatedAccountKey),
|
||||
signatures: array(string()),
|
||||
});
|
||||
|
||||
const ParsedInstructionResult = pick({
|
||||
parsed: unknown(),
|
||||
program: string(),
|
||||
|
@ -2028,16 +2129,7 @@ const ParsedOrRawInstruction = coerce(
|
|||
const ParsedConfirmedTransactionResult = pick({
|
||||
signatures: array(string()),
|
||||
message: pick({
|
||||
accountKeys: array(
|
||||
pick({
|
||||
pubkey: PublicKeyFromString,
|
||||
signer: boolean(),
|
||||
writable: boolean(),
|
||||
source: optional(
|
||||
union([literal('transaction'), literal('lookupTable')]),
|
||||
),
|
||||
}),
|
||||
),
|
||||
accountKeys: array(AnnotatedAccountKey),
|
||||
instructions: array(ParsedOrRawInstruction),
|
||||
recentBlockhash: string(),
|
||||
addressTableLookups: optional(nullable(array(AddressTableLookupStruct))),
|
||||
|
@ -2114,6 +2206,14 @@ const ParsedConfirmedTransactionMetaResult = pick({
|
|||
|
||||
const TransactionVersionStruct = union([literal(0), literal('legacy')]);
|
||||
|
||||
/** @internal */
|
||||
const RewardsResult = pick({
|
||||
pubkey: string(),
|
||||
lamports: number(),
|
||||
postBalance: nullable(number()),
|
||||
rewardType: nullable(string()),
|
||||
});
|
||||
|
||||
/**
|
||||
* Expected JSON RPC response for the "getBlock" message
|
||||
*/
|
||||
|
@ -2130,16 +2230,46 @@ const GetBlockRpcResult = jsonRpcResult(
|
|||
version: optional(TransactionVersionStruct),
|
||||
}),
|
||||
),
|
||||
rewards: optional(
|
||||
array(
|
||||
pick({
|
||||
pubkey: string(),
|
||||
lamports: number(),
|
||||
postBalance: nullable(number()),
|
||||
rewardType: nullable(string()),
|
||||
}),
|
||||
),
|
||||
rewards: optional(array(RewardsResult)),
|
||||
blockTime: nullable(number()),
|
||||
blockHeight: nullable(number()),
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Expected JSON RPC response for the "getBlock" message when `transactionDetails` is `none`
|
||||
*/
|
||||
const GetNoneModeBlockRpcResult = jsonRpcResult(
|
||||
nullable(
|
||||
pick({
|
||||
blockhash: string(),
|
||||
previousBlockhash: string(),
|
||||
parentSlot: number(),
|
||||
rewards: optional(array(RewardsResult)),
|
||||
blockTime: nullable(number()),
|
||||
blockHeight: nullable(number()),
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Expected JSON RPC response for the "getBlock" message when `transactionDetails` is `accounts`
|
||||
*/
|
||||
const GetAccountsModeBlockRpcResult = jsonRpcResult(
|
||||
nullable(
|
||||
pick({
|
||||
blockhash: string(),
|
||||
previousBlockhash: string(),
|
||||
parentSlot: number(),
|
||||
transactions: array(
|
||||
pick({
|
||||
transaction: ConfirmedTransactionAccountsModeResult,
|
||||
meta: nullable(ConfirmedTransactionMetaResult),
|
||||
version: optional(TransactionVersionStruct),
|
||||
}),
|
||||
),
|
||||
rewards: optional(array(RewardsResult)),
|
||||
blockTime: nullable(number()),
|
||||
blockHeight: nullable(number()),
|
||||
}),
|
||||
|
@ -2162,16 +2292,46 @@ const GetParsedBlockRpcResult = jsonRpcResult(
|
|||
version: optional(TransactionVersionStruct),
|
||||
}),
|
||||
),
|
||||
rewards: optional(
|
||||
array(
|
||||
pick({
|
||||
pubkey: string(),
|
||||
lamports: number(),
|
||||
postBalance: nullable(number()),
|
||||
rewardType: nullable(string()),
|
||||
}),
|
||||
),
|
||||
rewards: optional(array(RewardsResult)),
|
||||
blockTime: nullable(number()),
|
||||
blockHeight: nullable(number()),
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Expected parsed JSON RPC response for the "getBlock" message when `transactionDetails` is `accounts`
|
||||
*/
|
||||
const GetParsedAccountsModeBlockRpcResult = jsonRpcResult(
|
||||
nullable(
|
||||
pick({
|
||||
blockhash: string(),
|
||||
previousBlockhash: string(),
|
||||
parentSlot: number(),
|
||||
transactions: array(
|
||||
pick({
|
||||
transaction: ConfirmedTransactionAccountsModeResult,
|
||||
meta: nullable(ParsedConfirmedTransactionMetaResult),
|
||||
version: optional(TransactionVersionStruct),
|
||||
}),
|
||||
),
|
||||
rewards: optional(array(RewardsResult)),
|
||||
blockTime: nullable(number()),
|
||||
blockHeight: nullable(number()),
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Expected parsed JSON RPC response for the "getBlock" message when `transactionDetails` is `none`
|
||||
*/
|
||||
const GetParsedNoneModeBlockRpcResult = jsonRpcResult(
|
||||
nullable(
|
||||
pick({
|
||||
blockhash: string(),
|
||||
previousBlockhash: string(),
|
||||
parentSlot: number(),
|
||||
rewards: optional(array(RewardsResult)),
|
||||
blockTime: nullable(number()),
|
||||
blockHeight: nullable(number()),
|
||||
}),
|
||||
|
@ -2195,16 +2355,7 @@ const GetConfirmedBlockRpcResult = jsonRpcResult(
|
|||
meta: nullable(ConfirmedTransactionMetaResult),
|
||||
}),
|
||||
),
|
||||
rewards: optional(
|
||||
array(
|
||||
pick({
|
||||
pubkey: string(),
|
||||
lamports: number(),
|
||||
postBalance: nullable(number()),
|
||||
rewardType: nullable(string()),
|
||||
}),
|
||||
),
|
||||
),
|
||||
rewards: optional(array(RewardsResult)),
|
||||
blockTime: nullable(number()),
|
||||
}),
|
||||
),
|
||||
|
@ -4261,6 +4412,26 @@ export class Connection {
|
|||
rawConfig?: GetBlockConfig,
|
||||
): Promise<BlockResponse | null>;
|
||||
|
||||
/**
|
||||
* @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by
|
||||
* setting the `maxSupportedTransactionVersion` property.
|
||||
*/
|
||||
// eslint-disable-next-line no-dupe-class-members
|
||||
async getBlock(
|
||||
slot: number,
|
||||
rawConfig: GetBlockConfig & {transactionDetails: 'accounts'},
|
||||
): Promise<AccountsModeBlockResponse | null>;
|
||||
|
||||
/**
|
||||
* @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by
|
||||
* setting the `maxSupportedTransactionVersion` property.
|
||||
*/
|
||||
// eslint-disable-next-line no-dupe-class-members
|
||||
async getBlock(
|
||||
slot: number,
|
||||
rawConfig: GetBlockConfig & {transactionDetails: 'none'},
|
||||
): Promise<NoneModeBlockResponse | null>;
|
||||
|
||||
/**
|
||||
* Fetch a processed block from the cluster.
|
||||
*/
|
||||
|
@ -4270,6 +4441,18 @@ export class Connection {
|
|||
rawConfig?: GetVersionedBlockConfig,
|
||||
): Promise<VersionedBlockResponse | null>;
|
||||
|
||||
// eslint-disable-next-line no-dupe-class-members
|
||||
async getBlock(
|
||||
slot: number,
|
||||
rawConfig: GetVersionedBlockConfig & {transactionDetails: 'accounts'},
|
||||
): Promise<VersionedAccountsModeBlockResponse | null>;
|
||||
|
||||
// eslint-disable-next-line no-dupe-class-members
|
||||
async getBlock(
|
||||
slot: number,
|
||||
rawConfig: GetVersionedBlockConfig & {transactionDetails: 'none'},
|
||||
): Promise<VersionedNoneModeBlockResponse | null>;
|
||||
|
||||
/**
|
||||
* Fetch a processed block from the cluster.
|
||||
*/
|
||||
|
@ -4277,7 +4460,12 @@ export class Connection {
|
|||
async getBlock(
|
||||
slot: number,
|
||||
rawConfig?: GetVersionedBlockConfig,
|
||||
): Promise<VersionedBlockResponse | null> {
|
||||
): Promise<
|
||||
| VersionedBlockResponse
|
||||
| VersionedAccountsModeBlockResponse
|
||||
| VersionedNoneModeBlockResponse
|
||||
| null
|
||||
> {
|
||||
const {commitment, config} = extractCommitmentFromConfig(rawConfig);
|
||||
const args = this._buildArgsAtLeastConfirmed(
|
||||
[slot],
|
||||
|
@ -4286,26 +4474,54 @@ export class Connection {
|
|||
config,
|
||||
);
|
||||
const unsafeRes = await this._rpcRequest('getBlock', args);
|
||||
const res = create(unsafeRes, GetBlockRpcResult);
|
||||
|
||||
if ('error' in res) {
|
||||
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed block');
|
||||
try {
|
||||
switch (config?.transactionDetails) {
|
||||
case 'accounts': {
|
||||
const res = create(unsafeRes, GetAccountsModeBlockRpcResult);
|
||||
if ('error' in res) {
|
||||
throw res.error;
|
||||
}
|
||||
return res.result;
|
||||
}
|
||||
case 'none': {
|
||||
const res = create(unsafeRes, GetNoneModeBlockRpcResult);
|
||||
if ('error' in res) {
|
||||
throw res.error;
|
||||
}
|
||||
return res.result;
|
||||
}
|
||||
default: {
|
||||
const res = create(unsafeRes, GetBlockRpcResult);
|
||||
if ('error' in res) {
|
||||
throw res.error;
|
||||
}
|
||||
const {result} = res;
|
||||
return result
|
||||
? {
|
||||
...result,
|
||||
transactions: result.transactions.map(
|
||||
({transaction, meta, version}) => ({
|
||||
meta,
|
||||
transaction: {
|
||||
...transaction,
|
||||
message: versionedMessageFromResponse(
|
||||
version,
|
||||
transaction.message,
|
||||
),
|
||||
},
|
||||
version,
|
||||
}),
|
||||
),
|
||||
}
|
||||
: null;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
throw new SolanaJSONRPCError(
|
||||
e as JSONRPCError,
|
||||
'failed to get confirmed block',
|
||||
);
|
||||
}
|
||||
|
||||
const result = res.result;
|
||||
if (!result) return result;
|
||||
|
||||
return {
|
||||
...result,
|
||||
transactions: result.transactions.map(({transaction, meta, version}) => ({
|
||||
meta,
|
||||
transaction: {
|
||||
...transaction,
|
||||
message: versionedMessageFromResponse(version, transaction.message),
|
||||
},
|
||||
version,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4314,7 +4530,29 @@ export class Connection {
|
|||
async getParsedBlock(
|
||||
slot: number,
|
||||
rawConfig?: GetVersionedBlockConfig,
|
||||
): Promise<ParsedBlockResponse | null> {
|
||||
): Promise<ParsedAccountsModeBlockResponse>;
|
||||
|
||||
// eslint-disable-next-line no-dupe-class-members
|
||||
async getParsedBlock(
|
||||
slot: number,
|
||||
rawConfig: GetVersionedBlockConfig & {transactionDetails: 'accounts'},
|
||||
): Promise<ParsedAccountsModeBlockResponse>;
|
||||
|
||||
// eslint-disable-next-line no-dupe-class-members
|
||||
async getParsedBlock(
|
||||
slot: number,
|
||||
rawConfig: GetVersionedBlockConfig & {transactionDetails: 'none'},
|
||||
): Promise<ParsedNoneModeBlockResponse>;
|
||||
// eslint-disable-next-line no-dupe-class-members
|
||||
async getParsedBlock(
|
||||
slot: number,
|
||||
rawConfig?: GetVersionedBlockConfig,
|
||||
): Promise<
|
||||
| ParsedBlockResponse
|
||||
| ParsedAccountsModeBlockResponse
|
||||
| ParsedNoneModeBlockResponse
|
||||
| null
|
||||
> {
|
||||
const {commitment, config} = extractCommitmentFromConfig(rawConfig);
|
||||
const args = this._buildArgsAtLeastConfirmed(
|
||||
[slot],
|
||||
|
@ -4323,11 +4561,33 @@ export class Connection {
|
|||
config,
|
||||
);
|
||||
const unsafeRes = await this._rpcRequest('getBlock', args);
|
||||
const res = create(unsafeRes, GetParsedBlockRpcResult);
|
||||
if ('error' in res) {
|
||||
throw new SolanaJSONRPCError(res.error, 'failed to get block');
|
||||
try {
|
||||
switch (config?.transactionDetails) {
|
||||
case 'accounts': {
|
||||
const res = create(unsafeRes, GetParsedAccountsModeBlockRpcResult);
|
||||
if ('error' in res) {
|
||||
throw res.error;
|
||||
}
|
||||
return res.result;
|
||||
}
|
||||
case 'none': {
|
||||
const res = create(unsafeRes, GetParsedNoneModeBlockRpcResult);
|
||||
if ('error' in res) {
|
||||
throw res.error;
|
||||
}
|
||||
return res.result;
|
||||
}
|
||||
default: {
|
||||
const res = create(unsafeRes, GetParsedBlockRpcResult);
|
||||
if ('error' in res) {
|
||||
throw res.error;
|
||||
}
|
||||
return res.result;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
throw new SolanaJSONRPCError(e as JSONRPCError, 'failed to get block');
|
||||
}
|
||||
return res.result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -3071,6 +3071,229 @@ describe('Connection', function () {
|
|||
});
|
||||
}
|
||||
|
||||
describe('get parsed block', function () {
|
||||
it('can deserialize a response when `transactionDetails` is `full`', async () => {
|
||||
// Mock block with transaction, fetched using `"transactionDetails": "full"`.
|
||||
await mockRpcResponse({
|
||||
method: 'getBlock',
|
||||
params: [
|
||||
1,
|
||||
{
|
||||
encoding: 'jsonParsed',
|
||||
maxSupportedTransactionVersion: 0,
|
||||
transactionDetails: 'full',
|
||||
},
|
||||
],
|
||||
value: {
|
||||
blockHeight: 0,
|
||||
blockTime: 1614281964,
|
||||
blockhash: '49d2UbduiZWjtR3Wvfv2t2QxmXvtZNWSPFRZxEDYAvQN',
|
||||
parentSlot: 0,
|
||||
previousBlockhash: 'mDd5yMLfuroS1JVZMHo2VZLTgKXXNBXrzPR5UkzFD4X',
|
||||
transactions: [
|
||||
{
|
||||
meta: {
|
||||
err: null,
|
||||
fee: 5000,
|
||||
innerInstructions: [],
|
||||
logMessages: [
|
||||
'Program Vote111111111111111111111111111111111111111 invoke [1]',
|
||||
'Program Vote111111111111111111111111111111111111111 success',
|
||||
],
|
||||
postBalances: [3712706991, 5765419239, 1169280, 143487360, 1],
|
||||
postTokenBalances: [],
|
||||
preBalances: [3712711991, 5765419239, 1169280, 143487360, 1],
|
||||
preTokenBalances: [],
|
||||
rewards: null,
|
||||
status: {Ok: null},
|
||||
},
|
||||
transaction: {
|
||||
message: {
|
||||
accountKeys: [
|
||||
{
|
||||
pubkey: '7v5fMKBqC9PuwjSdS9k9JU7efEXmq3bHTMF5fuSHnqrm',
|
||||
signer: true,
|
||||
source: 'transaction',
|
||||
writable: true,
|
||||
},
|
||||
{
|
||||
pubkey: 'AhcvnNdppGEcgdpK5gfcaZnAWz4ct8V4n7De5QiLiuzG',
|
||||
signer: false,
|
||||
source: 'transaction',
|
||||
writable: true,
|
||||
},
|
||||
{
|
||||
pubkey: 'SysvarC1ock11111111111111111111111111111111',
|
||||
signer: false,
|
||||
source: 'transaction',
|
||||
writable: false,
|
||||
},
|
||||
{
|
||||
pubkey: 'SysvarS1otHashes111111111111111111111111111',
|
||||
signer: false,
|
||||
source: 'transaction',
|
||||
writable: false,
|
||||
},
|
||||
{
|
||||
pubkey: 'Vote111111111111111111111111111111111111111',
|
||||
signer: false,
|
||||
source: 'transaction',
|
||||
writable: false,
|
||||
},
|
||||
],
|
||||
addressTableLookups: null,
|
||||
instructions: [
|
||||
{
|
||||
parsed: {
|
||||
info: {
|
||||
clockSysvar:
|
||||
'SysvarC1ock11111111111111111111111111111111',
|
||||
slotHashesSysvar:
|
||||
'SysvarS1otHashes111111111111111111111111111',
|
||||
vote: {
|
||||
hash: '2gmQ8xMjZaXn63kr8qzPAUjQAHi7xCDjSibPdJxhVYMm',
|
||||
slots: [164153060, 164153061],
|
||||
timestamp: 1669845645,
|
||||
},
|
||||
voteAccount:
|
||||
'AhcvnNdppGEcgdpK5gfcaZnAWz4ct8V4n7De5QiLiuzG',
|
||||
voteAuthority:
|
||||
'7v5fMKBqC9PuwjSdS9k9JU7efEXmq3bHTMF5fuSHnqrm',
|
||||
},
|
||||
type: 'vote',
|
||||
},
|
||||
program: 'vote',
|
||||
programId: 'Vote111111111111111111111111111111111111111',
|
||||
},
|
||||
],
|
||||
recentBlockhash:
|
||||
'GLqYrN6AQxCGtFTQywkPj2WN5tafC3KerBhW4QkmAyD4',
|
||||
},
|
||||
signatures: [
|
||||
'5qDZ3nUUwp8VHFfAE5ydTQRULCoVLMGs16EprwdXsvyNCLe1NfckCkRE4BPi6wyEW9hXvG9iWU2prXfbM8SNPVEC',
|
||||
],
|
||||
},
|
||||
version: 'legacy',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
await expect(
|
||||
connection.getParsedBlock(1, {
|
||||
maxSupportedTransactionVersion: 0,
|
||||
transactionDetails: 'full',
|
||||
}),
|
||||
).not.to.eventually.be.rejected;
|
||||
});
|
||||
|
||||
it('can deserialize a response when `transactionDetails` is `none`', async () => {
|
||||
// Mock block with transaction, fetched using `"transactionDetails": "none"`.
|
||||
await mockRpcResponse({
|
||||
method: 'getBlock',
|
||||
params: [
|
||||
1,
|
||||
{
|
||||
encoding: 'jsonParsed',
|
||||
maxSupportedTransactionVersion: 0,
|
||||
transactionDetails: 'none',
|
||||
},
|
||||
],
|
||||
value: {
|
||||
blockHeight: 0,
|
||||
blockTime: 1614281964,
|
||||
blockhash: '49d2UbduiZWjtR3Wvfv2t2QxmXvtZNWSPFRZxEDYAvQN',
|
||||
parentSlot: 0,
|
||||
previousBlockhash: 'mDd5yMLfuroS1JVZMHo2VZLTgKXXNBXrzPR5UkzFD4X',
|
||||
},
|
||||
});
|
||||
await expect(
|
||||
connection.getParsedBlock(1, {
|
||||
maxSupportedTransactionVersion: 0,
|
||||
transactionDetails: 'none',
|
||||
}),
|
||||
).not.to.eventually.be.rejected;
|
||||
});
|
||||
|
||||
it('can deserialize a response when `transactionDetails` is `accounts`', async () => {
|
||||
// Mock block with transaction, fetched using `"transactionDetails": "accounts"`.
|
||||
await mockRpcResponse({
|
||||
method: 'getBlock',
|
||||
params: [
|
||||
1,
|
||||
{
|
||||
encoding: 'jsonParsed',
|
||||
maxSupportedTransactionVersion: 0,
|
||||
transactionDetails: 'accounts',
|
||||
},
|
||||
],
|
||||
value: {
|
||||
blockHeight: 0,
|
||||
blockTime: 1614281964,
|
||||
blockhash: '49d2UbduiZWjtR3Wvfv2t2QxmXvtZNWSPFRZxEDYAvQN',
|
||||
parentSlot: 0,
|
||||
previousBlockhash: 'mDd5yMLfuroS1JVZMHo2VZLTgKXXNBXrzPR5UkzFD4X',
|
||||
transactions: [
|
||||
{
|
||||
meta: {
|
||||
err: null,
|
||||
fee: 5000,
|
||||
postBalances: [18237691394, 26858640, 1169280, 143487360, 1],
|
||||
postTokenBalances: [],
|
||||
preBalances: [18237696394, 26858640, 1169280, 143487360, 1],
|
||||
preTokenBalances: [],
|
||||
status: {Ok: null},
|
||||
},
|
||||
transaction: {
|
||||
accountKeys: [
|
||||
{
|
||||
pubkey: '914RFshndUeZaNPjf8UWDCyo49ahQ1XQ2w9BnEMwpHKF',
|
||||
signer: true,
|
||||
source: 'transaction',
|
||||
writable: true,
|
||||
},
|
||||
{
|
||||
pubkey: '4cCd4SGrMswhqboYBJ5AcCVvCjh5NtaeZNwWFJzsnUWY',
|
||||
signer: false,
|
||||
source: 'transaction',
|
||||
writable: true,
|
||||
},
|
||||
{
|
||||
pubkey: 'SysvarC1ock11111111111111111111111111111111',
|
||||
signer: false,
|
||||
source: 'transaction',
|
||||
writable: false,
|
||||
},
|
||||
{
|
||||
pubkey: 'SysvarS1otHashes111111111111111111111111111',
|
||||
signer: false,
|
||||
source: 'transaction',
|
||||
writable: false,
|
||||
},
|
||||
{
|
||||
pubkey: 'Vote111111111111111111111111111111111111111',
|
||||
signer: false,
|
||||
source: 'transaction',
|
||||
writable: false,
|
||||
},
|
||||
],
|
||||
signatures: [
|
||||
'5ZDp1HfNZhNRHc75ncsiZ4sCq1fGJHMGf9u36M3foD5PMH4Xu5S4X2x7aryn4JinUdG11oSYCk7zxbNmLJzzqUft',
|
||||
],
|
||||
},
|
||||
version: 'legacy',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
await expect(
|
||||
connection.getParsedBlock(1, {
|
||||
maxSupportedTransactionVersion: 0,
|
||||
transactionDetails: 'accounts',
|
||||
}),
|
||||
).not.to.eventually.be.rejected;
|
||||
});
|
||||
});
|
||||
|
||||
describe('get block', function () {
|
||||
beforeEach(async function () {
|
||||
await mockRpcResponse({
|
||||
|
@ -3236,6 +3459,187 @@ describe('Connection', function () {
|
|||
`Block not available for slot ${Number.MAX_SAFE_INTEGER}`,
|
||||
);
|
||||
});
|
||||
|
||||
it('can deserialize a response when `transactionDetails` is `full`', async () => {
|
||||
// Mock block with transaction, fetched using `"transactionDetails": "full"`.
|
||||
await mockRpcResponse({
|
||||
method: 'getBlock',
|
||||
params: [
|
||||
1,
|
||||
{
|
||||
maxSupportedTransactionVersion: 0,
|
||||
transactionDetails: 'full',
|
||||
},
|
||||
],
|
||||
value: {
|
||||
blockHeight: 0,
|
||||
blockTime: 1614281964,
|
||||
blockhash: '49d2UbduiZWjtR3Wvfv2t2QxmXvtZNWSPFRZxEDYAvQN',
|
||||
parentSlot: 0,
|
||||
previousBlockhash: 'mDd5yMLfuroS1JVZMHo2VZLTgKXXNBXrzPR5UkzFD4X',
|
||||
transactions: [
|
||||
{
|
||||
meta: {
|
||||
err: null,
|
||||
fee: 5000,
|
||||
innerInstructions: [],
|
||||
loadedAddresses: {readonly: [], writable: []},
|
||||
logMessages: [
|
||||
'Program Vote111111111111111111111111111111111111111 invoke [1]',
|
||||
'Program Vote111111111111111111111111111111111111111 success',
|
||||
],
|
||||
postBalances: [12278161908, 39995373, 1169280, 143487360, 1],
|
||||
postTokenBalances: [],
|
||||
preBalances: [12278166908, 39995373, 1169280, 143487360, 1],
|
||||
preTokenBalances: [],
|
||||
rewards: null,
|
||||
status: {Ok: null},
|
||||
},
|
||||
transaction: {
|
||||
message: {
|
||||
accountKeys: [
|
||||
'FTWuJ2tqjecNizCSE66z4BD1tBHomG6DVffGUwRuWUkM',
|
||||
'H2z3pBT62ByS4jpqsiEMtgN3NUFEuZHiTvoKCFjqCtD6',
|
||||
'SysvarC1ock11111111111111111111111111111111',
|
||||
'SysvarS1otHashes111111111111111111111111111',
|
||||
'Vote111111111111111111111111111111111111111',
|
||||
],
|
||||
header: {
|
||||
numReadonlySignedAccounts: 0,
|
||||
numReadonlyUnsignedAccounts: 3,
|
||||
numRequiredSignatures: 1,
|
||||
},
|
||||
instructions: [
|
||||
{
|
||||
accounts: [1, 3, 2, 0],
|
||||
data: '29z5mr1JoRmJYQ6zG7p2F3mu68pWTNw9q49Tu7KrSEgoS6Jh1LMPGUK3HXs1N3Dody3icCcXxu6xPYoXLWnUTafEGm3knK',
|
||||
programIdIndex: 4,
|
||||
},
|
||||
],
|
||||
recentBlockhash:
|
||||
'GLqYrN6AQxCGtFTQywkPj2WN5tafC3KerBhW4QkmAyD4',
|
||||
},
|
||||
signatures: [
|
||||
'4SZofEnXEVzCYvzk16z6ScR6F3iNtZ3FsCC1PEWegpzvGwTJR6x9cDi8VHRmCFGC5XFs2yEFms3j36Mj7XVyHXbb',
|
||||
],
|
||||
},
|
||||
version: 'legacy',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
await expect(
|
||||
connection.getBlock(1, {
|
||||
maxSupportedTransactionVersion: 0,
|
||||
transactionDetails: 'full',
|
||||
}),
|
||||
).not.to.eventually.be.rejected;
|
||||
});
|
||||
|
||||
it('can deserialize a response when `transactionDetails` is `none`', async () => {
|
||||
// Mock block with transaction, fetched using `"transactionDetails": "none"`.
|
||||
await mockRpcResponse({
|
||||
method: 'getBlock',
|
||||
params: [
|
||||
1,
|
||||
{
|
||||
maxSupportedTransactionVersion: 0,
|
||||
transactionDetails: 'none',
|
||||
},
|
||||
],
|
||||
value: {
|
||||
blockHeight: 0,
|
||||
blockTime: 1614281964,
|
||||
blockhash: '49d2UbduiZWjtR3Wvfv2t2QxmXvtZNWSPFRZxEDYAvQN',
|
||||
parentSlot: 0,
|
||||
previousBlockhash: 'mDd5yMLfuroS1JVZMHo2VZLTgKXXNBXrzPR5UkzFD4X',
|
||||
},
|
||||
});
|
||||
await expect(
|
||||
connection.getBlock(1, {
|
||||
maxSupportedTransactionVersion: 0,
|
||||
transactionDetails: 'none',
|
||||
}),
|
||||
).not.to.eventually.be.rejected;
|
||||
});
|
||||
|
||||
it('can deserialize a response when `transactionDetails` is `accounts`', async () => {
|
||||
// Mock block with transaction, fetched using `"transactionDetails": "accounts"`.
|
||||
await mockRpcResponse({
|
||||
method: 'getBlock',
|
||||
params: [
|
||||
1,
|
||||
{
|
||||
maxSupportedTransactionVersion: 0,
|
||||
transactionDetails: 'accounts',
|
||||
},
|
||||
],
|
||||
value: {
|
||||
blockHeight: 0,
|
||||
blockTime: 1614281964,
|
||||
blockhash: '49d2UbduiZWjtR3Wvfv2t2QxmXvtZNWSPFRZxEDYAvQN',
|
||||
parentSlot: 0,
|
||||
previousBlockhash: 'mDd5yMLfuroS1JVZMHo2VZLTgKXXNBXrzPR5UkzFD4X',
|
||||
transactions: [
|
||||
{
|
||||
meta: {
|
||||
err: null,
|
||||
fee: 5000,
|
||||
postBalances: [2751549948, 11751747405, 1169280, 143487360, 1],
|
||||
postTokenBalances: [],
|
||||
preBalances: [2751554948, 11751747405, 1169280, 143487360, 1],
|
||||
preTokenBalances: [],
|
||||
status: {Ok: null},
|
||||
},
|
||||
transaction: {
|
||||
accountKeys: [
|
||||
{
|
||||
pubkey: 'D7hwgGRTr1vaCxzmfEKCaf56SPgBJmjHh6UXHG3p12bB',
|
||||
signer: true,
|
||||
source: 'transaction',
|
||||
writable: true,
|
||||
},
|
||||
{
|
||||
pubkey: '8iLE53Y9k4sccy4gxrT936BHbhYS6J13kQT5vRXhXFMX',
|
||||
signer: false,
|
||||
source: 'transaction',
|
||||
writable: true,
|
||||
},
|
||||
{
|
||||
pubkey: 'SysvarC1ock11111111111111111111111111111111',
|
||||
signer: false,
|
||||
source: 'transaction',
|
||||
writable: false,
|
||||
},
|
||||
{
|
||||
pubkey: 'SysvarS1otHashes111111111111111111111111111',
|
||||
signer: false,
|
||||
source: 'transaction',
|
||||
writable: false,
|
||||
},
|
||||
{
|
||||
pubkey: 'Vote111111111111111111111111111111111111111',
|
||||
signer: false,
|
||||
source: 'transaction',
|
||||
writable: false,
|
||||
},
|
||||
],
|
||||
signatures: [
|
||||
'uNKj2ogn8ZRRjyVWXLC7sLRWpKQyMUomm66RXoDuWLXikPSJN8C7ZZK95j8S2bzcjwH6MvrXKSHtCWEURPpEXMB',
|
||||
],
|
||||
},
|
||||
version: 'legacy',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
await expect(
|
||||
connection.getBlock(1, {
|
||||
maxSupportedTransactionVersion: 0,
|
||||
transactionDetails: 'accounts',
|
||||
}),
|
||||
).not.to.eventually.be.rejected;
|
||||
});
|
||||
});
|
||||
|
||||
describe('get confirmed block', function () {
|
||||
|
|
Loading…
Reference in New Issue