feat: expose feeCalculator
This commit is contained in:
@ -32,6 +32,13 @@ declare module '@solana/web3.js' {
|
|||||||
secretKey: Buffer;
|
secretKey: Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === src/fee-calculator.js ===
|
||||||
|
declare export type FeeCalculator = {
|
||||||
|
lamportsPerSignature: number,
|
||||||
|
targetSignaturesPerSlot: number,
|
||||||
|
targetLamportsPerSignature: number,
|
||||||
|
};
|
||||||
|
|
||||||
// === src/budget-program.js ===
|
// === src/budget-program.js ===
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
|
||||||
@ -55,6 +62,13 @@ declare module '@solana/web3.js' {
|
|||||||
accountInfo: AccountInfo,
|
accountInfo: AccountInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare export type VoteAccountInfo = {
|
||||||
|
votePubkey: string,
|
||||||
|
nodePubkey: string,
|
||||||
|
stake: number,
|
||||||
|
commission: number,
|
||||||
|
};
|
||||||
|
|
||||||
declare type AccountChangeCallback = (accountInfo: AccountInfo) => void;
|
declare type AccountChangeCallback = (accountInfo: AccountInfo) => void;
|
||||||
declare type ProgramAccountChangeCallback = (
|
declare type ProgramAccountChangeCallback = (
|
||||||
keyedAccountInfo: KeyedAccountInfo,
|
keyedAccountInfo: KeyedAccountInfo,
|
||||||
@ -72,13 +86,14 @@ declare module '@solana/web3.js' {
|
|||||||
getAccountInfo(publicKey: PublicKey): Promise<AccountInfo>;
|
getAccountInfo(publicKey: PublicKey): Promise<AccountInfo>;
|
||||||
getBalance(publicKey: PublicKey): Promise<number>;
|
getBalance(publicKey: PublicKey): Promise<number>;
|
||||||
getClusterNodes(): Promise<Array<ContactInfo>>;
|
getClusterNodes(): Promise<Array<ContactInfo>>;
|
||||||
|
getEpochVoteAccounts(): Promise<Array<VoteAccountInfo>>;
|
||||||
confirmTransaction(signature: TransactionSignature): Promise<boolean>;
|
confirmTransaction(signature: TransactionSignature): Promise<boolean>;
|
||||||
getSlotLeader(): Promise<string>;
|
getSlotLeader(): Promise<string>;
|
||||||
getSignatureStatus(
|
getSignatureStatus(
|
||||||
signature: TransactionSignature,
|
signature: TransactionSignature,
|
||||||
): Promise<SignatureSuccess | TransactionError | null>;
|
): Promise<SignatureSuccess | TransactionError | null>;
|
||||||
getTransactionCount(): Promise<number>;
|
getTransactionCount(): Promise<number>;
|
||||||
getRecentBlockhash(): Promise<Blockhash>;
|
getRecentBlockhash(): Promise<[Blockhash, FeeCalculator]>;
|
||||||
requestAirdrop(
|
requestAirdrop(
|
||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
amount: number,
|
amount: number,
|
||||||
|
@ -12,6 +12,7 @@ import {PublicKey} from './publickey';
|
|||||||
import {Transaction} from './transaction';
|
import {Transaction} from './transaction';
|
||||||
import {sleep} from './util/sleep';
|
import {sleep} from './util/sleep';
|
||||||
import type {Blockhash} from './blockhash';
|
import type {Blockhash} from './blockhash';
|
||||||
|
import type {FeeCalculator} from './fee-calculator';
|
||||||
import type {Account} from './account';
|
import type {Account} from './account';
|
||||||
import type {TransactionSignature} from './transaction';
|
import type {TransactionSignature} from './transaction';
|
||||||
|
|
||||||
@ -203,8 +204,23 @@ const GetTransactionCountRpcResult = jsonRpcResult('number');
|
|||||||
/**
|
/**
|
||||||
* Expected JSON RPC response for the "getRecentBlockhash" message
|
* Expected JSON RPC response for the "getRecentBlockhash" message
|
||||||
*/
|
*/
|
||||||
const GetRecentBlockhash = jsonRpcResult(['string', 'object']);
|
const GetRecentBlockhash = jsonRpcResult([
|
||||||
const GetRecentBlockhash_014 = jsonRpcResult('string'); // Legacy v0.14 response. TODO: Remove in July 2019
|
'string',
|
||||||
|
struct({
|
||||||
|
lamportsPerSignature: 'number',
|
||||||
|
targetLamportsPerSignature: 'number',
|
||||||
|
targetSignaturesPerSlot: 'number',
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
const GetRecentBlockhash_015 = jsonRpcResult([
|
||||||
|
'string',
|
||||||
|
struct({
|
||||||
|
lamportsPerSignature: 'number',
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expected JSON RPC response for the "requestAirdrop" message
|
* Expected JSON RPC response for the "requestAirdrop" message
|
||||||
@ -292,6 +308,12 @@ export type TransactionError = {|
|
|||||||
Err: Object,
|
Err: Object,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
type BlockhashAndFeeCalculator = [Blockhash, FeeCalculator]; // This type exists to workaround an esdoc parse error
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A connection to a fullnode JSON RPC endpoint
|
* A connection to a fullnode JSON RPC endpoint
|
||||||
*/
|
*/
|
||||||
@ -473,28 +495,32 @@ export class Connection {
|
|||||||
/**
|
/**
|
||||||
* Fetch a recent blockhash from the cluster
|
* Fetch a recent blockhash from the cluster
|
||||||
*/
|
*/
|
||||||
async getRecentBlockhash(): Promise<Blockhash> {
|
async getRecentBlockhash(): Promise<BlockhashAndFeeCalculator> {
|
||||||
const unsafeRes = await this._rpcRequest('getRecentBlockhash', []);
|
const unsafeRes = await this._rpcRequest('getRecentBlockhash', []);
|
||||||
|
|
||||||
// Legacy v0.14 response. TODO: Remove in July 2019
|
// Legacy v0.15 response. TODO: Remove in August 2019
|
||||||
try {
|
try {
|
||||||
const res_014 = GetRecentBlockhash_014(unsafeRes);
|
const res_015 = GetRecentBlockhash_015(unsafeRes);
|
||||||
if (res_014.error) {
|
if (res_015.error) {
|
||||||
throw new Error(res_014.error.message);
|
throw new Error(res_015.error.message);
|
||||||
}
|
}
|
||||||
return res_014.result;
|
const [blockhash, feeCalculator] = res_015.result;
|
||||||
|
feeCalculator.targetSignaturesPerSlot = 42;
|
||||||
|
feeCalculator.targetLamportsPerSignature =
|
||||||
|
feeCalculator.lamportsPerSignature;
|
||||||
|
|
||||||
|
return [blockhash, feeCalculator];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Not legacy format
|
// Not legacy format
|
||||||
}
|
}
|
||||||
// End Legacy v0.14 response
|
// End Legacy v0.15 response
|
||||||
|
|
||||||
const res = GetRecentBlockhash(unsafeRes);
|
const res = GetRecentBlockhash(unsafeRes);
|
||||||
if (res.error) {
|
if (res.error) {
|
||||||
throw new Error(res.error.message);
|
throw new Error(res.error.message);
|
||||||
}
|
}
|
||||||
assert(typeof res.result !== 'undefined');
|
assert(typeof res.result !== 'undefined');
|
||||||
// TODO: deserialize and expose FeeCalculator in res.result[1]
|
return res.result;
|
||||||
return res.result[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -552,7 +578,10 @@ export class Connection {
|
|||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const recentBlockhash = await this.getRecentBlockhash();
|
const [
|
||||||
|
recentBlockhash,
|
||||||
|
//feeCalculator,
|
||||||
|
] = await this.getRecentBlockhash();
|
||||||
|
|
||||||
if (this._blockhashInfo.recentBlockhash != recentBlockhash) {
|
if (this._blockhashInfo.recentBlockhash != recentBlockhash) {
|
||||||
this._blockhashInfo = {
|
this._blockhashInfo = {
|
||||||
|
13
web3.js/src/fee-calculator.js
Normal file
13
web3.js/src/fee-calculator.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} FeeCalculator
|
||||||
|
* @property {number} lamportsPerSignature lamports Cost in lamports to validate a signature
|
||||||
|
* @property {number} targetLamportsPerSignature
|
||||||
|
* @property {number} targetSignaturesPerSlot
|
||||||
|
*/
|
||||||
|
export type FeeCalculator = {
|
||||||
|
lamportsPerSignature: number,
|
||||||
|
targetSignaturesPerSlot: number,
|
||||||
|
targetLamportsPerSignature: number,
|
||||||
|
};
|
@ -1,6 +1,14 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
// These constants should match the values in
|
// TODO: These constants should be removed in favor of reading them out of a
|
||||||
// https://github.com/solana-labs/solana/blob/master/sdk/src/timing.rs
|
// Syscall account
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
export const NUM_TICKS_PER_SECOND = 10;
|
export const NUM_TICKS_PER_SECOND = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
export const DEFAULT_TICKS_PER_SLOT = 8;
|
export const DEFAULT_TICKS_PER_SLOT = 8;
|
||||||
|
@ -204,8 +204,12 @@ test('get recent blockhash', async () => {
|
|||||||
|
|
||||||
mockGetRecentBlockhash();
|
mockGetRecentBlockhash();
|
||||||
|
|
||||||
const recentBlockhash = await connection.getRecentBlockhash();
|
const [
|
||||||
|
recentBlockhash,
|
||||||
|
feeCalculator,
|
||||||
|
] = await connection.getRecentBlockhash();
|
||||||
expect(recentBlockhash.length).toBeGreaterThanOrEqual(43);
|
expect(recentBlockhash.length).toBeGreaterThanOrEqual(43);
|
||||||
|
expect(feeCalculator.lamportsPerSignature).toBeGreaterThanOrEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('request airdrop', async () => {
|
test('request airdrop', async () => {
|
||||||
@ -482,7 +486,9 @@ test('multi-instruction transaction', async () => {
|
|||||||
accountFrom.publicKey,
|
accountFrom.publicKey,
|
||||||
accountTo.publicKey,
|
accountTo.publicKey,
|
||||||
100,
|
100,
|
||||||
).add(SystemProgram.transfer(accountTo.publicKey, accountFrom.publicKey, 100));
|
).add(
|
||||||
|
SystemProgram.transfer(accountTo.publicKey, accountFrom.publicKey, 100),
|
||||||
|
);
|
||||||
const signature = await connection.sendTransaction(
|
const signature = await connection.sendTransaction(
|
||||||
transaction,
|
transaction,
|
||||||
accountFrom,
|
accountFrom,
|
||||||
|
@ -18,7 +18,7 @@ export function mockGetRecentBlockhash() {
|
|||||||
result: [
|
result: [
|
||||||
recentBlockhash.publicKey.toBase58(),
|
recentBlockhash.publicKey.toBase58(),
|
||||||
{
|
{
|
||||||
/* empty fee calculator */
|
lamportsPerSignature: 42,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -137,11 +137,11 @@ test('transaction-payer', async () => {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// accountPayer should be less less than 100 as it paid for the transaction
|
// accountPayer could be less than 100 as it paid for the transaction
|
||||||
// (exact amount less depends on the current cluster fees)
|
// (exact amount less depends on the current cluster fees)
|
||||||
const balance = await connection.getBalance(accountPayer.publicKey);
|
const balance = await connection.getBalance(accountPayer.publicKey);
|
||||||
expect(balance).toBeGreaterThan(0);
|
expect(balance).toBeGreaterThan(0);
|
||||||
expect(balance).toBeLessThanOrEqual(99);
|
expect(balance).toBeLessThanOrEqual(100);
|
||||||
|
|
||||||
// accountFrom should have exactly 2, since it didn't pay for the transaction
|
// accountFrom should have exactly 2, since it didn't pay for the transaction
|
||||||
mockRpc.push([
|
mockRpc.push([
|
||||||
|
Reference in New Issue
Block a user