feat: adds getBlockProduction RPC call
This commit is contained in:
@ -754,6 +754,48 @@ export type BlockSignatures = {
|
|||||||
blockTime: number | null;
|
blockTime: number | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* recent block production information
|
||||||
|
*/
|
||||||
|
export type BlockProduction = Readonly<{
|
||||||
|
/** a dictionary of validator identities, as base-58 encoded strings. Value is a two element array containing the number of leader slots and the number of blocks produced */
|
||||||
|
byIdentity: Readonly<Record<string, ReadonlyArray<number>>>;
|
||||||
|
/** Block production slot range */
|
||||||
|
range: Readonly<{
|
||||||
|
/** first slot of the block production information (inclusive) */
|
||||||
|
firstSlot: number;
|
||||||
|
/** last slot of block production information (inclusive) */
|
||||||
|
lastSlot: number;
|
||||||
|
}>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type GetBlockProductionConfig = {
|
||||||
|
/** Optional commitment level */
|
||||||
|
commitment?: Commitment;
|
||||||
|
/** Slot range to return block production for. If parameter not provided, defaults to current epoch. */
|
||||||
|
range?: {
|
||||||
|
/** first slot to return block production information for (inclusive) */
|
||||||
|
firstSlot: number;
|
||||||
|
/** last slot to return block production information for (inclusive). If parameter not provided, defaults to the highest slot */
|
||||||
|
lastSlot?: number;
|
||||||
|
};
|
||||||
|
/** Only return results for this validator identity (base-58 encoded) */
|
||||||
|
identity?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expected JSON RPC response for the "getBlockProduction" message
|
||||||
|
*/
|
||||||
|
const BlockProductionResponseStruct = jsonRpcResultAndContext(
|
||||||
|
pick({
|
||||||
|
byIdentity: record(string(), array(number())),
|
||||||
|
range: pick({
|
||||||
|
firstSlot: number(),
|
||||||
|
lastSlot: number(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A performance sample
|
* A performance sample
|
||||||
*/
|
*/
|
||||||
@ -3230,6 +3272,51 @@ export class Connection {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the current block height of the node
|
||||||
|
*/
|
||||||
|
async getBlockHeight(commitment?: Commitment): Promise<number> {
|
||||||
|
const args = this._buildArgs([], commitment);
|
||||||
|
const unsafeRes = await this._rpcRequest('getBlockHeight', args);
|
||||||
|
const res = create(unsafeRes, jsonRpcResult(number()));
|
||||||
|
if ('error' in res) {
|
||||||
|
throw new Error(
|
||||||
|
'failed to get block height information: ' + res.error.message,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns recent block production information from the current or previous epoch
|
||||||
|
*/
|
||||||
|
async getBlockProduction(
|
||||||
|
configOrCommitment?: GetBlockProductionConfig | Commitment,
|
||||||
|
): Promise<RpcResponseAndContext<BlockProduction>> {
|
||||||
|
let extra: Omit<GetBlockProductionConfig, 'commitment'> | undefined;
|
||||||
|
let commitment: Commitment | undefined;
|
||||||
|
|
||||||
|
if (typeof configOrCommitment === 'string') {
|
||||||
|
commitment = configOrCommitment;
|
||||||
|
} else if (configOrCommitment) {
|
||||||
|
const {commitment: c, ...rest} = configOrCommitment;
|
||||||
|
commitment = c;
|
||||||
|
extra = rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
const args = this._buildArgs([], commitment, 'base64', extra);
|
||||||
|
const unsafeRes = await this._rpcRequest('getBlockProduction', args);
|
||||||
|
const res = create(unsafeRes, BlockProductionResponseStruct);
|
||||||
|
if ('error' in res) {
|
||||||
|
throw new Error(
|
||||||
|
'failed to get block production information: ' + res.error.message,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch a confirmed or finalized transaction from the cluster.
|
* Fetch a confirmed or finalized transaction from the cluster.
|
||||||
*/
|
*/
|
||||||
|
@ -1513,6 +1513,128 @@ describe('Connection', function () {
|
|||||||
expect(result).to.be.empty;
|
expect(result).to.be.empty;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('get block height', async () => {
|
||||||
|
const commitment: Commitment = 'confirmed';
|
||||||
|
|
||||||
|
await mockRpcResponse({
|
||||||
|
method: 'getBlockHeight',
|
||||||
|
params: [{commitment: commitment}],
|
||||||
|
value: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
const blockHeight = await connection.getBlockHeight(commitment);
|
||||||
|
expect(blockHeight).to.be.a('number');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('get block production', async () => {
|
||||||
|
const commitment: Commitment = 'processed';
|
||||||
|
|
||||||
|
// Find slot of the lowest confirmed block
|
||||||
|
await mockRpcResponse({
|
||||||
|
method: 'getFirstAvailableBlock',
|
||||||
|
params: [],
|
||||||
|
value: 1,
|
||||||
|
});
|
||||||
|
let firstSlot = await connection.getFirstAvailableBlock();
|
||||||
|
|
||||||
|
// Find current block height
|
||||||
|
await mockRpcResponse({
|
||||||
|
method: 'getBlockHeight',
|
||||||
|
params: [{commitment: commitment}],
|
||||||
|
value: 10,
|
||||||
|
});
|
||||||
|
let lastSlot = await connection.getBlockHeight(commitment);
|
||||||
|
|
||||||
|
const blockProductionConfig = {
|
||||||
|
commitment: commitment,
|
||||||
|
range: {
|
||||||
|
firstSlot,
|
||||||
|
lastSlot,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const blockProductionRet = {
|
||||||
|
byIdentity: {
|
||||||
|
'85iYT5RuzRTDgjyRa3cP8SYhM2j21fj7NhfJ3peu1DPr': [12, 10],
|
||||||
|
},
|
||||||
|
range: {
|
||||||
|
firstSlot,
|
||||||
|
lastSlot,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
//mock RPC call with config specified
|
||||||
|
await mockRpcResponse({
|
||||||
|
method: 'getBlockProduction',
|
||||||
|
params: [blockProductionConfig],
|
||||||
|
value: blockProductionRet,
|
||||||
|
withContext: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
//mock RPC call with commitment only
|
||||||
|
await mockRpcResponse({
|
||||||
|
method: 'getBlockProduction',
|
||||||
|
params: [{commitment: commitment}],
|
||||||
|
value: blockProductionRet,
|
||||||
|
withContext: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await connection.getBlockProduction(blockProductionConfig);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
expect(result).to.be.ok;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(result.context).to.be.ok;
|
||||||
|
expect(result.value).to.be.ok;
|
||||||
|
|
||||||
|
const resultContextSlot = result.context.slot;
|
||||||
|
expect(resultContextSlot).to.be.a('number');
|
||||||
|
|
||||||
|
const resultIdentityDictionary = result.value.byIdentity;
|
||||||
|
expect(resultIdentityDictionary).to.be.a('object');
|
||||||
|
|
||||||
|
for (var key in resultIdentityDictionary) {
|
||||||
|
expect(key).to.be.a('string');
|
||||||
|
expect(resultIdentityDictionary[key]).to.be.a('array');
|
||||||
|
expect(resultIdentityDictionary[key][0]).to.be.a('number');
|
||||||
|
expect(resultIdentityDictionary[key][1]).to.be.a('number');
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultSlotRange = result.value.range;
|
||||||
|
expect(resultSlotRange.firstSlot).to.equal(firstSlot);
|
||||||
|
expect(resultSlotRange.lastSlot).to.equal(lastSlot);
|
||||||
|
|
||||||
|
const resultCommitmentOnly = await connection.getBlockProduction(
|
||||||
|
commitment,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!resultCommitmentOnly) {
|
||||||
|
expect(resultCommitmentOnly).to.be.ok;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
expect(resultCommitmentOnly.context).to.be.ok;
|
||||||
|
expect(resultCommitmentOnly.value).to.be.ok;
|
||||||
|
|
||||||
|
const resultCOContextSlot = result.context.slot;
|
||||||
|
expect(resultCOContextSlot).to.be.a('number');
|
||||||
|
|
||||||
|
const resultCOIdentityDictionary = result.value.byIdentity;
|
||||||
|
expect(resultCOIdentityDictionary).to.be.a('object');
|
||||||
|
|
||||||
|
for (var property in resultCOIdentityDictionary) {
|
||||||
|
expect(property).to.be.a('string');
|
||||||
|
expect(resultCOIdentityDictionary[property]).to.be.a('array');
|
||||||
|
expect(resultCOIdentityDictionary[property][0]).to.be.a('number');
|
||||||
|
expect(resultCOIdentityDictionary[property][1]).to.be.a('number');
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultCOSlotRange = result.value.range;
|
||||||
|
expect(resultCOSlotRange.firstSlot).to.equal(firstSlot);
|
||||||
|
expect(resultCOSlotRange.lastSlot).to.equal(lastSlot);
|
||||||
|
});
|
||||||
|
|
||||||
it('get transaction', async () => {
|
it('get transaction', async () => {
|
||||||
await mockRpcResponse({
|
await mockRpcResponse({
|
||||||
method: 'getSlot',
|
method: 'getSlot',
|
||||||
|
Reference in New Issue
Block a user