feat: support rpc method getSignaturesByAddres

This commit is contained in:
Rohit Narurkar 2021-06-22 10:07:36 +04:00 committed by Michael Vines
parent 3362ac06b5
commit db3475bcdf
2 changed files with 165 additions and 0 deletions

View File

@ -127,6 +127,21 @@ export type ConfirmedSignaturesForAddress2Options = {
limit?: number;
};
/**
* Options for getSignaturesForAddress
*/
export type SignaturesForAddressOptions = {
/**
* Start searching backwards from this transaction signature.
* @remark If not provided the search starts from the highest max confirmed block.
*/
before?: TransactionSignature;
/** Search until this transaction signature is reached, if found before `limit`. */
until?: TransactionSignature;
/** Maximum transaction signatures to return (between 1 and 1,000, default: 1,000). */
limit?: number;
};
/**
* RPC Response with extra contextual information
*/
@ -1060,6 +1075,21 @@ const GetConfirmedSignaturesForAddress2RpcResult = jsonRpcResult(
),
);
/**
* Expected JSON RPC response for the "getSignaturesForAddress" message
*/
const GetSignaturesForAddressRpcResult = jsonRpcResult(
array(
pick({
signature: string(),
slot: number(),
err: TransactionErrorResult,
memo: nullable(string()),
blockTime: optional(nullable(number())),
}),
),
);
/***
* Expected JSON RPC response for the "accountNotification" message
*/
@ -3205,6 +3235,35 @@ export class Connection {
return res.result;
}
/**
* Returns confirmed signatures for transactions involving an
* address backwards in time from the provided signature or most recent confirmed block
*
*
* @param address queried address
* @param options
*/
async getSignaturesForAddress(
address: PublicKey,
options?: SignaturesForAddressOptions,
commitment?: Finality,
): Promise<Array<ConfirmedSignatureInfo>> {
const args = this._buildArgsAtLeastConfirmed(
[address.toBase58()],
commitment,
undefined,
options,
);
const unsafeRes = await this._rpcRequest('getSignaturesForAddress', args);
const res = create(unsafeRes, GetSignaturesForAddressRpcResult);
if ('error' in res) {
throw new Error(
'failed to get signatures for address: ' + res.error.message,
);
}
return res.result;
}
/**
* Fetch the contents of a Nonce account from the cluster, return with context
*/

View File

@ -1011,6 +1011,112 @@ describe('Connection', () => {
}
});
it('get signatures for address', async () => {
const connection = new Connection(url);
await mockRpcResponse({
method: 'getSlot',
params: [],
value: 1,
});
while ((await connection.getSlot()) <= 0) {
continue;
}
await mockRpcResponse({
method: 'getConfirmedBlock',
params: [1],
value: {
blockTime: 1614281964,
blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy',
previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo',
parentSlot: 0,
transactions: [
{
meta: {
fee: 10000,
postBalances: [499260347380, 15298080, 1, 1, 1],
preBalances: [499260357380, 15298080, 1, 1, 1],
status: {Ok: null},
err: null,
},
transaction: {
message: {
accountKeys: [
'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf',
'57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy',
'SysvarS1otHashes111111111111111111111111111',
'SysvarC1ock11111111111111111111111111111111',
'Vote111111111111111111111111111111111111111',
],
header: {
numReadonlySignedAccounts: 0,
numReadonlyUnsignedAccounts: 3,
numRequiredSignatures: 2,
},
instructions: [
{
accounts: [1, 2, 3],
data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7',
programIdIndex: 4,
},
],
recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE',
},
signatures: [
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt',
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG',
],
},
},
],
},
});
// Find a block that has a transaction, usually Block 1
let slot = 0;
let address: PublicKey | undefined;
let expectedSignature: string | undefined;
while (!address || !expectedSignature) {
slot++;
const block = await connection.getConfirmedBlock(slot);
if (block.transactions.length > 0) {
const {signature, publicKey} =
block.transactions[0].transaction.signatures[0];
if (signature) {
address = publicKey;
expectedSignature = bs58.encode(signature);
}
}
}
// getSignaturesForAddress tests...
await mockRpcResponse({
method: 'getSignaturesForAddress',
params: [address.toBase58(), {limit: 1}],
value: [
{
signature: expectedSignature,
slot,
err: null,
memo: null,
},
],
});
const signatures = await connection.getSignaturesForAddress(address, {
limit: 1,
});
expect(signatures).to.have.length(1);
if (mockServer) {
expect(signatures[0].signature).to.eq(expectedSignature);
expect(signatures[0].slot).to.eq(slot);
expect(signatures[0].err).to.be.null;
expect(signatures[0].memo).to.be.null;
}
});
it('get parsed confirmed transactions', async () => {
await mockRpcResponse({
method: 'getSlot',