diff --git a/web3.js/module.flow.js b/web3.js/module.flow.js index e4bea19d92..47ae704c90 100644 --- a/web3.js/module.flow.js +++ b/web3.js/module.flow.js @@ -22,6 +22,9 @@ declare module '@solana/web3.js' { toBuffer(): Buffer; } + // === src/blockhash.js === + declare export type Blockhash = string; + // === src/account.js === declare export class Account { constructor(secretKey: ?Buffer): Account; @@ -58,7 +61,7 @@ declare module '@solana/web3.js' { signature: TransactionSignature, ): Promise; getTransactionCount(): Promise; - getLastId(): Promise; + getRecentBlockhash(): Promise; requestAirdrop( to: PublicKey, amount: number, @@ -92,7 +95,6 @@ declare module '@solana/web3.js' { // === src/transaction.js === declare export type TransactionSignature = string; - declare export type TransactionId = string; declare type TransactionInstructionCtorFields = {| keys: ?Array, @@ -113,7 +115,7 @@ declare module '@solana/web3.js' { declare type TransactionCtorFields = {| fee?: number, - lastId?: TransactionId, + recentBlockhash?: Blockhash, signatures?: Array, |}; @@ -121,7 +123,7 @@ declare module '@solana/web3.js' { signatures: Array; signature: ?Buffer; instructions: Array; - lastId: ?TransactionId; + recentBlockhash: ?Blockhash; fee: number; constructor(opts?: TransactionCtorFields): Transaction; diff --git a/web3.js/src/blockhash.js b/web3.js/src/blockhash.js new file mode 100644 index 0000000000..d275a3a372 --- /dev/null +++ b/web3.js/src/blockhash.js @@ -0,0 +1,6 @@ +// @flow + +/** + * @typedef {string} Blockhhash + */ +export type Blockhash = string; diff --git a/web3.js/src/connection.js b/web3.js/src/connection.js index 6f1cb1c4a0..7e9e5896b4 100644 --- a/web3.js/src/connection.js +++ b/web3.js/src/connection.js @@ -10,8 +10,9 @@ import {Client as RpcWebSocketClient} from 'rpc-websockets'; import {Transaction} from './transaction'; import {PublicKey} from './publickey'; import {sleep} from './util/sleep'; +import type {Blockhash} from './blockhash'; import type {Account} from './account'; -import type {TransactionSignature, TransactionId} from './transaction'; +import type {TransactionSignature} from './transaction'; type RpcRequest = (methodName: string, args: Array) => any; @@ -124,9 +125,9 @@ const GetSignatureStatusRpcResult = jsonRpcResult( const GetTransactionCountRpcResult = jsonRpcResult('number'); /** - * Expected JSON RPC response for the "getLastId" message + * Expected JSON RPC response for the "getRecentBlockhash" message */ -const GetLastId = jsonRpcResult('string'); +const GetRecentBlockhash = jsonRpcResult('string'); /** * Expected JSON RPC response for the "requestAirdrop" message @@ -188,12 +189,12 @@ export class Connection { _rpcWebSocket: RpcWebSocketClient; _rpcWebSocketConnected: boolean = false; - _lastIdInfo: { - lastId: TransactionId | null, + _blockhashInfo: { + recentBlockhash: Blockhash | null, seconds: number, transactionSignatures: Array, }; - _disableLastIdCaching: boolean = false; + _disableBlockhashCaching: boolean = false; _accountChangeSubscriptions: {[number]: AccountSubscriptionInfo} = {}; _accountChangeSubscriptionCounter: number = 0; @@ -206,8 +207,8 @@ export class Connection { let url = urlParse(endpoint); this._rpcRequest = createRpcRequest(url.href); - this._lastIdInfo = { - lastId: null, + this._blockhashInfo = { + recentBlockhash: null, seconds: -1, transactionSignatures: [], }; @@ -283,7 +284,7 @@ export class Connection { } /** - * Fetch the current transaction count of the network + * Fetch the current transaction count of the cluster */ async getSignatureStatus( signature: TransactionSignature, @@ -298,7 +299,7 @@ export class Connection { } /** - * Fetch the current transaction count of the network + * Fetch the current transaction count of the cluster */ async getTransactionCount(): Promise { const unsafeRes = await this._rpcRequest('getTransactionCount', []); @@ -311,11 +312,11 @@ export class Connection { } /** - * Fetch the identifier to the latest transaction on the network + * Fetch a recent blockhash from the cluster */ - async getLastId(): Promise { - const unsafeRes = await this._rpcRequest('getLastId', []); - const res = GetLastId(unsafeRes); + async getRecentBlockhash(): Promise { + const unsafeRes = await this._rpcRequest('getRecentBlockhash', []); + const res = GetRecentBlockhash(unsafeRes); if (res.error) { throw new Error(res.error.message); } @@ -353,22 +354,22 @@ export class Connection { // Attempt to use the previous last id for up to 1 second const seconds = new Date().getSeconds(); if ( - this._lastIdInfo.lastId != null && - this._lastIdInfo.seconds === seconds + this._blockhashInfo.recentBlockhash != null && + this._blockhashInfo.seconds === seconds ) { - transaction.lastId = this._lastIdInfo.lastId; + transaction.recentBlockhash = this._blockhashInfo.recentBlockhash; transaction.sign(...signers); if (!transaction.signature) { throw new Error('!signature'); // should never happen } // If the signature of this transaction has not been seen before with the - // current lastId, all done. + // current recentBlockhash, all done. const signature = transaction.signature.toString(); - if (!this._lastIdInfo.transactionSignatures.includes(signature)) { - this._lastIdInfo.transactionSignatures.push(signature); - if (this._disableLastIdCaching) { - this._lastIdInfo.seconds = -1; + if (!this._blockhashInfo.transactionSignatures.includes(signature)) { + this._blockhashInfo.transactionSignatures.push(signature); + if (this._disableBlockhashCaching) { + this._blockhashInfo.seconds = -1; } break; } @@ -378,11 +379,11 @@ export class Connection { let attempts = 0; const startTime = Date.now(); for (;;) { - const lastId = await this.getLastId(); + const recentBlockhash = await this.getRecentBlockhash(); - if (this._lastIdInfo.lastId != lastId) { - this._lastIdInfo = { - lastId, + if (this._blockhashInfo.recentBlockhash != recentBlockhash) { + this._blockhashInfo = { + recentBlockhash, seconds: new Date().getSeconds(), transactionSignatures: [], }; diff --git a/web3.js/src/transaction.js b/web3.js/src/transaction.js index e0ad14fe6d..aafffa4bbc 100644 --- a/web3.js/src/transaction.js +++ b/web3.js/src/transaction.js @@ -9,17 +9,13 @@ import * as Layout from './layout'; import {PublicKey} from './publickey'; import {Account} from './account'; import * as shortvec from './util/shortvec-encoding'; +import type {Blockhash} from './blockhash'; /** * @typedef {string} TransactionSignature */ export type TransactionSignature = string; -/** - * @typedef {string} TransactionId - */ -export type TransactionId = string; - /** * Maximum over-the-wire size of a Transaction */ @@ -76,13 +72,13 @@ type SignaturePubkeyPair = {| * * @typedef {Object} TransactionCtorFields * @property {?number} fee - * @property (?lastId} A recent transaction id + * @property (?recentBlockhash} A recent block hash * @property (?signatures} One or more signatures * */ type TransactionCtorFields = {| fee?: number, - lastId?: TransactionId, + recentBlockhash?: Blockhash, signatures?: Array, |}; @@ -114,7 +110,7 @@ export class Transaction { /** * A recent transaction id. Must be populated by the caller */ - lastId: ?TransactionId; + recentBlockhash: ?Blockhash; /** * Fee for this transaction @@ -152,9 +148,9 @@ export class Transaction { * @private */ _getSignData(): Buffer { - const {lastId} = this; - if (!lastId) { - throw new Error('Transaction lastId required'); + const {recentBlockhash} = this; + if (!recentBlockhash) { + throw new Error('Transaction recentBlockhash required'); } if (this.instructions.length < 1) { @@ -245,7 +241,7 @@ export class Transaction { const signDataLayout = BufferLayout.struct([ BufferLayout.blob(keyCount.length, 'keyCount'), BufferLayout.seq(Layout.publicKey('key'), keys.length, 'keys'), - Layout.publicKey('lastId'), + Layout.publicKey('recentBlockhash'), BufferLayout.ns64('fee'), BufferLayout.blob(programIdCount.length, 'programIdCount'), @@ -259,7 +255,7 @@ export class Transaction { const transaction = { keyCount: Buffer.from(keyCount), keys: keys.map(key => new PublicKey(key).toBuffer()), - lastId: Buffer.from(bs58.decode(lastId)), + recentBlockhash: Buffer.from(bs58.decode(recentBlockhash)), fee: this.fee, programIdCount: Buffer.from(programIdCount), programIds: programIds.map(programId => @@ -284,7 +280,7 @@ export class Transaction { * as doing so may invalidate the signature and cause the Transaction to be * rejected. * - * The Transaction must be assigned a valid `lastId` before invoking this method + * The Transaction must be assigned a valid `recentBlockhash` before invoking this method */ sign(...signers: Array) { this.signPartial(...signers); @@ -442,7 +438,7 @@ export class Transaction { accounts.push(account); } - const lastId = byteArray.slice(0, PUBKEY_LENGTH); + const recentBlockhash = byteArray.slice(0, PUBKEY_LENGTH); byteArray = byteArray.slice(PUBKEY_LENGTH); let fee = 0; @@ -473,7 +469,7 @@ export class Transaction { } // Populate Transaction object - transaction.lastId = new PublicKey(lastId).toBase58(); + transaction.recentBlockhash = new PublicKey(recentBlockhash).toBase58(); transaction.fee = fee; for (let i = 0; i < signatureCount; i++) { const sigPubkeyPair = { diff --git a/web3.js/test/connection.test.js b/web3.js/test/connection.test.js index d4bda7a193..51fa8126c4 100644 --- a/web3.js/test/connection.test.js +++ b/web3.js/test/connection.test.js @@ -8,7 +8,7 @@ import { sendAndConfirmTransaction, } from '../src'; import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch'; -import {mockGetLastId} from './mockrpc/getlastid'; +import {mockGetRecentBlockhash} from './mockrpc/get-recent-blockhash'; import {url} from './url'; import {sleep} from '../src/util/sleep'; @@ -117,10 +117,10 @@ test('get transaction count', async () => { test('get last Id', async () => { const connection = new Connection(url); - mockGetLastId(); + mockGetRecentBlockhash(); - const lastId = await connection.getLastId(); - expect(lastId.length).toBeGreaterThanOrEqual(43); + const recentBlockhash = await connection.getRecentBlockhash(); + expect(recentBlockhash.length).toBeGreaterThanOrEqual(43); }); test('request airdrop', async () => { @@ -282,7 +282,7 @@ test('transaction', async () => { await connection.requestAirdrop(accountTo.publicKey, 21); expect(await connection.getBalance(accountTo.publicKey)).toBe(21); - mockGetLastId(); + mockGetRecentBlockhash(); mockRpc.push([ url, { diff --git a/web3.js/test/mockrpc/getlastid.js b/web3.js/test/mockrpc/get-recent-blockhash.js similarity index 56% rename from web3.js/test/mockrpc/getlastid.js rename to web3.js/test/mockrpc/get-recent-blockhash.js index c451e5b7be..0689002942 100644 --- a/web3.js/test/mockrpc/getlastid.js +++ b/web3.js/test/mockrpc/get-recent-blockhash.js @@ -4,18 +4,18 @@ import {Account} from '../../src'; import {url} from '../url'; import {mockRpc} from '../__mocks__/node-fetch'; -export function mockGetLastId() { - const lastId = new Account(); +export function mockGetRecentBlockhash() { + const recentBlockhash = new Account(); mockRpc.push([ url, { - method: 'getLastId', + method: 'getRecentBlockhash', params: [], }, { error: null, - result: lastId.publicKey.toBase58(), + result: recentBlockhash.publicKey.toBase58(), }, ]); } diff --git a/web3.js/test/token-program.test.js b/web3.js/test/token-program.test.js index 77ac7e8be5..66219a3799 100644 --- a/web3.js/test/token-program.test.js +++ b/web3.js/test/token-program.test.js @@ -5,7 +5,7 @@ import {SYSTEM_TOKEN_PROGRAM_ID} from '../src/token-program'; import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch'; import {url} from './url'; import {newAccountWithTokens} from './new-account-with-tokens'; -import {mockGetLastId} from './mockrpc/getlastid'; +import {mockGetRecentBlockhash} from './mockrpc/get-recent-blockhash'; import {sleep} from '../src/util/sleep'; if (!mockRpcEnabled) { @@ -48,29 +48,29 @@ let initialOwnerTokenAccount: PublicKey; test('create new token', async () => { const connection = new Connection(url); - connection._disableLastIdCaching = mockRpcEnabled; + connection._disableBlockhashCaching = mockRpcEnabled; initialOwner = await newAccountWithTokens(connection, 1024); { // mock SystemProgram.createAccount transaction for Token.createNewToken() - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus(); // mock Token.newAccount() transaction - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus('SignatureNotFound'); mockGetSignatureStatus(); // mock SystemProgram.createAccount transaction for Token.createNewToken() - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus(); // mock Token.createNewToken() transaction - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus('SignatureNotFound'); mockGetSignatureStatus(); @@ -228,17 +228,17 @@ test('create new token', async () => { test('create new token account', async () => { const connection = new Connection(url); - connection._disableLastIdCaching = mockRpcEnabled; + connection._disableBlockhashCaching = mockRpcEnabled; const destOwner = await newAccountWithTokens(connection); { // mock SystemProgram.createAccount transaction for Token.newAccount() - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus(); // mock Token.newAccount() transaction - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus(); } @@ -287,17 +287,17 @@ test('create new token account', async () => { test('transfer', async () => { const connection = new Connection(url); - connection._disableLastIdCaching = mockRpcEnabled; + connection._disableBlockhashCaching = mockRpcEnabled; const destOwner = await newAccountWithTokens(connection); { // mock SystemProgram.createAccount transaction for Token.newAccount() - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus(); // mock Token.newAccount() transaction - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus(); } @@ -337,7 +337,7 @@ test('transfer', async () => { ]); // mock Token.transfer() transaction - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus(); } @@ -385,17 +385,17 @@ test('transfer', async () => { test('approve/revoke', async () => { const connection = new Connection(url); - connection._disableLastIdCaching = mockRpcEnabled; + connection._disableBlockhashCaching = mockRpcEnabled; const delegateOwner = await newAccountWithTokens(connection); { // mock SystemProgram.createAccount transaction for Token.newAccount() - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus(); // mock Token.newAccount() transaction - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus(); } @@ -406,7 +406,7 @@ test('approve/revoke', async () => { { // mock Token.approve() transaction - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus(); } @@ -474,7 +474,7 @@ test('approve/revoke', async () => { { // mock Token.revoke() transaction - mockGetLastId(); + mockGetRecentBlockhash(); mockSendTransaction(); mockGetSignatureStatus(); } @@ -542,7 +542,7 @@ test('invalid approve', async () => { } const connection = new Connection(url); - connection._disableLastIdCaching = mockRpcEnabled; + connection._disableBlockhashCaching = mockRpcEnabled; const owner = await newAccountWithTokens(connection); const account1 = await testToken.newAccount(owner); @@ -567,7 +567,7 @@ test('fail on approve overspend', async () => { } const connection = new Connection(url); - connection._disableLastIdCaching = mockRpcEnabled; + connection._disableBlockhashCaching = mockRpcEnabled; const owner = await newAccountWithTokens(connection); const account1 = await testToken.newAccount(owner); @@ -611,7 +611,7 @@ test('set owner', async () => { } const connection = new Connection(url); - connection._disableLastIdCaching = mockRpcEnabled; + connection._disableBlockhashCaching = mockRpcEnabled; const owner = await newAccountWithTokens(connection); const newOwner = await newAccountWithTokens(connection); diff --git a/web3.js/test/transaction.test.js b/web3.js/test/transaction.test.js index 8c29f62954..b025a7d5b8 100644 --- a/web3.js/test/transaction.test.js +++ b/web3.js/test/transaction.test.js @@ -7,13 +7,13 @@ import {SystemProgram} from '../src/system-program'; test('signPartial', () => { const account1 = new Account(); const account2 = new Account(); - const lastId = account1.publicKey.toBase58(); // Fake lastId + const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash const move = SystemProgram.move(account1.publicKey, account2.publicKey, 123); - const transaction = new Transaction({lastId}).add(move); + const transaction = new Transaction({recentBlockhash}).add(move); transaction.sign(account1, account2); - const partialTransaction = new Transaction({lastId}).add(move); + const partialTransaction = new Transaction({recentBlockhash}).add(move); partialTransaction.signPartial(account1, account2.publicKey); expect(partialTransaction.signatures[1].signature).toBeNull(); partialTransaction.addSigner(account2); @@ -24,15 +24,15 @@ test('signPartial', () => { test('transfer signatures', () => { const account1 = new Account(); const account2 = new Account(); - const lastId = account1.publicKey.toBase58(); // Fake lastId + const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash const move1 = SystemProgram.move(account1.publicKey, account2.publicKey, 123); const move2 = SystemProgram.move(account2.publicKey, account1.publicKey, 123); - const orgTransaction = new Transaction({lastId}).add(move1, move2); + const orgTransaction = new Transaction({recentBlockhash}).add(move1, move2); orgTransaction.sign(account1, account2); const newTransaction = new Transaction({ - lastId: orgTransaction.lastId, + recentBlockhash: orgTransaction.recentBlockhash, fee: orgTransaction.fee, signatures: orgTransaction.signatures, }).add(move1, move2); @@ -41,13 +41,13 @@ test('transfer signatures', () => { }); test('parse wire format and serialize', () => { - const lastId = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known lastId + const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash const sender = new Account(Buffer.alloc(64, 8)); // Arbitrary known account const recipient = new PublicKey( 'J3dxNj7nDRRqRRXuEMynDG57DkZK4jYRuv3Garmb1i99', ); // Arbitrary known public key const move = SystemProgram.move(sender.publicKey, recipient, 49); - const expectedTransaction = new Transaction({lastId}).add(move); + const expectedTransaction = new Transaction({recentBlockhash}).add(move); expectedTransaction.sign(sender); const wireTransaction = Buffer.from([