fix: update ConfirmedBlock handling to match solana upstream
This commit is contained in:
parent
77745a278d
commit
a461d5f25f
|
@ -71,6 +71,13 @@ declare module '@solana/web3.js' {
|
||||||
rpc: string | null,
|
rpc: string | null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare export type ConfirmedBlock = {
|
||||||
|
blockhash: Blockhash,
|
||||||
|
previousBlockhash: Blockhash,
|
||||||
|
parentSlot: number,
|
||||||
|
transactions: Array<[Transaction, SignatureSuccess | TransactionError | null]>,
|
||||||
|
};
|
||||||
|
|
||||||
declare export type KeyedAccountInfo = {
|
declare export type KeyedAccountInfo = {
|
||||||
accountId: PublicKey,
|
accountId: PublicKey,
|
||||||
accountInfo: AccountInfo,
|
accountInfo: AccountInfo,
|
||||||
|
@ -136,6 +143,7 @@ declare module '@solana/web3.js' {
|
||||||
): Promise<RpcResponseAndContext<number>>;
|
): Promise<RpcResponseAndContext<number>>;
|
||||||
getBalance(publicKey: PublicKey, commitment: ?Commitment): Promise<number>;
|
getBalance(publicKey: PublicKey, commitment: ?Commitment): Promise<number>;
|
||||||
getClusterNodes(): Promise<Array<ContactInfo>>;
|
getClusterNodes(): Promise<Array<ContactInfo>>;
|
||||||
|
getConfirmedBlock(): Promise<ConfirmedBlock>;
|
||||||
getVoteAccounts(commitment: ?Commitment): Promise<VoteAccountStatus>;
|
getVoteAccounts(commitment: ?Commitment): Promise<VoteAccountStatus>;
|
||||||
confirmTransactionAndContext(
|
confirmTransactionAndContext(
|
||||||
signature: TransactionSignature,
|
signature: TransactionSignature,
|
||||||
|
|
|
@ -186,6 +186,22 @@ const Version = struct({
|
||||||
'solana-core': 'string',
|
'solana-core': 'string',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ConfirmedBlock on the ledger
|
||||||
|
*
|
||||||
|
* @typedef {Object} ConfirmedBlock
|
||||||
|
* @property {Blockhash} blockhash Blockhash of this block
|
||||||
|
* @property {Blockhash} previousBlockhash Blockhash of this block's parent
|
||||||
|
* @property {number} parentSlot Slot index of this block's parent
|
||||||
|
* @property {Array<Array<object>>} transactions Vector of transactions paired with statuses
|
||||||
|
*/
|
||||||
|
type ConfirmedBlock = {
|
||||||
|
blockhash: Blockhash,
|
||||||
|
previousBlockhash: Blockhash,
|
||||||
|
parentSlot: number,
|
||||||
|
transactions: Array<[Transaction, GetSignatureStatusRpcResult]>,
|
||||||
|
};
|
||||||
|
|
||||||
function createRpcRequest(url): RpcRequest {
|
function createRpcRequest(url): RpcRequest {
|
||||||
const server = jayson(async (request, callback) => {
|
const server = jayson(async (request, callback) => {
|
||||||
const options = {
|
const options = {
|
||||||
|
@ -412,16 +428,20 @@ const GetMinimumBalanceForRentExemptionRpcResult = jsonRpcResult('number');
|
||||||
* Expected JSON RPC response for the "getConfirmedBlock" message
|
* Expected JSON RPC response for the "getConfirmedBlock" message
|
||||||
*/
|
*/
|
||||||
export const GetConfirmedBlockRpcResult = jsonRpcResult(
|
export const GetConfirmedBlockRpcResult = jsonRpcResult(
|
||||||
struct.list([
|
struct({
|
||||||
|
blockhash: struct.list(['number']),
|
||||||
|
previousBlockhash: struct.list(['number']),
|
||||||
|
parentSlot: 'number',
|
||||||
|
transactions: struct.list([
|
||||||
struct.tuple([
|
struct.tuple([
|
||||||
struct({
|
struct({
|
||||||
signatures: struct.list([struct.list(['number'])]),
|
signatures: struct.list([struct.list(['number'])]),
|
||||||
message: struct({
|
message: struct({
|
||||||
account_keys: struct.list([struct.list(['number'])]),
|
accountKeys: struct.list([struct.list(['number'])]),
|
||||||
header: struct({
|
header: struct({
|
||||||
num_required_signatures: 'number',
|
numRequiredSignatures: 'number',
|
||||||
num_readonly_signed_accounts: 'number',
|
numReadonlySignedAccounts: 'number',
|
||||||
num_readonly_unsigned_accounts: 'number',
|
numReadonlyUnsignedAccounts: 'number',
|
||||||
}),
|
}),
|
||||||
instructions: struct.list([
|
instructions: struct.list([
|
||||||
struct.union([
|
struct.union([
|
||||||
|
@ -433,16 +453,23 @@ export const GetConfirmedBlockRpcResult = jsonRpcResult(
|
||||||
data: struct.list([
|
data: struct.list([
|
||||||
struct.union([struct.list(['number']), 'number']),
|
struct.union([struct.list(['number']), 'number']),
|
||||||
]),
|
]),
|
||||||
program_id_index: 'number',
|
programIdIndex: 'number',
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
recent_blockhash: struct.list(['number']),
|
recentBlockhash: struct.list(['number']),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
struct.union([struct({Ok: 'null'}), struct({Err: 'object'})]),
|
struct.union([
|
||||||
|
'null',
|
||||||
|
struct({
|
||||||
|
status: GetSignatureStatusRpcResult,
|
||||||
|
fee: 'number',
|
||||||
|
}),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1055,20 +1082,23 @@ export class Connection {
|
||||||
* Fetch a list of Transactions and transaction statuses from the cluster
|
* Fetch a list of Transactions and transaction statuses from the cluster
|
||||||
* for a confirmed block
|
* for a confirmed block
|
||||||
*/
|
*/
|
||||||
async getConfirmedBlock(
|
async getConfirmedBlock(slot: number): Promise<ConfirmedBlock> {
|
||||||
slot: number,
|
|
||||||
): Promise<
|
|
||||||
Array<[Transaction, SignatureSuccess] | [Transaction, TransactionError]>,
|
|
||||||
> {
|
|
||||||
const unsafeRes = await this._rpcRequest('getConfirmedBlock', [slot]);
|
const unsafeRes = await this._rpcRequest('getConfirmedBlock', [slot]);
|
||||||
const result = GetConfirmedBlockRpcResult(unsafeRes);
|
const result = GetConfirmedBlockRpcResult(unsafeRes);
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
throw new Error(result.error.message);
|
throw new Error(result.error.message);
|
||||||
}
|
}
|
||||||
assert(typeof result.result !== 'undefined');
|
assert(typeof result.result !== 'undefined');
|
||||||
return result.result.map(result => {
|
return {
|
||||||
|
blockhash: new PublicKey(result.result.blockhash).toString(),
|
||||||
|
previousBlockhash: new PublicKey(
|
||||||
|
result.result.previousBlockhash,
|
||||||
|
).toString(),
|
||||||
|
parentSlot: result.result.parentSlot,
|
||||||
|
transactions: result.result.transactions.map(result => {
|
||||||
return [Transaction.fromRpcResult(result[0]), result[1]];
|
return [Transaction.fromRpcResult(result[0]), result[1]];
|
||||||
});
|
}),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -504,19 +504,19 @@ export class Transaction {
|
||||||
*/
|
*/
|
||||||
static fromRpcResult(rpcResult: any): Transaction {
|
static fromRpcResult(rpcResult: any): Transaction {
|
||||||
const signatures = rpcResult.signatures.slice(1);
|
const signatures = rpcResult.signatures.slice(1);
|
||||||
const accounts = rpcResult.message.account_keys.slice(1);
|
const accounts = rpcResult.message.accountKeys.slice(1);
|
||||||
const instructions = rpcResult.message.instructions.slice(1).map(ix => {
|
const instructions = rpcResult.message.instructions.slice(1).map(ix => {
|
||||||
ix.accounts.shift();
|
ix.accounts.shift();
|
||||||
ix.data.shift();
|
ix.data.shift();
|
||||||
return ix;
|
return ix;
|
||||||
});
|
});
|
||||||
const recentBlockhash = rpcResult.message.recent_blockhash;
|
const recentBlockhash = rpcResult.message.recentBlockhash;
|
||||||
const numRequiredSignatures =
|
const numRequiredSignatures =
|
||||||
rpcResult.message.header.num_required_signatures;
|
rpcResult.message.header.numRequiredSignatures;
|
||||||
const numReadonlySignedAccounts =
|
const numReadonlySignedAccounts =
|
||||||
rpcResult.message.header.num_readonly_signed_accounts;
|
rpcResult.message.header.numReadonlySignedAccounts;
|
||||||
const numReadonlyUnsignedAccounts =
|
const numReadonlyUnsignedAccounts =
|
||||||
rpcResult.message.header.num_readonly_unsigned_accounts;
|
rpcResult.message.header.numReadonlyUnsignedAccounts;
|
||||||
return Transaction._populate(
|
return Transaction._populate(
|
||||||
signatures,
|
signatures,
|
||||||
accounts,
|
accounts,
|
||||||
|
|
|
@ -426,12 +426,26 @@ test('get confirmed block', async () => {
|
||||||
}
|
}
|
||||||
const connection = new Connection(url);
|
const connection = new Connection(url);
|
||||||
|
|
||||||
// These test cases need to be updated when upstream solana RPC api is fleshed out
|
// Block 0 never has any transactions in automation localnet
|
||||||
const zeroTransactions = await connection.getConfirmedBlock(0);
|
const block0 = await connection.getConfirmedBlock(0);
|
||||||
expect(zeroTransactions.length).toBe(0);
|
const blockhash0 = block0.blockhash;
|
||||||
|
expect(block0.transactions.length).toBe(0);
|
||||||
|
expect(blockhash0).not.toBeNull();
|
||||||
|
expect(block0.previousBlockhash).not.toBeNull();
|
||||||
|
expect(block0.parentSlot).toBe(0);
|
||||||
|
|
||||||
const oneTransaction = await connection.getConfirmedBlock(1);
|
// Find a block that has a transaction, usually Block 1
|
||||||
expect(oneTransaction.length).toBe(1);
|
let x = 1;
|
||||||
|
while (x < 10) {
|
||||||
|
const block1 = await connection.getConfirmedBlock(x);
|
||||||
|
if (block1.transactions.length >= 1) {
|
||||||
|
expect(block1.previousBlockhash).toBe(blockhash0);
|
||||||
|
expect(block1.blockhash).not.toBeNull();
|
||||||
|
expect(block1.parentSlot).toBe(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('get recent blockhash', async () => {
|
test('get recent blockhash', async () => {
|
||||||
|
|
|
@ -105,7 +105,7 @@ test('transaction from rpc result', () => {
|
||||||
const rawBlockhash = new PublicKey(0).toBuffer();
|
const rawBlockhash = new PublicKey(0).toBuffer();
|
||||||
const rpcResult = {
|
const rpcResult = {
|
||||||
message: {
|
message: {
|
||||||
account_keys: [
|
accountKeys: [
|
||||||
[5],
|
[5],
|
||||||
new PublicKey(1).toBuffer(),
|
new PublicKey(1).toBuffer(),
|
||||||
new PublicKey(2).toBuffer(),
|
new PublicKey(2).toBuffer(),
|
||||||
|
@ -114,19 +114,19 @@ test('transaction from rpc result', () => {
|
||||||
new PublicKey(5).toBuffer(),
|
new PublicKey(5).toBuffer(),
|
||||||
],
|
],
|
||||||
header: {
|
header: {
|
||||||
num_readonly_signed_accounts: 0,
|
num_ReadonlySignedAccounts: 0,
|
||||||
num_readonly_unsigned_accounts: 3,
|
numReadonlyUnsignedAccounts: 3,
|
||||||
num_required_signatures: 2,
|
numRequiredSignatures: 2,
|
||||||
},
|
},
|
||||||
instructions: [
|
instructions: [
|
||||||
[1],
|
[1],
|
||||||
{
|
{
|
||||||
accounts: [[3], 1, 2, 3],
|
accounts: [[3], 1, 2, 3],
|
||||||
data: [[1], 0],
|
data: [[1], 0],
|
||||||
program_id_index: 4,
|
programIdIndex: 4,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
recent_blockhash: rawBlockhash,
|
recentBlockhash: rawBlockhash,
|
||||||
},
|
},
|
||||||
signatures: [[2], Array(64).fill(1), Array(64).fill(2)],
|
signatures: [[2], Array(64).fill(1), Array(64).fill(2)],
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue