feat: expose feeCalculator

This commit is contained in:
Michael Vines
2019-06-12 14:36:05 -07:00
parent 9fde1eb404
commit 10e3a26338
7 changed files with 91 additions and 20 deletions

View File

@ -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,

View File

@ -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 = {

View 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,
};

View File

@ -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;

View File

@ -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,

View File

@ -18,7 +18,7 @@ export function mockGetRecentBlockhash() {
result: [ result: [
recentBlockhash.publicKey.toBase58(), recentBlockhash.publicKey.toBase58(),
{ {
/* empty fee calculator */ lamportsPerSignature: 42,
}, },
], ],
}, },

View File

@ -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([