2020-04-21 00:40:44 -07:00
import bs58 from 'bs58' ;
2021-02-05 18:59:00 -08:00
import { Buffer } from 'buffer' ;
2022-05-06 09:14:11 -07:00
import * as splToken from '@solana/spl-token' ;
2021-02-05 18:59:00 -08:00
import { expect , use } from 'chai' ;
import chaiAsPromised from 'chai-as-promised' ;
2022-11-28 11:55:56 -08:00
import { mock , useFakeTimers , SinonFakeTimers } from 'sinon' ;
import sinonChai from 'sinon-chai' ;
2020-04-21 00:40:44 -07:00
2019-06-28 18:28:06 -07:00
import {
2020-09-16 23:50:13 -07:00
Authorized ,
2019-06-28 18:28:06 -07:00
Connection ,
2021-06-09 22:47:54 -07:00
EpochSchedule ,
2019-06-28 18:28:06 -07:00
SystemProgram ,
2020-09-10 00:43:32 -07:00
Transaction ,
2019-12-30 10:36:12 -08:00
LAMPORTS_PER_SOL ,
2020-09-16 23:50:13 -07:00
Lockup ,
2020-04-21 00:40:44 -07:00
PublicKey ,
2020-09-16 23:50:13 -07:00
StakeProgram ,
2021-02-05 18:59:00 -08:00
sendAndConfirmTransaction ,
2021-05-07 01:59:51 -07:00
Keypair ,
2021-09-16 14:10:28 -07:00
Message ,
2022-08-14 03:11:49 -07:00
AddressLookupTableProgram ,
2022-08-25 06:42:54 -07:00
SYSTEM_INSTRUCTION_LAYOUTS ,
2022-11-28 22:46:27 -08:00
NONCE_ACCOUNT_LENGTH ,
2019-06-28 18:28:06 -07:00
} from '../src' ;
2022-08-11 02:10:11 -07:00
import invariant from '../src/utils/assert' ;
2021-02-05 18:59:00 -08:00
import { MOCK_PORT , url } from './url' ;
2021-03-14 22:08:10 -07:00
import {
2022-04-09 12:48:58 -07:00
AccountInfo ,
2021-03-14 22:08:10 -07:00
BLOCKHASH_CACHE_TIMEOUT_MS ,
2022-03-24 22:21:14 -07:00
BlockResponse ,
BlockSignatures ,
2021-03-14 22:08:10 -07:00
Commitment ,
2022-03-24 22:21:14 -07:00
ConfirmedBlock ,
2022-04-09 18:39:32 -07:00
Context ,
2021-03-14 22:08:10 -07:00
EpochInfo ,
InflationGovernor ,
2022-04-09 18:39:32 -07:00
Logs ,
2022-04-09 19:03:29 -07:00
SignatureResult ,
2021-03-14 22:08:10 -07:00
SlotInfo ,
} from '../src/connection' ;
2022-08-11 02:10:11 -07:00
import { sleep } from '../src/utils/sleep' ;
2021-02-05 18:59:00 -08:00
import {
helpers ,
mockErrorMessage ,
mockErrorResponse ,
2021-03-22 10:22:59 -07:00
mockRpcBatchResponse ,
2021-02-05 18:59:00 -08:00
mockRpcResponse ,
mockServer ,
} from './mocks/rpc-http' ;
2022-05-13 18:42:40 -07:00
import {
stubRpcWebSocket ,
restoreRpcWebSocket ,
mockRpcMessage ,
} from './mocks/rpc-websockets' ;
2022-08-11 02:10:11 -07:00
import {
2022-11-28 22:46:27 -08:00
NonceInformation ,
2022-08-11 02:10:11 -07:00
TransactionInstruction ,
TransactionSignature ,
TransactionExpiredBlockheightExceededError ,
2022-11-28 22:46:27 -08:00
TransactionExpiredNonceInvalidError ,
2022-08-11 02:10:11 -07:00
TransactionExpiredTimeoutError ,
} from '../src/transaction' ;
2021-02-07 08:57:12 -08:00
import type {
SignatureStatus ,
TransactionError ,
KeyedAccountInfo ,
} from '../src/connection' ;
2022-08-25 06:42:54 -07:00
import { VersionedTransaction } from '../src/transaction/versioned' ;
import { MessageV0 } from '../src/message/v0' ;
import { encodeData } from '../src/instruction' ;
2021-02-05 18:59:00 -08:00
use ( chaiAsPromised ) ;
2022-11-28 11:55:56 -08:00
use ( sinonChai ) ;
2018-08-24 11:12:48 -07:00
2022-11-28 22:46:27 -08:00
async function mockNonceAccountResponse (
nonceAccountPubkey : string ,
nonceValue : string ,
nonceAuthority : string ,
slot? : number ,
) {
const mockNonceAccountData = Buffer . alloc ( NONCE_ACCOUNT_LENGTH ) ;
mockNonceAccountData . fill ( 0 ) ;
// Authority starts after 4 version bytes and 4 state bytes.
mockNonceAccountData . set ( bs58 . decode ( nonceAuthority ) , 4 + 4 ) ;
// Nonce hash starts 32 bytes after the authority.
mockNonceAccountData . set ( bs58 . decode ( nonceValue ) , 4 + 4 + 32 ) ;
await mockRpcResponse ( {
method : 'getAccountInfo' ,
params : [ nonceAccountPubkey , { encoding : 'base64' } ] ,
value : {
owner : SystemProgram.programId.toBase58 ( ) ,
lamports : LAMPORTS_PER_SOL ,
data : [ mockNonceAccountData . toString ( 'base64' ) , 'base64' ] ,
executable : false ,
rentEpoch : 20 ,
} ,
slot ,
withContext : true ,
} ) ;
}
2020-05-20 02:13:21 -07:00
const verifySignatureStatus = (
status : SignatureStatus | null ,
err? : TransactionError ,
) : SignatureStatus = > {
if ( status === null ) {
2021-02-05 18:59:00 -08:00
expect ( status ) . not . to . be . null ;
2020-05-20 02:13:21 -07:00
throw new Error ( ) ; // unreachable
}
const expectedErr = err || null ;
2021-02-05 18:59:00 -08:00
expect ( status . err ) . to . eql ( expectedErr ) ;
expect ( status . slot ) . to . be . at . least ( 0 ) ;
2020-05-20 02:13:21 -07:00
if ( expectedErr !== null ) return status ;
const confirmations = status . confirmations ;
if ( typeof confirmations === 'number' ) {
2021-02-05 18:59:00 -08:00
expect ( confirmations ) . to . be . at . least ( 0 ) ;
2020-05-20 02:13:21 -07:00
} else {
2021-02-05 18:59:00 -08:00
expect ( confirmations ) . to . be . null ;
2020-05-20 02:13:21 -07:00
}
return status ;
} ;
2022-03-24 22:21:14 -07:00
describe ( 'Connection' , function ( ) {
2021-02-05 18:59:00 -08:00
let connection : Connection ;
beforeEach ( ( ) = > {
connection = new Connection ( url ) ;
} ) ;
2018-09-20 15:08:52 -07:00
2021-03-14 22:08:10 -07:00
if ( mockServer ) {
const server = mockServer ;
2021-02-05 18:59:00 -08:00
beforeEach ( ( ) = > {
2021-03-14 22:08:10 -07:00
server . start ( MOCK_PORT ) ;
2021-02-05 18:59:00 -08:00
stubRpcWebSocket ( connection ) ;
} ) ;
2020-08-06 08:47:22 -07:00
2021-02-05 18:59:00 -08:00
afterEach ( ( ) = > {
2021-03-14 22:08:10 -07:00
server . stop ( ) ;
2021-02-05 18:59:00 -08:00
restoreRpcWebSocket ( connection ) ;
} ) ;
2020-08-06 08:47:22 -07:00
}
2018-09-20 15:08:52 -07:00
2021-04-26 08:35:07 -07:00
if ( mockServer ) {
it ( 'should pass HTTP headers to RPC' , async ( ) = > {
const headers = {
Authorization : 'Bearer 123' ,
} ;
let connection = new Connection ( url , {
httpHeaders : headers ,
} ) ;
await mockRpcResponse ( {
method : 'getVersion' ,
params : [ ] ,
value : { 'solana-core' : '0.20.4' } ,
withHeaders : headers ,
} ) ;
expect ( await connection . getVersion ( ) ) . to . be . not . null ;
} ) ;
it ( 'should allow middleware to augment request' , async ( ) = > {
let connection = new Connection ( url , {
fetchMiddleware : ( url , options , fetch ) = > {
options . headers = Object . assign ( options . headers , {
Authorization : 'Bearer 123' ,
} ) ;
fetch ( url , options ) ;
} ,
} ) ;
await mockRpcResponse ( {
method : 'getVersion' ,
params : [ ] ,
value : { 'solana-core' : '0.20.4' } ,
withHeaders : {
Authorization : 'Bearer 123' ,
} ,
} ) ;
expect ( await connection . getVersion ( ) ) . to . be . not . null ;
} ) ;
}
2021-11-28 21:43:33 -08:00
it ( 'should attribute middleware fatals to the middleware' , async ( ) = > {
let connection = new Connection ( url , {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fetchMiddleware : ( _url , _options , _fetch ) = > {
throw new Error ( 'This middleware experienced a fatal error' ) ;
} ,
} ) ;
const error = await expect ( connection . getVersion ( ) ) . to . be . rejectedWith (
'This middleware experienced a fatal error' ,
) ;
expect ( error )
. to . be . an . instanceOf ( Error )
. and . to . have . property ( 'stack' )
. that . include ( 'fetchMiddleware' ) ;
} ) ;
it ( 'should not attribute fetch errors to the middleware' , async ( ) = > {
let connection = new Connection ( url , {
fetchMiddleware : ( url , _options , fetch ) = > {
fetch ( url , 'An `Object` was expected here; this is a `TypeError`.' ) ;
} ,
} ) ;
const error = await expect ( connection . getVersion ( ) ) . to . be . rejected ;
expect ( error )
. to . be . an . instanceOf ( Error )
. and . to . have . property ( 'stack' )
. that . does . not . include ( 'fetchMiddleware' ) ;
} ) ;
2021-02-05 18:59:00 -08:00
it ( 'get account info - not found' , async ( ) = > {
2021-05-07 01:59:51 -07:00
const account = Keypair . generate ( ) ;
2020-12-24 10:43:45 -08:00
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
method : 'getAccountInfo' ,
params : [ account . publicKey . toBase58 ( ) , { encoding : 'base64' } ] ,
value : null ,
withContext : true ,
} ) ;
2019-06-28 18:28:06 -07:00
2021-02-05 18:59:00 -08:00
expect ( await connection . getAccountInfo ( account . publicKey ) ) . to . be . null ;
2020-09-07 22:12:47 -07:00
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
method : 'getAccountInfo' ,
params : [ account . publicKey . toBase58 ( ) , { encoding : 'jsonParsed' } ] ,
value : null ,
withContext : true ,
} ) ;
expect ( ( await connection . getParsedAccountInfo ( account . publicKey ) ) . value ) . to
. be . null ;
2020-06-03 04:55:42 -07:00
} ) ;
2019-06-28 18:28:06 -07:00
2021-07-20 09:42:14 -07:00
it ( 'get multiple accounts info' , async ( ) = > {
const account1 = Keypair . generate ( ) ;
const account2 = Keypair . generate ( ) ;
{
await helpers . airdrop ( {
connection ,
address : account1.publicKey ,
amount : LAMPORTS_PER_SOL ,
} ) ;
await helpers . airdrop ( {
connection ,
address : account2.publicKey ,
amount : LAMPORTS_PER_SOL ,
} ) ;
}
const value = [
{
owner : '11111111111111111111111111111111' ,
lamports : LAMPORTS_PER_SOL ,
data : [ '' , 'base64' ] ,
executable : false ,
rentEpoch : 0 ,
2022-10-20 13:37:55 -07:00
space : 0 ,
2021-07-20 09:42:14 -07:00
} ,
{
owner : '11111111111111111111111111111111' ,
lamports : LAMPORTS_PER_SOL ,
data : [ '' , 'base64' ] ,
executable : false ,
rentEpoch : 0 ,
2022-10-20 13:37:55 -07:00
space : 0 ,
2021-07-20 09:42:14 -07:00
} ,
] ;
await mockRpcResponse ( {
method : 'getMultipleAccounts' ,
params : [
[ account1 . publicKey . toBase58 ( ) , account2 . publicKey . toBase58 ( ) ] ,
{ encoding : 'base64' } ,
] ,
value : value ,
withContext : true ,
} ) ;
const res = await connection . getMultipleAccountsInfo (
[ account1 . publicKey , account2 . publicKey ] ,
'confirmed' ,
) ;
const expectedValue = [
{
owner : new PublicKey ( '11111111111111111111111111111111' ) ,
lamports : LAMPORTS_PER_SOL ,
data : Buffer.from ( [ ] ) ,
executable : false ,
rentEpoch : 0 ,
2022-10-20 13:37:55 -07:00
space : 0 ,
2021-07-20 09:42:14 -07:00
} ,
{
owner : new PublicKey ( '11111111111111111111111111111111' ) ,
lamports : LAMPORTS_PER_SOL ,
data : Buffer.from ( [ ] ) ,
executable : false ,
rentEpoch : 0 ,
2022-10-20 13:37:55 -07:00
space : 0 ,
2021-07-20 09:42:14 -07:00
} ,
] ;
expect ( res ) . to . eql ( expectedValue ) ;
} ) ;
2021-02-05 18:59:00 -08:00
it ( 'get program accounts' , async ( ) = > {
2021-05-07 01:59:51 -07:00
const account0 = Keypair . generate ( ) ;
const account1 = Keypair . generate ( ) ;
const programId = Keypair . generate ( ) ;
2021-02-05 18:59:00 -08:00
2020-01-16 12:09:21 -08:00
{
2021-02-05 18:59:00 -08:00
await helpers . airdrop ( {
connection ,
address : account0.publicKey ,
amount : LAMPORTS_PER_SOL ,
} ) ;
2020-03-03 00:05:50 -08:00
2021-02-05 18:59:00 -08:00
const transaction = new Transaction ( ) . add (
SystemProgram . assign ( {
accountPubkey : account0.publicKey ,
programId : programId.publicKey ,
} ) ,
) ;
await helpers . processTransaction ( {
connection ,
transaction ,
signers : [ account0 ] ,
2021-02-17 16:15:09 -08:00
commitment : 'confirmed' ,
2021-02-05 18:59:00 -08:00
} ) ;
}
2019-06-28 18:28:06 -07:00
2020-06-04 03:12:59 -07:00
{
2021-02-05 18:59:00 -08:00
await helpers . airdrop ( {
connection ,
address : account1.publicKey ,
amount : 0.5 * LAMPORTS_PER_SOL ,
} ) ;
2020-06-04 03:12:59 -07:00
2021-02-05 18:59:00 -08:00
const transaction = new Transaction ( ) . add (
SystemProgram . assign ( {
accountPubkey : account1.publicKey ,
programId : programId.publicKey ,
} ) ,
) ;
2020-06-04 03:12:59 -07:00
2021-02-05 18:59:00 -08:00
await helpers . processTransaction ( {
connection ,
transaction ,
signers : [ account1 ] ,
2021-02-17 16:15:09 -08:00
commitment : 'confirmed' ,
2021-02-05 18:59:00 -08:00
} ) ;
}
2020-06-04 03:12:59 -07:00
2021-02-05 18:59:00 -08:00
const feeCalculator = ( await helpers . recentBlockhash ( { connection } ) )
. feeCalculator ;
2019-06-28 18:28:06 -07:00
2021-04-16 10:18:19 -07:00
{
await mockRpcResponse ( {
method : 'getProgramAccounts' ,
params : [
programId . publicKey . toBase58 ( ) ,
{ commitment : 'confirmed' , encoding : 'base64' } ,
] ,
value : [
{
account : {
data : [ '' , 'base64' ] ,
executable : false ,
lamports : LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
owner : programId.publicKey.toBase58 ( ) ,
rentEpoch : 20 ,
} ,
pubkey : account0.publicKey.toBase58 ( ) ,
} ,
{
account : {
data : [ '' , 'base64' ] ,
executable : false ,
lamports :
0.5 * LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
owner : programId.publicKey.toBase58 ( ) ,
rentEpoch : 20 ,
} ,
pubkey : account1.publicKey.toBase58 ( ) ,
} ,
] ,
} ) ;
const programAccounts = await connection . getProgramAccounts (
programId . publicKey ,
{
commitment : 'confirmed' ,
} ,
) ;
expect ( programAccounts ) . to . have . length ( 2 ) ;
programAccounts . forEach ( function ( keyedAccount ) {
if ( keyedAccount . pubkey . equals ( account0 . publicKey ) ) {
expect ( keyedAccount . account . lamports ) . to . eq (
LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
) ;
} else {
expect ( keyedAccount . pubkey ) . to . eql ( account1 . publicKey ) ;
expect ( keyedAccount . account . lamports ) . to . eq (
0.5 * LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
) ;
}
} ) ;
}
2020-01-16 12:09:21 -08:00
{
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
method : 'getProgramAccounts' ,
params : [
programId . publicKey . toBase58 ( ) ,
2021-02-17 16:15:09 -08:00
{ commitment : 'confirmed' , encoding : 'base64' } ,
2021-02-05 18:59:00 -08:00
] ,
value : [
{
account : {
data : [ '' , 'base64' ] ,
executable : false ,
lamports : LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
owner : programId.publicKey.toBase58 ( ) ,
rentEpoch : 20 ,
} ,
pubkey : account0.publicKey.toBase58 ( ) ,
2020-01-16 12:09:21 -08:00
} ,
2021-02-05 18:59:00 -08:00
{
account : {
data : [ '' , 'base64' ] ,
executable : false ,
lamports :
0.5 * LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
owner : programId.publicKey.toBase58 ( ) ,
rentEpoch : 20 ,
} ,
pubkey : account1.publicKey.toBase58 ( ) ,
2020-01-16 12:09:21 -08:00
} ,
2021-02-05 18:59:00 -08:00
] ,
} ) ;
2019-06-28 18:28:06 -07:00
2021-02-05 18:59:00 -08:00
const programAccounts = await connection . getProgramAccounts (
programId . publicKey ,
2021-02-17 16:15:09 -08:00
'confirmed' ,
2019-10-22 16:10:21 -07:00
) ;
2021-02-05 18:59:00 -08:00
expect ( programAccounts ) . to . have . length ( 2 ) ;
programAccounts . forEach ( function ( keyedAccount ) {
if ( keyedAccount . pubkey . equals ( account0 . publicKey ) ) {
expect ( keyedAccount . account . lamports ) . to . eq (
LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
) ;
} else {
expect ( keyedAccount . pubkey ) . to . eql ( account1 . publicKey ) ;
expect ( keyedAccount . account . lamports ) . to . eq (
0.5 * LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
) ;
}
} ) ;
}
2021-04-16 10:18:19 -07:00
{
await mockRpcResponse ( {
method : 'getProgramAccounts' ,
params : [
programId . publicKey . toBase58 ( ) ,
{
commitment : 'confirmed' ,
encoding : 'base64' ,
filters : [
{
dataSize : 0 ,
} ,
] ,
} ,
] ,
value : [
{
account : {
data : [ '' , 'base64' ] ,
executable : false ,
lamports : LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
owner : programId.publicKey.toBase58 ( ) ,
rentEpoch : 20 ,
} ,
pubkey : account0.publicKey.toBase58 ( ) ,
} ,
{
account : {
data : [ '' , 'base64' ] ,
executable : false ,
lamports :
0.5 * LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
owner : programId.publicKey.toBase58 ( ) ,
rentEpoch : 20 ,
} ,
pubkey : account1.publicKey.toBase58 ( ) ,
} ,
] ,
} ) ;
const programAccountsDoMatchFilter = await connection . getProgramAccounts (
programId . publicKey ,
{
commitment : 'confirmed' ,
encoding : 'base64' ,
filters : [ { dataSize : 0 } ] ,
} ,
) ;
expect ( programAccountsDoMatchFilter ) . to . have . length ( 2 ) ;
}
{
await mockRpcResponse ( {
method : 'getProgramAccounts' ,
params : [
programId . publicKey . toBase58 ( ) ,
{
commitment : 'confirmed' ,
encoding : 'base64' ,
filters : [
{
memcmp : {
offset : 0 ,
bytes : 'XzdZ3w' ,
} ,
} ,
] ,
} ,
] ,
value : [ ] ,
} ) ;
2021-05-24 20:53:16 -07:00
const programAccountsDontMatchFilter =
await connection . getProgramAccounts ( programId . publicKey , {
2021-04-16 10:18:19 -07:00
commitment : 'confirmed' ,
filters : [
{
memcmp : {
offset : 0 ,
bytes : 'XzdZ3w' ,
} ,
} ,
] ,
2021-05-24 20:53:16 -07:00
} ) ;
2021-04-16 10:18:19 -07:00
expect ( programAccountsDontMatchFilter ) . to . have . length ( 0 ) ;
}
2021-02-05 18:59:00 -08:00
{
await mockRpcResponse ( {
method : 'getProgramAccounts' ,
params : [
programId . publicKey . toBase58 ( ) ,
2021-02-17 16:15:09 -08:00
{ commitment : 'confirmed' , encoding : 'jsonParsed' } ,
2021-02-05 18:59:00 -08:00
] ,
value : [
{
account : {
data : [ '' , 'base64' ] ,
executable : false ,
lamports : LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
owner : programId.publicKey.toBase58 ( ) ,
rentEpoch : 20 ,
} ,
pubkey : account0.publicKey.toBase58 ( ) ,
} ,
{
account : {
data : [ '' , 'base64' ] ,
executable : false ,
lamports :
0.5 * LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
owner : programId.publicKey.toBase58 ( ) ,
rentEpoch : 20 ,
} ,
pubkey : account1.publicKey.toBase58 ( ) ,
} ,
] ,
} ) ;
const programAccounts = await connection . getParsedProgramAccounts (
programId . publicKey ,
2021-04-16 10:18:19 -07:00
{
commitment : 'confirmed' ,
} ,
2019-10-22 16:10:21 -07:00
) ;
2021-02-05 18:59:00 -08:00
expect ( programAccounts ) . to . have . length ( 2 ) ;
programAccounts . forEach ( function ( element ) {
if ( element . pubkey . equals ( account0 . publicKey ) ) {
expect ( element . account . lamports ) . to . eq (
LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
) ;
} else {
expect ( element . pubkey ) . to . eql ( account1 . publicKey ) ;
expect ( element . account . lamports ) . to . eq (
0.5 * LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
) ;
}
} ) ;
2019-06-28 18:28:06 -07:00
}
2021-04-16 10:18:19 -07:00
{
await mockRpcResponse ( {
method : 'getProgramAccounts' ,
params : [
programId . publicKey . toBase58 ( ) ,
{
commitment : 'confirmed' ,
encoding : 'jsonParsed' ,
filters : [
{
dataSize : 2 ,
} ,
] ,
} ,
] ,
value : [ ] ,
} ) ;
2021-05-24 20:53:16 -07:00
const programAccountsDontMatchFilter =
await connection . getParsedProgramAccounts ( programId . publicKey , {
2021-04-16 10:18:19 -07:00
commitment : 'confirmed' ,
filters : [ { dataSize : 2 } ] ,
2021-05-24 20:53:16 -07:00
} ) ;
2021-04-16 10:18:19 -07:00
expect ( programAccountsDontMatchFilter ) . to . have . length ( 0 ) ;
}
{
await mockRpcResponse ( {
method : 'getProgramAccounts' ,
params : [
programId . publicKey . toBase58 ( ) ,
{
commitment : 'confirmed' ,
encoding : 'jsonParsed' ,
filters : [
{
memcmp : {
offset : 0 ,
bytes : '' ,
} ,
} ,
] ,
} ,
] ,
value : [
{
account : {
data : [ '' , 'base64' ] ,
executable : false ,
lamports : LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
owner : programId.publicKey.toBase58 ( ) ,
rentEpoch : 20 ,
} ,
pubkey : account0.publicKey.toBase58 ( ) ,
} ,
{
account : {
data : [ '' , 'base64' ] ,
executable : false ,
lamports :
0.5 * LAMPORTS_PER_SOL - feeCalculator . lamportsPerSignature ,
owner : programId.publicKey.toBase58 ( ) ,
rentEpoch : 20 ,
} ,
pubkey : account1.publicKey.toBase58 ( ) ,
} ,
] ,
} ) ;
2021-05-24 20:53:16 -07:00
const programAccountsDoMatchFilter =
await connection . getParsedProgramAccounts ( programId . publicKey , {
2021-04-16 10:18:19 -07:00
commitment : 'confirmed' ,
filters : [
{
memcmp : {
offset : 0 ,
bytes : '' ,
} ,
} ,
] ,
2021-05-24 20:53:16 -07:00
} ) ;
2021-04-16 10:18:19 -07:00
expect ( programAccountsDoMatchFilter ) . to . have . length ( 2 ) ;
}
2022-01-21 13:01:48 -08:00
} ) . timeout ( 30 * 1000 ) ;
2020-08-06 08:47:22 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get balance' , async ( ) = > {
2021-05-07 01:59:51 -07:00
const account = Keypair . generate ( ) ;
2018-08-23 10:52:48 -07:00
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
2018-08-24 10:39:51 -07:00
method : 'getBalance' ,
2018-09-30 18:42:45 -07:00
params : [ account . publicKey . toBase58 ( ) ] ,
2021-02-05 18:59:00 -08:00
value : {
2020-01-08 12:59:58 -08:00
context : {
slot : 11 ,
} ,
value : 0 ,
} ,
2021-02-05 18:59:00 -08:00
} ) ;
2018-08-23 10:52:48 -07:00
2021-02-05 18:59:00 -08:00
const balance = await connection . getBalance ( account . publicKey ) ;
expect ( balance ) . to . be . at . least ( 0 ) ;
} ) ;
2019-08-28 07:21:39 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get inflation' , async ( ) = > {
await mockRpcResponse ( {
2020-06-03 08:38:48 -07:00
method : 'getInflationGovernor' ,
2019-08-28 07:21:39 -07:00
params : [ ] ,
2021-02-05 18:59:00 -08:00
value : {
2019-08-28 07:21:39 -07:00
foundation : 0.05 ,
2020-01-15 13:04:26 -08:00
foundationTerm : 7.0 ,
2019-08-28 07:21:39 -07:00
initial : 0.15 ,
taper : 0.15 ,
terminal : 0.015 ,
} ,
2021-02-05 18:59:00 -08:00
} ) ;
2019-08-28 07:21:39 -07:00
2021-02-05 18:59:00 -08:00
const inflation = await connection . getInflationGovernor ( ) ;
2021-03-14 22:08:10 -07:00
const inflationKeys : ( keyof InflationGovernor ) [ ] = [
2021-02-05 18:59:00 -08:00
'initial' ,
'terminal' ,
'taper' ,
'foundation' ,
'foundationTerm' ,
2021-03-14 22:08:10 -07:00
] ;
for ( const key of inflationKeys ) {
2021-02-05 18:59:00 -08:00
expect ( inflation ) . to . have . property ( key ) ;
expect ( inflation [ key ] ) . to . be . greaterThan ( 0 ) ;
}
} ) ;
2019-10-29 09:50:05 -07:00
2021-04-26 11:09:40 -07:00
it ( 'get inflation reward' , async ( ) = > {
if ( mockServer ) {
await mockRpcResponse ( {
method : 'getInflationReward' ,
params : [
[
'7GHnTRB8Rz14qZQhDXf8ox1Kfu7mPcPLpKaBJJirmYj2' ,
'CrinLuHjVGDDcQfrEoCmM4k31Ni9sMoTCEEvNSUSh7Jg' ,
] ,
{
epoch : 0 ,
} ,
] ,
value : [
{
amount : 3646143 ,
effectiveSlot : 432000 ,
epoch : 0 ,
postBalance : 30504783 ,
} ,
null ,
] ,
} ) ;
const inflationReward = await connection . getInflationReward (
[
new PublicKey ( '7GHnTRB8Rz14qZQhDXf8ox1Kfu7mPcPLpKaBJJirmYj2' ) ,
new PublicKey ( 'CrinLuHjVGDDcQfrEoCmM4k31Ni9sMoTCEEvNSUSh7Jg' ) ,
] ,
0 ,
) ;
expect ( inflationReward ) . to . have . lengthOf ( 2 ) ;
}
} ) ;
2021-02-05 18:59:00 -08:00
it ( 'get epoch info' , async ( ) = > {
await mockRpcResponse ( {
2019-10-29 09:50:05 -07:00
method : 'getEpochInfo' ,
2021-02-17 16:15:09 -08:00
params : [ { commitment : 'confirmed' } ] ,
2021-02-05 18:59:00 -08:00
value : {
2019-11-11 10:01:10 -08:00
epoch : 0 ,
2019-10-29 09:50:05 -07:00
slotIndex : 1 ,
slotsInEpoch : 8192 ,
absoluteSlot : 1 ,
2020-07-21 14:43:40 -07:00
blockHeight : 1 ,
2019-10-29 09:50:05 -07:00
} ,
2021-02-05 18:59:00 -08:00
} ) ;
2019-10-29 09:50:05 -07:00
2021-02-17 16:15:09 -08:00
const epochInfo = await connection . getEpochInfo ( 'confirmed' ) ;
2021-03-14 22:08:10 -07:00
const epochInfoKeys : ( keyof EpochInfo ) [ ] = [
2021-02-05 18:59:00 -08:00
'epoch' ,
'slotIndex' ,
'slotsInEpoch' ,
'absoluteSlot' ,
'blockHeight' ,
2021-03-14 22:08:10 -07:00
] ;
for ( const key of epochInfoKeys ) {
2021-02-05 18:59:00 -08:00
expect ( epochInfo ) . to . have . property ( key ) ;
expect ( epochInfo [ key ] ) . to . be . at . least ( 0 ) ;
}
} ) ;
2019-10-23 06:48:24 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get epoch schedule' , async ( ) = > {
await mockRpcResponse ( {
2019-10-23 06:48:24 -07:00
method : 'getEpochSchedule' ,
params : [ ] ,
2021-02-05 18:59:00 -08:00
value : {
2020-01-15 13:04:26 -08:00
firstNormalEpoch : 8 ,
firstNormalSlot : 8160 ,
leaderScheduleSlotOffset : 8192 ,
slotsPerEpoch : 8192 ,
2019-10-23 06:48:24 -07:00
warmup : true ,
} ,
2021-02-05 18:59:00 -08:00
} ) ;
2019-10-23 06:48:24 -07:00
2021-02-05 18:59:00 -08:00
const epochSchedule = await connection . getEpochSchedule ( ) ;
2021-03-14 22:08:10 -07:00
const epochScheduleKeys : ( keyof EpochSchedule ) [ ] = [
2021-02-05 18:59:00 -08:00
'firstNormalEpoch' ,
'firstNormalSlot' ,
'leaderScheduleSlotOffset' ,
'slotsPerEpoch' ,
2021-03-14 22:08:10 -07:00
] ;
for ( const key of epochScheduleKeys ) {
2021-02-05 18:59:00 -08:00
expect ( epochSchedule ) . to . have . property ( 'warmup' ) ;
expect ( epochSchedule ) . to . have . property ( key ) ;
if ( epochSchedule . warmup ) {
expect ( epochSchedule [ key ] ) . to . be . greaterThan ( 0 ) ;
}
}
} ) ;
2020-07-17 08:16:44 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get leader schedule' , async ( ) = > {
await mockRpcResponse ( {
2020-07-17 08:16:44 -07:00
method : 'getLeaderSchedule' ,
params : [ ] ,
2021-02-05 18:59:00 -08:00
value : {
2020-07-17 08:16:44 -07:00
'123vij84ecQEKUvQ7gYMKxKwKF6PbYSzCzzURYA4xULY' : [ 0 , 1 , 2 , 3 ] ,
'8PTjAikKoAybKXcEPnDSoy8wSNNikUBJ1iKawJKQwXnB' : [ 4 , 5 , 6 , 7 ] ,
} ,
2021-02-05 18:59:00 -08:00
} ) ;
2020-07-17 08:16:44 -07:00
2021-02-05 18:59:00 -08:00
const leaderSchedule = await connection . getLeaderSchedule ( ) ;
expect ( Object . keys ( leaderSchedule ) . length ) . to . be . at . least ( 1 ) ;
for ( const key in leaderSchedule ) {
const slots = leaderSchedule [ key ] ;
expect ( Array . isArray ( slots ) ) . to . be . true ;
expect ( slots . length ) . to . be . at . least ( 4 ) ;
}
} ) ;
2019-08-02 16:06:54 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get slot' , async ( ) = > {
await mockRpcResponse ( {
2019-08-02 16:06:54 -07:00
method : 'getSlot' ,
2021-02-05 18:59:00 -08:00
params : [ ] ,
value : 123 ,
} ) ;
2019-08-02 16:06:54 -07:00
2021-02-05 18:59:00 -08:00
const slot = await connection . getSlot ( ) ;
2021-03-14 22:08:10 -07:00
if ( mockServer ) {
2021-02-05 18:59:00 -08:00
expect ( slot ) . to . eq ( 123 ) ;
} else {
// No idea what the correct slot value should be on a live cluster, so
// just check the type
expect ( typeof slot ) . to . eq ( 'number' ) ;
}
} ) ;
2019-04-23 09:53:26 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get slot leader' , async ( ) = > {
await mockRpcResponse ( {
2019-04-23 09:53:26 -07:00
method : 'getSlotLeader' ,
2021-02-05 18:59:00 -08:00
params : [ ] ,
value : '11111111111111111111111111111111' ,
} ) ;
2019-04-23 09:53:26 -07:00
2021-02-05 18:59:00 -08:00
const slotLeader = await connection . getSlotLeader ( ) ;
2021-03-14 22:08:10 -07:00
if ( mockServer ) {
2021-02-05 18:59:00 -08:00
expect ( slotLeader ) . to . eq ( '11111111111111111111111111111111' ) ;
} else {
// No idea what the correct slotLeader value should be on a live cluster, so
// just check the type
expect ( typeof slotLeader ) . to . eq ( 'string' ) ;
}
} ) ;
2019-04-23 09:53:26 -07:00
2021-05-01 20:54:27 -07:00
it ( 'get slot leaders' , async ( ) = > {
await mockRpcResponse ( {
method : 'getSlotLeaders' ,
params : [ 0 , 1 ] ,
value : [ '11111111111111111111111111111111' ] ,
} ) ;
const slotLeaders = await connection . getSlotLeaders ( 0 , 1 ) ;
expect ( slotLeaders ) . to . have . length ( 1 ) ;
expect ( slotLeaders [ 0 ] ) . to . be . instanceOf ( PublicKey ) ;
} ) ;
2021-02-05 18:59:00 -08:00
it ( 'get cluster nodes' , async ( ) = > {
await mockRpcResponse ( {
2019-04-23 09:53:26 -07:00
method : 'getClusterNodes' ,
2021-02-05 18:59:00 -08:00
params : [ ] ,
value : [
2019-04-23 09:53:26 -07:00
{
2019-06-12 10:26:55 -07:00
pubkey : '11111111111111111111111111111111' ,
2019-04-23 09:53:26 -07:00
gossip : '127.0.0.0:1234' ,
tpu : '127.0.0.0:1235' ,
rpc : null ,
2020-05-13 08:14:03 -07:00
version : '1.1.10' ,
2019-04-23 09:53:26 -07:00
} ,
] ,
2021-02-05 18:59:00 -08:00
} ) ;
2019-06-12 10:26:55 -07:00
2021-02-05 18:59:00 -08:00
const clusterNodes = await connection . getClusterNodes ( ) ;
2021-03-14 22:08:10 -07:00
if ( mockServer ) {
2021-02-05 18:59:00 -08:00
expect ( clusterNodes ) . to . have . length ( 1 ) ;
expect ( clusterNodes [ 0 ] . pubkey ) . to . eq ( '11111111111111111111111111111111' ) ;
expect ( typeof clusterNodes [ 0 ] . gossip ) . to . eq ( 'string' ) ;
expect ( typeof clusterNodes [ 0 ] . tpu ) . to . eq ( 'string' ) ;
expect ( clusterNodes [ 0 ] . rpc ) . to . be . null ;
} else {
// There should be at least one node (the node that we're talking to)
expect ( clusterNodes . length ) . to . be . greaterThan ( 0 ) ;
}
} ) ;
2019-06-12 10:26:55 -07:00
2021-02-05 18:59:00 -08:00
if ( process . env . TEST_LIVE ) {
it ( 'get vote accounts' , async ( ) = > {
const voteAccounts = await connection . getVoteAccounts ( ) ;
expect (
voteAccounts . current . concat ( voteAccounts . delinquent ) . length ,
) . to . be . greaterThan ( 0 ) ;
} ) ;
}
2018-08-23 10:52:48 -07:00
2022-05-13 18:42:40 -07:00
if ( process . env . TEST_LIVE ) {
describe ( 'transaction confirmation (live)' , ( ) = > {
let connection : Connection ;
beforeEach ( ( ) = > {
connection = new Connection ( url , 'confirmed' ) ;
} ) ;
2018-08-24 10:39:51 -07:00
2022-05-13 18:42:40 -07:00
describe ( 'blockheight based transaction confirmation' , ( ) = > {
let latestBlockhash : { blockhash : string ; lastValidBlockHeight : number } ;
let signature : string ;
beforeEach ( async function ( ) {
this . timeout ( 60 * 1000 ) ;
const keypair = Keypair . generate ( ) ;
const [
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_ ,
blockhash ,
] = await Promise . all ( [
connection . confirmTransaction (
await connection . requestAirdrop (
keypair . publicKey ,
LAMPORTS_PER_SOL ,
) ,
) ,
helpers . latestBlockhash ( { connection } ) ,
] ) ;
latestBlockhash = blockhash ;
const ix = new TransactionInstruction ( {
keys : [
{
pubkey : keypair.publicKey ,
isSigner : true ,
isWritable : true ,
} ,
] ,
programId : new PublicKey (
'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr' ,
) ,
data : Buffer.from ( 'Hello world' , 'utf8' ) ,
} ) ;
2018-09-26 19:16:17 -07:00
2022-05-13 18:42:40 -07:00
const transaction = new Transaction ( {
. . . latestBlockhash ,
} ) ;
transaction . add ( ix ) ;
transaction . sign ( keypair ) ;
signature = await connection . sendTransaction ( transaction , [ keypair ] ) ;
} ) ;
it ( 'confirms transactions using the last valid blockheight strategy' , async ( ) = > {
let result = await connection . confirmTransaction (
{
signature ,
. . . latestBlockhash ,
} ,
'processed' ,
) ;
expect ( result . value ) . to . have . property ( 'err' , null ) ;
} ) . timeout ( 60 * 1000 ) ;
it ( 'throws when confirming using a blockhash whose last valid blockheight has passed' , async ( ) = > {
const confirmationPromise = connection . confirmTransaction ( {
signature ,
. . . latestBlockhash ,
lastValidBlockHeight : ( await connection . getBlockHeight ( ) ) - 1 , // Simulate the blockheight having passed.
} ) ;
expect ( confirmationPromise ) . to . eventually . be . rejectedWith (
TransactionExpiredBlockheightExceededError ,
) ;
} ) . timeout ( 60 * 1000 ) ;
} ) ;
2022-11-28 22:46:27 -08:00
describe ( 'nonce-based transaction confirmation' , ( ) = > {
let keypair : Keypair ;
let minContextSlot : number ;
let nonceInfo : NonceInformation ;
let nonceKeypair : Keypair ;
let transaction : Transaction ;
beforeEach ( async function ( ) {
this . timeout ( 60 * 1000 ) ;
keypair = Keypair . generate ( ) ;
nonceKeypair = Keypair . generate ( ) ;
const [
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_ ,
blockhash ,
minimumNonceAccountRentLamports ,
] = await Promise . all ( [
connection . confirmTransaction (
await connection . requestAirdrop (
keypair . publicKey ,
LAMPORTS_PER_SOL ,
) ,
) ,
helpers . latestBlockhash ( { connection } ) ,
connection . getMinimumBalanceForRentExemption ( NONCE_ACCOUNT_LENGTH ) ,
] ) ;
const createNonceAccountTransaction =
SystemProgram . createNonceAccount ( {
authorizedPubkey : keypair.publicKey ,
fromPubkey : keypair.publicKey ,
lamports : minimumNonceAccountRentLamports ,
noncePubkey : nonceKeypair.publicKey ,
} ) ;
createNonceAccountTransaction . recentBlockhash = blockhash . blockhash ;
createNonceAccountTransaction . feePayer = keypair . publicKey ;
const createNonceAccountTransactionSignature =
await connection . sendTransaction ( createNonceAccountTransaction , [
keypair ,
nonceKeypair ,
] ) ;
const { context } = await connection . confirmTransaction ( {
. . . blockhash ,
signature : createNonceAccountTransactionSignature ,
} ) ;
minContextSlot = context . slot ;
const nonceAccount = await connection . getNonce (
nonceKeypair . publicKey ,
{ minContextSlot } ,
) ;
nonceInfo = {
nonce : nonceAccount ! . nonce ,
nonceInstruction : SystemProgram.nonceAdvance ( {
authorizedPubkey : keypair.publicKey ,
noncePubkey : nonceKeypair.publicKey ,
} ) ,
} ;
invariant (
nonceAccount ,
'Expected a nonce account to have been created in the test setup' ,
) ;
const ix = new TransactionInstruction ( {
keys : [
{
pubkey : keypair.publicKey ,
isSigner : true ,
isWritable : true ,
} ,
] ,
programId : new PublicKey (
'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr' ,
) ,
data : Buffer.from ( 'Hello world' , 'utf8' ) ,
} ) ;
transaction = new Transaction ( { minContextSlot , nonceInfo } ) ;
transaction . add ( ix ) ;
transaction . sign ( keypair ) ;
} ) ;
it ( 'confirms transactions using the durable nonce strategy' , async ( ) = > {
const signature = await connection . sendTransaction ( transaction , [
keypair ,
] ) ;
const result = await connection . confirmTransaction (
{
minContextSlot ,
nonceAccountPubkey : nonceKeypair.publicKey ,
nonceValue : nonceInfo.nonce ,
signature ,
} ,
'processed' ,
) ;
expect ( result . value ) . to . have . property ( 'err' , null ) ;
} ) . timeout ( 60 * 1000 ) ;
it ( 'throws when confirming using a nonce that is no longer valid' , async ( ) = > {
// Advance the nonce.
const blockhash = await connection . getLatestBlockhash ( ) ;
await sendAndConfirmTransaction (
connection ,
new Transaction ( { feePayer : keypair.publicKey , . . . blockhash } ) . add (
nonceInfo . nonceInstruction ,
) ,
[ keypair ] ,
) ;
const [ currentSlot , signature ] = await Promise . all ( [
connection . getSlot ( ) ,
connection . sendTransaction ( transaction , [ keypair ] , {
skipPreflight : true ,
} ) ,
] ) ;
const confirmationPromise = connection . confirmTransaction ( {
minContextSlot : currentSlot ,
nonceAccountPubkey : nonceKeypair.publicKey ,
nonceValue : nonceInfo.nonce , // The old nonce.
signature ,
} ) ;
await expect ( confirmationPromise ) . to . eventually . be . rejectedWith (
TransactionExpiredNonceInvalidError ,
) ;
} ) . timeout ( 60 * 1000 ) ;
} ) ;
2021-02-05 18:59:00 -08:00
} ) ;
2022-05-13 18:42:40 -07:00
}
if ( ! process . env . TEST_LIVE ) {
describe ( 'transaction confirmation (mock)' , ( ) = > {
let clock : SinonFakeTimers ;
beforeEach ( ( ) = > {
clock = useFakeTimers ( ) ;
} ) ;
afterEach ( ( ) = > {
clock . restore ( ) ;
} ) ;
2022-11-28 22:46:27 -08:00
describe ( 'timeout strategy (deprecated)' , ( ) = > {
it ( 'throws a `TransactionExpiredTimeoutError` when the timer elapses without a signature confirmation' , async ( ) = > {
const mockSignature =
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ;
2022-05-13 18:42:40 -07:00
2022-11-28 22:46:27 -08:00
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : new Promise ( ( ) = > { } ) ,
} ) ;
const timeoutPromise = connection . confirmTransaction ( mockSignature ) ;
2022-05-13 18:42:40 -07:00
2022-11-28 22:46:27 -08:00
// Advance the clock past all waiting timers, notably the expiry timer.
clock . runAllAsync ( ) ;
2022-05-13 18:42:40 -07:00
2022-11-28 22:46:27 -08:00
await expect ( timeoutPromise ) . to . be . rejectedWith (
TransactionExpiredTimeoutError ,
) ;
} ) ;
2022-05-13 18:42:40 -07:00
} ) ;
2022-11-28 22:46:27 -08:00
describe ( 'block height strategy' , ( ) = > {
it ( 'throws a `TransactionExpiredBlockheightExceededError` when the block height advances past the last valid one for this transaction without a signature confirmation' , async ( ) = > {
const mockSignature =
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG' ;
2022-05-13 18:42:40 -07:00
2022-11-28 22:46:27 -08:00
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : new Promise ( ( ) = > { } ) , // Never resolve this = never get a response.
} ) ;
2022-05-13 18:42:40 -07:00
2022-11-28 22:46:27 -08:00
const lastValidBlockHeight = 3 ;
2022-05-13 18:42:40 -07:00
2022-11-28 22:46:27 -08:00
// Start the block height at `lastValidBlockHeight - 1`.
await mockRpcResponse ( {
method : 'getBlockHeight' ,
params : [ ] ,
value : lastValidBlockHeight - 1 ,
} ) ;
2018-08-23 10:52:48 -07:00
2022-11-28 22:46:27 -08:00
const confirmationPromise = connection . confirmTransaction ( {
signature : mockSignature ,
blockhash : 'sampleBlockhash' ,
lastValidBlockHeight ,
} ) ;
clock . runAllAsync ( ) ;
// Advance the block height to the `lastValidBlockHeight`.
await mockRpcResponse ( {
method : 'getBlockHeight' ,
params : [ ] ,
value : lastValidBlockHeight ,
} ) ;
clock . runAllAsync ( ) ;
// Advance the block height to `lastValidBlockHeight + 1`,
// past the last valid blockheight for this transaction.
await mockRpcResponse ( {
method : 'getBlockHeight' ,
params : [ ] ,
value : lastValidBlockHeight + 1 ,
} ) ;
clock . runAllAsync ( ) ;
await expect ( confirmationPromise ) . to . be . rejectedWith (
TransactionExpiredBlockheightExceededError ,
) ;
2022-05-13 18:42:40 -07:00
} ) ;
2022-11-28 22:46:27 -08:00
it ( 'when the `getBlockHeight` method throws an error it does not timeout but rather keeps waiting for a confirmation' , async ( ) = > {
const mockSignature =
'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC' ;
let resolveResultPromise : ( result : SignatureResult ) = > void ;
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : new Promise < SignatureResult > ( resolve = > {
resolveResultPromise = resolve ;
} ) ,
} ) ;
// Simulate a failure to fetch the block height.
let rejectBlockheightPromise : ( ) = > void ;
await mockRpcResponse ( {
method : 'getBlockHeight' ,
params : [ ] ,
value : ( ( ) = > {
const p = new Promise ( ( _ , reject ) = > {
rejectBlockheightPromise = reject ;
} ) ;
p . catch ( ( ) = > { } ) ;
return p ;
} ) ( ) ,
} ) ;
const confirmationPromise = connection . confirmTransaction ( {
signature : mockSignature ,
blockhash : 'sampleBlockhash' ,
lastValidBlockHeight : 3 ,
} ) ;
rejectBlockheightPromise ( ) ;
clock . runToLastAsync ( ) ;
resolveResultPromise ( { err : null } ) ;
clock . runToLastAsync ( ) ;
expect ( confirmationPromise ) . not . to . eventually . be . rejected ;
2022-05-13 18:42:40 -07:00
} ) ;
2022-11-28 22:46:27 -08:00
it ( 'confirms the transaction if the signature confirmation is received before the block height is exceeded' , async ( ) = > {
const mockSignature =
'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC' ;
let resolveResultPromise : ( result : SignatureResult ) = > void ;
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : new Promise < SignatureResult > ( resolve = > {
resolveResultPromise = resolve ;
} ) ,
} ) ;
const lastValidBlockHeight = 3 ;
// Advance the block height to the `lastValidBlockHeight`.
await mockRpcResponse ( {
method : 'getBlockHeight' ,
params : [ ] ,
value : lastValidBlockHeight ,
} ) ;
const confirmationPromise = connection . confirmTransaction ( {
signature : mockSignature ,
blockhash : 'sampleBlockhash' ,
lastValidBlockHeight ,
} ) ;
clock . runAllAsync ( ) ;
// Return a signature result in the nick of time.
resolveResultPromise ( { err : null } ) ;
await expect ( confirmationPromise ) . to . eventually . deep . equal ( {
context : { slot : 11 } ,
value : { err : null } ,
} ) ;
2022-05-13 18:42:40 -07:00
} ) ;
} ) ;
2022-11-28 22:46:27 -08:00
describe ( 'nonce strategy' , ( ) = > {
it ( 'confirms the transaction if the signature confirmation is received before the nonce is advanced' , async ( ) = > {
const mockSignature =
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG' ;
let resolveResultPromise : ( result : SignatureResult ) = > void ;
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : new Promise < SignatureResult > ( resolve = > {
resolveResultPromise = resolve ;
} ) ,
} ) ;
const nonceAccountPubkey = new PublicKey ( 1 ) ;
const nonceValue = new PublicKey ( 2 ) . toBase58 ( ) ;
const authority = new PublicKey ( 3 ) ;
// Start with the nonce account matching the nonce used to sign the transaction.
await mockNonceAccountResponse (
nonceAccountPubkey . toBase58 ( ) ,
nonceValue ,
authority . toBase58 ( ) ,
) ;
const confirmationPromise = connection . confirmTransaction ( {
minContextSlot : 0 ,
nonceAccountPubkey ,
nonceValue ,
signature : mockSignature ,
} ) ;
clock . runAllAsync ( ) ;
// Respond, a second time, with the same nonce hash.
await mockNonceAccountResponse (
nonceAccountPubkey . toBase58 ( ) ,
nonceValue ,
authority . toBase58 ( ) ,
) ;
clock . runAllAsync ( ) ;
// Return a signature result in the nick of time.
resolveResultPromise ( { err : null } ) ;
await expect ( confirmationPromise ) . to . eventually . deep . equal ( {
context : { slot : 11 } ,
value : { err : null } ,
} ) ;
2022-05-13 18:42:40 -07:00
} ) ;
2022-11-28 22:46:27 -08:00
it ( 'succeeds if double-checking the signature after the nonce-advances demonstrates that the transaction is confirmed' , async ( ) = > {
const mockSignature =
'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC' ;
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : new Promise ( ( ) = > { } ) , // Never resolve this = never get a response.
} ) ;
const nonceAccountPubkey = new PublicKey ( 1 ) ;
const nonceValue = new PublicKey ( 2 ) . toBase58 ( ) ;
const authority = new PublicKey ( 3 ) ;
const confirmationPromise = connection . confirmTransaction ( {
minContextSlot : 0 ,
nonceAccountPubkey ,
nonceValue ,
signature : mockSignature ,
} ) ;
// Simulate the nonce advancing but the double-check of the signature status succeeding.
await mockNonceAccountResponse (
nonceAccountPubkey . toBase58 ( ) ,
new PublicKey ( 4 ) . toBase58 ( ) , // A new nonce.
authority . toBase58 ( ) ,
) ;
await mockRpcResponse ( {
method : 'getSignatureStatuses' ,
params : [ [ mockSignature ] ] ,
value : [
{
err : null ,
confirmations : 0 ,
confirmationStatus : 'finalized' , // Demonstrate that the transaction is, in fact, confirmed.
slot : 0 ,
} ,
] ,
withContext : true ,
} ) ;
clock . runToLastAsync ( ) ;
await expect ( confirmationPromise ) . to . eventually . deep . equal ( {
context : { slot : 11 } ,
value : { err : null } ,
} ) ;
2022-05-13 18:42:40 -07:00
} ) ;
2022-11-28 22:46:27 -08:00
it ( 'keeps double-checking the signature after the nonce-advances until a signature from the minimum allowable slot is obtained' , async ( ) = > {
const mockSignature =
'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC' ;
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : new Promise ( ( ) = > { } ) , // Never resolve this = never get a response.
} ) ;
const nonceAccountPubkey = new PublicKey ( 1 ) ;
const nonceValue = new PublicKey ( 2 ) . toBase58 ( ) ;
const authority = new PublicKey ( 3 ) ;
const confirmationPromise = connection . confirmTransaction ( {
minContextSlot : 11 ,
nonceAccountPubkey ,
nonceValue ,
signature : mockSignature ,
} ) ;
// Simulate the nonce advancing but the double-check of the signature status succeeding.
await mockNonceAccountResponse (
nonceAccountPubkey . toBase58 ( ) ,
new PublicKey ( 4 ) . toBase58 ( ) , // A new nonce.
authority . toBase58 ( ) ,
) ;
// Simulate getting a response from an old slot.
await mockRpcResponse ( {
method : 'getSignatureStatuses' ,
params : [ [ mockSignature ] ] ,
value : [
{
err : null ,
confirmations : 0 ,
confirmationStatus : 'processed' , // A non-finalized value from an old slot.
slot : 10 ,
} ,
] ,
slot : 10 ,
withContext : true ,
} ) ;
// Then obtain a response from the minimum allowable slot.
await mockRpcResponse ( {
method : 'getSignatureStatuses' ,
params : [ [ mockSignature ] ] ,
value : [
{
err : null ,
confirmations : 32 ,
confirmationStatus : 'finalized' , // Demonstrate that the transaction is, in fact, confirmed.
slot : 11 ,
} ,
] ,
slot : 11 ,
withContext : true ,
} ) ;
clock . runAllAsync ( ) ;
await expect ( confirmationPromise ) . to . eventually . deep . equal ( {
context : { slot : 11 } ,
value : { err : null } ,
} ) ;
2022-05-13 18:42:40 -07:00
} ) ;
2022-11-28 22:46:27 -08:00
it ( 'throws a `TransactionExpiredNonceInvalidError` when the nonce is no longer the one with which this transaction was signed' , async ( ) = > {
const mockSignature =
'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC' ;
2022-05-13 18:42:40 -07:00
2022-11-28 22:46:27 -08:00
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : new Promise ( ( ) = > { } ) , // Never resolve this = never get a response.
} ) ;
const nonceAccountPubkey = new PublicKey ( 1 ) ;
const nonceValue = new PublicKey ( 2 ) . toBase58 ( ) ;
const authority = new PublicKey ( 3 ) ;
const confirmationPromise = connection . confirmTransaction ( {
minContextSlot : 0 ,
nonceAccountPubkey ,
nonceValue ,
signature : mockSignature ,
} ) ;
// Simulate the nonce advancing but the double-check of the signature status succeeding.
await mockNonceAccountResponse (
nonceAccountPubkey . toBase58 ( ) ,
new PublicKey ( 4 ) . toBase58 ( ) , // A new nonce.
authority . toBase58 ( ) ,
) ;
await mockRpcResponse ( {
method : 'getSignatureStatuses' ,
params : [ [ mockSignature ] ] ,
value : [
{
err : null ,
confirmations : 0 ,
confirmationStatus : 'processed' , // Demonstrate that the transaction is, in fact, not confirmed.
slot : 0 ,
} ,
] ,
withContext : true ,
} ) ;
clock . runToLastAsync ( ) ;
2022-05-13 18:42:40 -07:00
2022-11-28 22:46:27 -08:00
await expect ( confirmationPromise ) . to . eventually . be . rejectedWith (
TransactionExpiredNonceInvalidError ,
) ;
2022-05-13 18:42:40 -07:00
} ) ;
2022-11-28 22:46:27 -08:00
it ( 'when fetching the nonce account throws an error it does not timeout but rather keeps waiting for a confirmation' , async ( ) = > {
const mockSignature =
'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC' ;
let resolveResultPromise : ( result : SignatureResult ) = > void ;
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : new Promise < SignatureResult > ( resolve = > {
resolveResultPromise = resolve ;
} ) ,
} ) ;
// Simulate a failure to fetch the nonce account.
let rejectNonceAccountFetchPromise : ( ) = > void ;
await mockRpcResponse ( {
method : 'getAccountInfo' ,
params : [ ] ,
value : ( ( ) = > {
const p = new Promise ( ( _ , reject ) = > {
rejectNonceAccountFetchPromise = reject ;
} ) ;
p . catch ( ( ) = > { } ) ;
return p ;
} ) ( ) ,
} ) ;
2022-05-13 18:42:40 -07:00
2022-11-28 22:46:27 -08:00
const nonceAccountPubkey = new PublicKey ( 1 ) ;
const nonceValue = new PublicKey ( 2 ) . toBase58 ( ) ;
const confirmationPromise = connection . confirmTransaction ( {
minContextSlot : 0 ,
nonceAccountPubkey ,
nonceValue ,
signature : mockSignature ,
} ) ;
rejectNonceAccountFetchPromise ( ) ;
clock . runToLastAsync ( ) ;
resolveResultPromise ( { err : null } ) ;
clock . runToLastAsync ( ) ;
await expect ( confirmationPromise ) . to . eventually . deep . equal ( {
context : { slot : 11 } ,
value : { err : null } ,
} ) ;
2022-05-13 18:42:40 -07:00
} ) ;
2022-11-28 22:46:27 -08:00
it ( 'throws `TransactionExpiredNonceInvalidError` when the nonce account does not exist' , async ( ) = > {
const mockSignature =
'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC' ;
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : new Promise ( ( ) = > { } ) , // Never resolve this = never get a response.
} ) ;
const nonceAccountPubkey = new PublicKey ( 1 ) ;
const nonceValue = new PublicKey ( 2 ) . toBase58 ( ) ;
const confirmationPromise = connection . confirmTransaction ( {
minContextSlot : 0 ,
nonceAccountPubkey ,
nonceValue ,
signature : mockSignature ,
} ) ;
// Simulate a non-existent nonce account.
await mockRpcResponse ( {
method : 'getAccountInfo' ,
params : [ ] ,
value : null ,
withContext : true ,
} ) ;
clock . runToLastAsync ( ) ;
await mockRpcResponse ( {
method : 'getSignatureStatuses' ,
params : [ [ mockSignature ] ] ,
value : [
{
err : null ,
confirmations : 0 ,
confirmationStatus : 'processed' , // Demonstrate that the transaction is, in fact, not confirmed.
slot : 0 ,
} ,
] ,
withContext : true ,
} ) ;
clock . runToLastAsync ( ) ;
await expect ( confirmationPromise ) . to . eventually . be . rejectedWith (
TransactionExpiredNonceInvalidError ,
) ;
2022-05-13 18:42:40 -07:00
} ) ;
2022-11-28 22:46:27 -08:00
it ( 'when the nonce account data fails to deserialize' , async ( ) = > {
const mockSignature =
'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC' ;
let resolveResultPromise : ( result : SignatureResult ) = > void ;
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : new Promise < SignatureResult > ( resolve = > {
resolveResultPromise = resolve ;
} ) ,
} ) ;
const nonceAccountPubkey = new PublicKey ( 1 ) ;
const nonceValue = new PublicKey ( 2 ) . toBase58 ( ) ;
// Simulate a failure to deserialize the nonce.
await mockRpcResponse ( {
method : 'getAccountInfo' ,
params : [ nonceAccountPubkey . toBase58 ( ) , { encoding : 'base64' } ] ,
value : {
owner : SystemProgram.programId.toBase58 ( ) ,
lamports : LAMPORTS_PER_SOL ,
data : [ 'JUNK_DATA' , 'base64' ] ,
executable : false ,
rentEpoch : 20 ,
} ,
withContext : true ,
} ) ;
2022-05-13 18:42:40 -07:00
2022-11-28 22:46:27 -08:00
const confirmationPromise = connection . confirmTransaction ( {
minContextSlot : 0 ,
nonceAccountPubkey ,
nonceValue ,
signature : mockSignature ,
} ) ;
clock . runToLastAsync ( ) ;
resolveResultPromise ( { err : null } ) ;
clock . runToLastAsync ( ) ;
await expect ( confirmationPromise ) . to . eventually . deep . equal ( {
context : { slot : 11 } ,
value : { err : null } ,
} ) ;
2022-05-13 18:42:40 -07:00
} ) ;
} ) ;
2022-11-28 11:55:56 -08:00
it ( 'confirm transaction - does not check the signature status before the signature subscription comes alive' , async ( ) = > {
const mockSignature =
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ;
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : { err : null } ,
subscriptionEstablishmentPromise : new Promise ( ( ) = > { } ) , // Never resolve.
} ) ;
const getSignatureStatusesExpectation = mock ( connection )
. expects ( 'getSignatureStatuses' )
. never ( ) ;
connection . confirmTransaction ( mockSignature ) ;
getSignatureStatusesExpectation . verify ( ) ;
} ) ;
it ( 'confirm transaction - checks the signature status once the signature subscription comes alive' , async ( ) = > {
const mockSignature =
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ;
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : { err : null } ,
} ) ;
const getSignatureStatusesExpectation = mock ( connection )
. expects ( 'getSignatureStatuses' )
. once ( ) ;
const confirmationPromise =
connection . confirmTransaction ( mockSignature ) ;
clock . runAllAsync ( ) ;
await expect ( confirmationPromise ) . to . eventually . deep . equal ( {
context : { slot : 11 } ,
value : { err : null } ,
} ) ;
getSignatureStatusesExpectation . verify ( ) ;
} ) ;
// FIXME: This test does not work.
// it('confirm transaction - confirms transaction when signature status check yields confirmation before signature subscription does', async () => {
// const mockSignature =
// 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt';
// // Keep the subscription from ever returning data.
// await mockRpcMessage({
// method: 'signatureSubscribe',
// params: [mockSignature, {commitment: 'finalized'}],
// result: new Promise(() => {}), // Never resolve.
// });
// clock.runAllAsync();
// const confirmationPromise =
// connection.confirmTransaction(mockSignature);
// clock.runAllAsync();
// // Return a signature status through the RPC API.
// await mockRpcResponse({
// method: 'getSignatureStatuses',
// params: [[mockSignature]],
// value: [
// {
// slot: 0,
// confirmations: 11,
// status: {Ok: null},
// err: null,
// },
// ],
// });
// clock.runAllAsync();
// await expect(confirmationPromise).to.eventually.deep.equal({
// context: {slot: 11},
// value: {err: null},
// });
// });
2022-11-28 18:50:16 -08:00
it ( 'confirm transaction - does not confirm the transaction when signature status check yields confirmation for a lower commitment before signature subscription confirms the transaction' , async ( ) = > {
const mockSignature =
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ;
// Keep the subscription from ever returning data.
await mockRpcMessage ( {
method : 'signatureSubscribe' ,
params : [ mockSignature , { commitment : 'finalized' } ] ,
result : new Promise ( ( ) = > { } ) , // Never resolve.
} ) ;
clock . runAllAsync ( ) ;
const confirmationPromise =
connection . confirmTransaction ( mockSignature ) ;
clock . runAllAsync ( ) ;
// Return a signature status with a lower finality through the RPC API.
await mockRpcResponse ( {
method : 'getSignatureStatuses' ,
params : [ [ mockSignature ] ] ,
value : [
{
slot : 0 ,
confirmations : null ,
confirmationStatus : 'processed' , // Lower than we expect
err : null ,
} ,
] ,
} ) ;
clock . runAllAsync ( ) ;
await expect ( confirmationPromise ) . to . be . rejectedWith (
TransactionExpiredTimeoutError ,
) ;
} ) ;
2022-05-13 18:42:40 -07:00
} ) ;
}
describe ( 'transaction confirmation' , ( ) = > {
it ( 'confirm transaction - error' , async ( ) = > {
const badTransactionSignature = 'bad transaction signature' ;
await expect (
2022-05-14 21:54:12 -07:00
connection . confirmTransaction ( {
blockhash : 'sampleBlockhash' ,
lastValidBlockHeight : 9999 ,
signature : badTransactionSignature ,
} ) ,
2022-05-13 18:42:40 -07:00
) . to . be . rejectedWith ( 'signature must be base58 encoded' ) ;
await mockRpcResponse ( {
method : 'getSignatureStatuses' ,
params : [ [ badTransactionSignature ] ] ,
error : mockErrorResponse ,
} ) ;
await expect (
connection . getSignatureStatus ( badTransactionSignature ) ,
) . to . be . rejectedWith ( mockErrorMessage ) ;
} ) ;
2021-02-05 18:59:00 -08:00
} ) ;
2018-08-23 10:52:48 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get transaction count' , async ( ) = > {
await mockRpcResponse ( {
2018-08-24 10:39:51 -07:00
method : 'getTransactionCount' ,
params : [ ] ,
2021-02-05 18:59:00 -08:00
value : 1000000 ,
} ) ;
2018-08-23 10:52:48 -07:00
2021-02-05 18:59:00 -08:00
const count = await connection . getTransactionCount ( ) ;
expect ( count ) . to . be . at . least ( 0 ) ;
} ) ;
2019-06-25 08:31:22 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get total supply' , async ( ) = > {
await mockRpcResponse ( {
2021-04-14 01:28:40 -07:00
method : 'getSupply' ,
2019-06-25 08:31:22 -07:00
params : [ ] ,
2021-04-14 01:28:40 -07:00
value : {
total : 1000000 ,
circulating : 100000 ,
nonCirculating : 900000 ,
2021-10-22 13:12:49 -07:00
nonCirculatingAccounts : [ ] ,
2021-04-14 01:28:40 -07:00
} ,
withContext : true ,
2021-02-05 18:59:00 -08:00
} ) ;
2019-06-25 08:31:22 -07:00
2021-02-05 18:59:00 -08:00
const count = await connection . getTotalSupply ( ) ;
expect ( count ) . to . be . at . least ( 0 ) ;
} ) ;
2019-09-26 13:13:57 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get minimum balance for rent exemption' , async ( ) = > {
await mockRpcResponse ( {
2019-09-26 13:13:57 -07:00
method : 'getMinimumBalanceForRentExemption' ,
params : [ 512 ] ,
2021-02-05 18:59:00 -08:00
value : 1000000 ,
} ) ;
2019-09-26 13:13:57 -07:00
2021-02-05 18:59:00 -08:00
const count = await connection . getMinimumBalanceForRentExemption ( 512 ) ;
expect ( count ) . to . be . at . least ( 0 ) ;
} ) ;
2019-09-26 13:13:57 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get confirmed signatures for address' , async ( ) = > {
const connection = new Connection ( url ) ;
2020-04-21 00:40:44 -07:00
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
2020-04-21 00:40:44 -07:00
method : 'getSlot' ,
params : [ ] ,
2021-02-05 18:59:00 -08:00
value : 1 ,
} ) ;
2020-04-21 00:40:44 -07:00
2021-02-05 18:59:00 -08:00
while ( ( await connection . getSlot ( ) ) <= 0 ) {
continue ;
}
2020-04-21 00:40:44 -07:00
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
2020-04-21 00:40:44 -07:00
method : 'getConfirmedBlock' ,
params : [ 1 ] ,
2021-02-05 18:59:00 -08:00
value : {
2021-03-18 07:10:48 -07:00
blockTime : 1614281964 ,
2020-04-21 00:40:44 -07:00
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 ] ,
2021-05-24 20:53:16 -07:00
data : '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7' ,
2020-04-21 00:40:44 -07:00
programIdIndex : 4 ,
} ,
] ,
recentBlockhash : 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE' ,
} ,
signatures : [
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ,
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG' ,
] ,
} ,
} ,
] ,
} ,
2021-02-05 18:59:00 -08:00
} ) ;
2022-03-24 22:21:14 -07:00
// Find a block that has a transaction.
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 1 ,
} ) ;
let slot = await connection . getFirstAvailableBlock ( ) ;
2021-03-14 22:08:10 -07:00
let address : PublicKey | undefined ;
let expectedSignature : string | undefined ;
2021-02-05 18:59:00 -08:00
while ( ! address || ! expectedSignature ) {
const block = await connection . getConfirmedBlock ( slot ) ;
if ( block . transactions . length > 0 ) {
2021-05-24 20:53:16 -07:00
const { signature , publicKey } =
block . transactions [ 0 ] . transaction . signatures [ 0 ] ;
2021-02-05 18:59:00 -08:00
if ( signature ) {
address = publicKey ;
expectedSignature = bs58 . encode ( signature ) ;
2022-03-24 22:21:14 -07:00
break ;
2021-02-05 18:59:00 -08:00
}
2020-04-21 00:40:44 -07:00
}
2022-03-24 22:21:14 -07:00
slot ++ ;
2020-04-21 00:40:44 -07:00
}
2021-02-05 18:59:00 -08:00
// getConfirmedSignaturesForAddress tests...
await mockRpcResponse ( {
2021-04-14 01:25:19 -07:00
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 0 ,
} ) ;
const mockSignature =
'5SHZ9NwpnS9zYnauN7pnuborKf39zGMr11XpMC59VvRSeDJNcnYLecmdxXCVuBFPNQLdCBBjyZiNCL4KoHKr3tvz' ;
await mockRpcResponse ( {
method : 'getConfirmedBlock' ,
params : [ slot , { transactionDetails : 'signatures' , rewards : false } ] ,
value : {
blockTime : 1614281964 ,
blockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
previousBlockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
parentSlot : 1 ,
signatures : [ mockSignature ] ,
} ,
} ) ;
await mockRpcResponse ( {
method : 'getSlot' ,
params : [ ] ,
value : 123 ,
} ) ;
await mockRpcResponse ( {
method : 'getConfirmedBlock' ,
params : [ slot + 2 , { transactionDetails : 'signatures' , rewards : false } ] ,
value : {
blockTime : 1614281964 ,
blockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
previousBlockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
parentSlot : 1 ,
signatures : [ mockSignature ] ,
} ,
} ) ;
await mockRpcResponse ( {
method : 'getConfirmedSignaturesForAddress2' ,
params : [ address . toBase58 ( ) , { before : mockSignature } ] ,
value : [
{
signature : expectedSignature ,
slot ,
err : null ,
memo : null ,
} ,
] ,
2021-02-05 18:59:00 -08:00
} ) ;
2020-04-21 00:40:44 -07:00
2021-05-24 20:53:16 -07:00
const confirmedSignatures =
await connection . getConfirmedSignaturesForAddress (
address ,
slot ,
slot + 1 ,
) ;
2021-02-05 18:59:00 -08:00
expect ( confirmedSignatures . includes ( expectedSignature ) ) . to . be . true ;
const badSlot = Number . MAX_SAFE_INTEGER - 1 ;
await mockRpcResponse ( {
2021-04-14 01:25:19 -07:00
method : 'getConfirmedBlock' ,
params : [ badSlot - 1 , { transactionDetails : 'signatures' , rewards : false } ] ,
error : { message : 'Block not available for slot ' + badSlot } ,
2021-02-05 18:59:00 -08:00
} ) ;
2021-04-14 01:25:19 -07:00
expect (
connection . getConfirmedSignaturesForAddress (
address ,
badSlot ,
badSlot + 1 ,
) ,
) . to . be . rejected ;
2021-02-05 18:59:00 -08:00
// getConfirmedSignaturesForAddress2 tests...
await mockRpcResponse ( {
2020-07-29 22:40:46 -07:00
method : 'getConfirmedSignaturesForAddress2' ,
params : [ address . toBase58 ( ) , { limit : 1 } ] ,
2021-02-05 18:59:00 -08:00
value : [
2020-07-29 22:40:46 -07:00
{
signature : expectedSignature ,
slot ,
err : null ,
memo : null ,
} ,
] ,
2021-02-05 18:59:00 -08:00
} ) ;
2020-04-21 00:40:44 -07:00
2021-05-24 20:53:16 -07:00
const confirmedSignatures2 =
await connection . getConfirmedSignaturesForAddress2 ( address , { limit : 1 } ) ;
2021-02-05 18:59:00 -08:00
expect ( confirmedSignatures2 ) . to . have . length ( 1 ) ;
2021-03-14 22:08:10 -07:00
if ( mockServer ) {
2021-02-05 18:59:00 -08:00
expect ( confirmedSignatures2 [ 0 ] . signature ) . to . eq ( expectedSignature ) ;
expect ( confirmedSignatures2 [ 0 ] . slot ) . to . eq ( slot ) ;
expect ( confirmedSignatures2 [ 0 ] . err ) . to . be . null ;
expect ( confirmedSignatures2 [ 0 ] . memo ) . to . be . null ;
}
} ) ;
2020-04-21 00:40:44 -07:00
2021-06-21 23:07:36 -07:00
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' ,
] ,
} ,
} ,
] ,
} ,
} ) ;
2022-03-24 22:21:14 -07:00
// Find a block that has a transaction.
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 1 ,
} ) ;
let slot = await connection . getFirstAvailableBlock ( ) ;
2021-06-21 23:07:36 -07:00
let address : PublicKey | undefined ;
let expectedSignature : string | undefined ;
while ( ! address || ! expectedSignature ) {
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 ) ;
2022-03-24 22:21:14 -07:00
break ;
2021-06-21 23:07:36 -07:00
}
}
2022-03-24 22:21:14 -07:00
slot ++ ;
2021-06-21 23:07:36 -07:00
}
// 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 ;
}
} ) ;
2021-03-22 10:22:59 -07:00
it ( 'get parsed confirmed transactions' , async ( ) = > {
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 ] ,
2021-05-24 20:53:16 -07:00
data : '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7' ,
2021-03-22 10:22:59 -07:00
programIdIndex : 4 ,
} ,
] ,
recentBlockhash : 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE' ,
} ,
signatures : [
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ,
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG' ,
] ,
} ,
} ,
] ,
} ,
} ) ;
2022-03-24 22:21:14 -07:00
// Find a block that has a transaction.
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 1 ,
} ) ;
let slot = await connection . getFirstAvailableBlock ( ) ;
2021-03-22 10:22:59 -07:00
let confirmedTransaction : string | undefined ;
while ( ! confirmedTransaction ) {
const block = await connection . getConfirmedBlock ( slot ) ;
for ( const tx of block . transactions ) {
if ( tx . transaction . signature ) {
confirmedTransaction = bs58 . encode ( tx . transaction . signature ) ;
2022-03-24 22:21:14 -07:00
break ;
2021-03-22 10:22:59 -07:00
}
}
2022-03-24 22:21:14 -07:00
slot ++ ;
2021-03-22 10:22:59 -07:00
}
await mockRpcBatchResponse ( {
batch : [
{
methodName : 'getConfirmedTransaction' ,
args : [ ] ,
} ,
] ,
result : [
{
blockTime : 1616102519 ,
meta : {
err : null ,
fee : 5000 ,
innerInstructions : [ ] ,
logMessages : [
'Program Vote111111111111111111111111111111111111111 invoke [1]' ,
'Program Vote111111111111111111111111111111111111111 success' ,
] ,
postBalances : [ 499999995000 , 26858640 , 1 , 1 , 1 ] ,
postTokenBalances : [ ] ,
preBalances : [ 500000000000 , 26858640 , 1 , 1 , 1 ] ,
preTokenBalances : [ ] ,
status : {
Ok : null ,
} ,
} ,
slot : 2 ,
transaction : {
message : {
accountKeys : [
{
pubkey : 'jcU4R7JccGEvDpe1i6bahvHpe47XahMXacG73EzE198' ,
signer : true ,
writable : true ,
} ,
{
pubkey : 'GfBcnCAU7kWfAYqKRCNyWEHjdEJZmzRZvEcX5bbzEQqt' ,
signer : false ,
writable : true ,
} ,
{
pubkey : 'SysvarS1otHashes111111111111111111111111111' ,
signer : false ,
writable : false ,
} ,
{
pubkey : 'SysvarC1ock11111111111111111111111111111111' ,
signer : false ,
writable : false ,
} ,
{
pubkey : 'Vote111111111111111111111111111111111111111' ,
signer : false ,
writable : false ,
} ,
] ,
instructions : [
{
parsed : {
info : {
clockSysvar :
'SysvarC1ock11111111111111111111111111111111' ,
slotHashesSysvar :
'SysvarS1otHashes111111111111111111111111111' ,
vote : {
hash : 'GuCya3AAGxn1qhoqxqy3WEdZdZUkXKpa9pthQ3tqvbpx' ,
slots : [ 1 ] ,
timestamp : 1616102669 ,
} ,
voteAccount :
'GfBcnCAU7kWfAYqKRCNyWEHjdEJZmzRZvEcX5bbzEQqt' ,
voteAuthority :
'jcU4R7JccGEvDpe1i6bahvHpe47XahMXacG73EzE198' ,
} ,
type : 'vote' ,
} ,
program : 'vote' ,
programId : 'Vote111111111111111111111111111111111111111' ,
} ,
] ,
recentBlockhash : 'G9ywjV5CVgMtLXruXtrE7af4QgFKYNXgDTw4jp7SWcSo' ,
} ,
signatures : [
'4G4rTqnUdzrmBHsdKJSiMtonpQLWSw1avJ8YxWQ95jE6iFFHFsEkBnoYycxnkBS9xHWRc6EarDsrFG9USFBbjfjx' ,
] ,
} ,
} ,
{
blockTime : 1616102519 ,
meta : {
err : null ,
fee : 5000 ,
innerInstructions : [ ] ,
logMessages : [
'Program Vote111111111111111111111111111111111111111 invoke [1]' ,
'Program Vote111111111111111111111111111111111111111 success' ,
] ,
postBalances : [ 499999995000 , 26858640 , 1 , 1 , 1 ] ,
postTokenBalances : [ ] ,
preBalances : [ 500000000000 , 26858640 , 1 , 1 , 1 ] ,
preTokenBalances : [ ] ,
status : {
Ok : null ,
} ,
} ,
slot : 2 ,
transaction : {
message : {
accountKeys : [
{
pubkey : 'jcU4R7JccGEvDpe1i6bahvHpe47XahMXacG73EzE198' ,
signer : true ,
writable : true ,
} ,
{
pubkey : 'GfBcnCAU7kWfAYqKRCNyWEHjdEJZmzRZvEcX5bbzEQqt' ,
signer : false ,
writable : true ,
} ,
{
pubkey : 'SysvarS1otHashes111111111111111111111111111' ,
signer : false ,
writable : false ,
} ,
{
pubkey : 'SysvarC1ock11111111111111111111111111111111' ,
signer : false ,
writable : false ,
} ,
{
pubkey : 'Vote111111111111111111111111111111111111111' ,
signer : false ,
writable : false ,
} ,
] ,
instructions : [
{
parsed : {
info : {
clockSysvar :
'SysvarC1ock11111111111111111111111111111111' ,
slotHashesSysvar :
'SysvarS1otHashes111111111111111111111111111' ,
vote : {
hash : 'GuCya3AAGxn1qhoqxqy3WEdZdZUkXKpa9pthQ3tqvbpx' ,
slots : [ 1 ] ,
timestamp : 1616102669 ,
} ,
voteAccount :
'GfBcnCAU7kWfAYqKRCNyWEHjdEJZmzRZvEcX5bbzEQqt' ,
voteAuthority :
'jcU4R7JccGEvDpe1i6bahvHpe47XahMXacG73EzE198' ,
} ,
type : 'vote' ,
} ,
program : 'vote' ,
programId : 'Vote111111111111111111111111111111111111111' ,
} ,
] ,
recentBlockhash : 'G9ywjV5CVgMtLXruXtrE7af4QgFKYNXgDTw4jp7SWcSo' ,
} ,
signatures : [
'4G4rTqnUdzrmBHsdKJSiMtonpQLWSw1avJ8YxWQ95jE6iFFHFsEkBnoYycxnkBS9xHWRc6EarDsrFG9USFBbjfjx' ,
] ,
} ,
} ,
] ,
} ) ;
2021-03-31 00:15:04 -07:00
let result = await connection . getParsedConfirmedTransactions ( [
2021-03-22 10:22:59 -07:00
confirmedTransaction ,
confirmedTransaction ,
] ) ;
if ( ! result ) {
expect ( result ) . to . be . ok ;
return ;
}
expect ( result ) . to . be . length ( 2 ) ;
expect ( result [ 0 ] ) . to . not . be . null ;
expect ( result [ 1 ] ) . to . not . be . null ;
if ( result [ 0 ] !== null ) {
expect ( result [ 0 ] . transaction . signatures ) . not . to . be . null ;
}
if ( result [ 1 ] !== null ) {
expect ( result [ 1 ] . transaction . signatures ) . not . to . be . null ;
}
2021-03-31 00:15:04 -07:00
result = await connection . getParsedConfirmedTransactions ( [ ] ) ;
if ( ! result ) {
expect ( result ) . to . be . ok ;
return ;
}
expect ( result ) . to . be . empty ;
2021-03-22 10:22:59 -07:00
} ) ;
2022-02-22 18:49:27 -08:00
it ( 'get block height' , async ( ) = > {
const commitment : Commitment = 'confirmed' ;
await mockRpcResponse ( {
method : 'getBlockHeight' ,
params : [ { commitment : commitment } ] ,
value : 10 ,
} ) ;
const blockHeight = await connection . getBlockHeight ( commitment ) ;
expect ( blockHeight ) . to . be . a ( 'number' ) ;
} ) ;
it ( 'get block production' , async ( ) = > {
const commitment : Commitment = 'processed' ;
// Find slot of the lowest confirmed block
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 1 ,
} ) ;
let firstSlot = await connection . getFirstAvailableBlock ( ) ;
// Find current block height
await mockRpcResponse ( {
method : 'getBlockHeight' ,
params : [ { commitment : commitment } ] ,
value : 10 ,
} ) ;
let lastSlot = await connection . getBlockHeight ( commitment ) ;
const blockProductionConfig = {
commitment : commitment ,
range : {
firstSlot ,
lastSlot ,
} ,
} ;
const blockProductionRet = {
byIdentity : {
'85iYT5RuzRTDgjyRa3cP8SYhM2j21fj7NhfJ3peu1DPr' : [ 12 , 10 ] ,
} ,
range : {
firstSlot ,
lastSlot ,
} ,
} ;
//mock RPC call with config specified
await mockRpcResponse ( {
method : 'getBlockProduction' ,
params : [ blockProductionConfig ] ,
value : blockProductionRet ,
withContext : true ,
} ) ;
//mock RPC call with commitment only
await mockRpcResponse ( {
method : 'getBlockProduction' ,
params : [ { commitment : commitment } ] ,
value : blockProductionRet ,
withContext : true ,
} ) ;
const result = await connection . getBlockProduction ( blockProductionConfig ) ;
if ( ! result ) {
expect ( result ) . to . be . ok ;
return ;
}
expect ( result . context ) . to . be . ok ;
expect ( result . value ) . to . be . ok ;
const resultContextSlot = result . context . slot ;
expect ( resultContextSlot ) . to . be . a ( 'number' ) ;
const resultIdentityDictionary = result . value . byIdentity ;
expect ( resultIdentityDictionary ) . to . be . a ( 'object' ) ;
for ( var key in resultIdentityDictionary ) {
expect ( key ) . to . be . a ( 'string' ) ;
expect ( resultIdentityDictionary [ key ] ) . to . be . a ( 'array' ) ;
expect ( resultIdentityDictionary [ key ] [ 0 ] ) . to . be . a ( 'number' ) ;
expect ( resultIdentityDictionary [ key ] [ 1 ] ) . to . be . a ( 'number' ) ;
}
const resultSlotRange = result . value . range ;
expect ( resultSlotRange . firstSlot ) . to . equal ( firstSlot ) ;
expect ( resultSlotRange . lastSlot ) . to . equal ( lastSlot ) ;
const resultCommitmentOnly = await connection . getBlockProduction (
commitment ,
) ;
if ( ! resultCommitmentOnly ) {
expect ( resultCommitmentOnly ) . to . be . ok ;
return ;
}
expect ( resultCommitmentOnly . context ) . to . be . ok ;
expect ( resultCommitmentOnly . value ) . to . be . ok ;
const resultCOContextSlot = result . context . slot ;
expect ( resultCOContextSlot ) . to . be . a ( 'number' ) ;
const resultCOIdentityDictionary = result . value . byIdentity ;
expect ( resultCOIdentityDictionary ) . to . be . a ( 'object' ) ;
for ( var property in resultCOIdentityDictionary ) {
expect ( property ) . to . be . a ( 'string' ) ;
expect ( resultCOIdentityDictionary [ property ] ) . to . be . a ( 'array' ) ;
expect ( resultCOIdentityDictionary [ property ] [ 0 ] ) . to . be . a ( 'number' ) ;
expect ( resultCOIdentityDictionary [ property ] [ 1 ] ) . to . be . a ( 'number' ) ;
}
const resultCOSlotRange = result . value . range ;
expect ( resultCOSlotRange . firstSlot ) . to . equal ( firstSlot ) ;
expect ( resultCOSlotRange . lastSlot ) . to . equal ( lastSlot ) ;
} ) ;
2021-05-25 10:12:47 -07:00
it ( 'get transaction' , async ( ) = > {
await mockRpcResponse ( {
method : 'getSlot' ,
params : [ ] ,
value : 1 ,
} ) ;
while ( ( await connection . getSlot ( ) ) <= 0 ) {
continue ;
}
await mockRpcResponse ( {
2022-01-27 15:43:01 -08:00
method : 'getBlock' ,
2021-05-25 10:12:47 -07:00
params : [ 1 ] ,
value : {
2022-01-27 15:43:01 -08:00
blockHeight : 0 ,
2021-05-25 10:12:47 -07:00
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 ] ,
2021-05-25 12:39:11 -07:00
data : '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7' ,
2021-05-25 10:12:47 -07:00
programIdIndex : 4 ,
} ,
] ,
recentBlockhash : 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE' ,
} ,
signatures : [
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ,
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG' ,
] ,
} ,
} ,
] ,
} ,
} ) ;
2022-03-24 22:21:14 -07:00
// Find a block that has a transaction.
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 1 ,
} ) ;
let slot = await connection . getFirstAvailableBlock ( ) ;
2022-01-27 15:43:01 -08:00
let transaction : string | undefined ;
while ( ! transaction ) {
2021-05-25 10:12:47 -07:00
const block = await connection . getBlock ( slot ) ;
if ( block && block . transactions . length > 0 ) {
2022-01-27 15:43:01 -08:00
transaction = block . transactions [ 0 ] . transaction . signatures [ 0 ] ;
2022-03-24 22:21:14 -07:00
continue ;
2021-05-25 10:12:47 -07:00
}
2022-03-24 22:21:14 -07:00
slot ++ ;
2021-05-25 10:12:47 -07:00
}
await mockRpcResponse ( {
2022-01-27 15:43:01 -08:00
method : 'getTransaction' ,
params : [ transaction ] ,
2021-05-25 10:12:47 -07:00
value : {
slot ,
transaction : {
message : {
accountKeys : [
'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf' ,
'57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy' ,
'SysvarS1otHashes111111111111111111111111111' ,
'SysvarC1ock11111111111111111111111111111111' ,
'Vote111111111111111111111111111111111111111' ,
] ,
header : {
numReadonlySignedAccounts : 0 ,
numReadonlyUnsignedAccounts : 3 ,
numRequiredSignatures : 2 ,
} ,
instructions : [
{
accounts : [ 1 , 2 , 3 ] ,
2021-05-25 12:39:11 -07:00
data : '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7' ,
2021-05-25 10:12:47 -07:00
programIdIndex : 4 ,
} ,
] ,
recentBlockhash : 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE' ,
} ,
signatures : [
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ,
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG' ,
] ,
} ,
meta : {
fee : 10000 ,
postBalances : [ 499260347380 , 15298080 , 1 , 1 , 1 ] ,
preBalances : [ 499260357380 , 15298080 , 1 , 1 , 1 ] ,
status : { Ok : null } ,
err : null ,
} ,
} ,
} ) ;
2022-01-27 15:43:01 -08:00
const result = await connection . getTransaction ( transaction ) ;
2021-05-25 10:12:47 -07:00
if ( ! result ) {
expect ( result ) . to . be . ok ;
return ;
}
const resultSignature = result . transaction . signatures [ 0 ] ;
2022-01-27 15:43:01 -08:00
expect ( resultSignature ) . to . eq ( transaction ) ;
2021-05-25 10:12:47 -07:00
const newAddress = Keypair . generate ( ) . publicKey ;
const recentSignature = await helpers . airdrop ( {
connection ,
address : newAddress ,
amount : 1 ,
} ) ;
await mockRpcResponse ( {
2022-01-27 15:43:01 -08:00
method : 'getTransaction' ,
2021-05-25 10:12:47 -07:00
params : [ recentSignature ] ,
value : null ,
} ) ;
// Signature hasn't been finalized yet
const nullResponse = await connection . getTransaction ( recentSignature ) ;
expect ( nullResponse ) . to . be . null ;
} ) ;
2021-02-05 18:59:00 -08:00
it ( 'get confirmed transaction' , async ( ) = > {
await mockRpcResponse ( {
2020-04-21 00:40:44 -07:00
method : 'getSlot' ,
params : [ ] ,
2021-02-05 18:59:00 -08:00
value : 1 ,
} ) ;
2020-04-21 00:40:44 -07:00
2021-02-05 18:59:00 -08:00
while ( ( await connection . getSlot ( ) ) <= 0 ) {
continue ;
}
2020-04-21 00:40:44 -07:00
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
2020-04-21 00:40:44 -07:00
method : 'getConfirmedBlock' ,
params : [ 1 ] ,
2021-02-05 18:59:00 -08:00
value : {
2021-03-18 07:10:48 -07:00
blockTime : 1614281964 ,
2020-04-21 00:40:44 -07:00
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 ] ,
2021-05-24 20:53:16 -07:00
data : '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7' ,
2020-04-21 00:40:44 -07:00
programIdIndex : 4 ,
} ,
] ,
recentBlockhash : 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE' ,
} ,
signatures : [
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ,
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG' ,
] ,
} ,
} ,
] ,
} ,
2021-02-05 18:59:00 -08:00
} ) ;
2022-03-24 22:21:14 -07:00
// Find a block that has a transaction.
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 1 ,
} ) ;
let slot = await connection . getFirstAvailableBlock ( ) ;
2021-03-14 22:08:10 -07:00
let confirmedTransaction : string | undefined ;
2021-02-05 18:59:00 -08:00
while ( ! confirmedTransaction ) {
const block = await connection . getConfirmedBlock ( slot ) ;
for ( const tx of block . transactions ) {
if ( tx . transaction . signature ) {
confirmedTransaction = bs58 . encode ( tx . transaction . signature ) ;
2022-03-24 22:21:14 -07:00
break ;
2021-02-05 18:59:00 -08:00
}
2020-04-21 00:40:44 -07:00
}
2022-03-24 22:21:14 -07:00
slot ++ ;
2020-04-21 00:40:44 -07:00
}
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
2020-04-21 00:40:44 -07:00
method : 'getConfirmedTransaction' ,
params : [ confirmedTransaction ] ,
2021-02-05 18:59:00 -08:00
value : {
2020-04-21 00:40:44 -07:00
slot ,
transaction : {
message : {
accountKeys : [
'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf' ,
'57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy' ,
'SysvarS1otHashes111111111111111111111111111' ,
'SysvarC1ock11111111111111111111111111111111' ,
'Vote111111111111111111111111111111111111111' ,
] ,
header : {
numReadonlySignedAccounts : 0 ,
numReadonlyUnsignedAccounts : 3 ,
numRequiredSignatures : 2 ,
} ,
instructions : [
{
accounts : [ 1 , 2 , 3 ] ,
2021-05-24 20:53:16 -07:00
data : '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7' ,
2020-04-21 00:40:44 -07:00
programIdIndex : 4 ,
} ,
] ,
recentBlockhash : 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE' ,
} ,
signatures : [
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ,
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG' ,
] ,
} ,
meta : {
fee : 10000 ,
postBalances : [ 499260347380 , 15298080 , 1 , 1 , 1 ] ,
preBalances : [ 499260357380 , 15298080 , 1 , 1 , 1 ] ,
status : { Ok : null } ,
err : null ,
} ,
} ,
2021-02-05 18:59:00 -08:00
} ) ;
2020-04-21 00:40:44 -07:00
2021-02-05 18:59:00 -08:00
const result = await connection . getConfirmedTransaction (
confirmedTransaction ,
) ;
2020-04-21 00:40:44 -07:00
2021-02-05 18:59:00 -08:00
if ( ! result ) {
expect ( result ) . to . be . ok ;
return ;
}
2020-04-21 00:40:44 -07:00
2021-02-05 18:59:00 -08:00
if ( result . transaction . signature === null ) {
expect ( result . transaction . signature ) . not . to . be . null ;
return ;
}
2020-04-21 00:40:44 -07:00
2021-02-05 18:59:00 -08:00
const resultSignature = bs58 . encode ( result . transaction . signature ) ;
expect ( resultSignature ) . to . eq ( confirmedTransaction ) ;
2020-04-21 00:40:44 -07:00
2021-05-07 01:59:51 -07:00
const newAddress = Keypair . generate ( ) . publicKey ;
2021-02-05 18:59:00 -08:00
const recentSignature = await helpers . airdrop ( {
connection ,
address : newAddress ,
amount : 1 ,
} ) ;
await mockRpcResponse ( {
2020-04-21 00:40:44 -07:00
method : 'getConfirmedTransaction' ,
params : [ recentSignature ] ,
2021-02-05 18:59:00 -08:00
value : null ,
} ) ;
2020-12-14 19:22:22 -08:00
2021-02-05 18:59:00 -08:00
// Signature hasn't been finalized yet
const nullResponse = await connection . getConfirmedTransaction (
recentSignature ,
) ;
expect ( nullResponse ) . to . be . null ;
} ) ;
2020-12-14 19:22:22 -08:00
2022-06-21 10:31:42 -07:00
it ( 'get transactions' , async function ( ) {
await mockRpcResponse ( {
method : 'getSlot' ,
params : [ ] ,
value : 1 ,
} ) ;
while ( ( await connection . getSlot ( ) ) <= 0 ) {
continue ;
}
await mockRpcResponse ( {
method : 'getBlock' ,
params : [ 1 ] ,
value : {
blockHeight : 0 ,
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.
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 1 ,
} ) ;
let slot = await connection . getFirstAvailableBlock ( ) ;
let transaction : string | undefined ;
while ( ! transaction ) {
const block = await connection . getBlock ( slot ) ;
if ( block && block . transactions . length > 0 ) {
transaction = block . transactions [ 0 ] . transaction . signatures [ 0 ] ;
continue ;
}
slot ++ ;
}
await mockRpcBatchResponse ( {
batch : [
{
methodName : 'getTransaction' ,
args : [ transaction ] ,
} ,
] ,
result : [
{
slot ,
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' ,
] ,
} ,
meta : {
fee : 10000 ,
postBalances : [ 499260347380 , 15298080 , 1 , 1 , 1 ] ,
preBalances : [ 499260357380 , 15298080 , 1 , 1 , 1 ] ,
status : { Ok : null } ,
err : null ,
} ,
} ,
] ,
} ) ;
const [ firstResult ] = await connection . getTransactions ( [ transaction ] ) ;
if ( firstResult == null ) {
expect . fail ( 'Expected `getTransactions()` to return one result' ) ;
}
expect ( firstResult . transaction . message . isAccountSigner ( 0 ) ) . to . be . true ;
} ) ;
2021-03-14 22:08:10 -07:00
if ( mockServer ) {
2021-02-05 18:59:00 -08:00
it ( 'get parsed confirmed transaction coerces public keys of inner instructions' , async ( ) = > {
const confirmedTransaction : TransactionSignature =
'4ADvAUQYxkh4qWKYE9QLW8gCLomGG94QchDLG4quvpBz1WqARYvzWQDDitKduAKspuy1DjcbnaDAnCAfnKpJYs48' ;
2021-03-14 22:08:10 -07:00
function getMockData ( inner : any ) {
2021-02-05 18:59:00 -08:00
return {
slot : 353050305 ,
transaction : {
message : {
accountKeys : [
{
pubkey : 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf' ,
signer : true ,
writable : true ,
} ,
] ,
instructions : [
{
accounts : [ 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf' ] ,
2021-05-24 20:53:16 -07:00
data : '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7' ,
2021-02-05 18:59:00 -08:00
programId : 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' ,
} ,
] ,
recentBlockhash : 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE' ,
} ,
signatures : [
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ,
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG' ,
2020-12-14 19:22:22 -08:00
] ,
2021-02-05 18:59:00 -08:00
} ,
meta : {
fee : 10000 ,
postBalances : [ 499260347380 , 15298080 , 1 , 1 , 1 ] ,
preBalances : [ 499260357380 , 15298080 , 1 , 1 , 1 ] ,
innerInstructions : [
2020-12-14 19:22:22 -08:00
{
2021-02-05 18:59:00 -08:00
index : 0 ,
instructions : [ inner ] ,
2020-12-14 19:22:22 -08:00
} ,
] ,
2021-02-05 18:59:00 -08:00
status : { Ok : null } ,
err : null ,
2020-12-14 19:22:22 -08:00
} ,
2021-02-05 18:59:00 -08:00
} ;
}
2020-12-14 19:22:22 -08:00
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
method : 'getConfirmedTransaction' ,
2021-04-09 11:58:08 -07:00
params : [ confirmedTransaction , { encoding : 'jsonParsed' } ] ,
2021-02-05 18:59:00 -08:00
value : getMockData ( {
parsed : { } ,
program : 'spl-token' ,
programId : 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' ,
} ) ,
} ) ;
const result = await connection . getParsedConfirmedTransaction (
confirmedTransaction ,
) ;
2020-12-14 19:22:22 -08:00
2021-03-14 22:08:10 -07:00
if ( result && result . meta && result . meta . innerInstructions ) {
const innerInstructions = result . meta . innerInstructions ;
const firstIx = innerInstructions [ 0 ] . instructions [ 0 ] ;
expect ( firstIx . programId ) . to . be . instanceOf ( PublicKey ) ;
2021-02-05 18:59:00 -08:00
}
2020-12-14 19:22:22 -08:00
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
method : 'getConfirmedTransaction' ,
2021-04-09 11:58:08 -07:00
params : [ confirmedTransaction , { encoding : 'jsonParsed' } ] ,
2021-02-05 18:59:00 -08:00
value : getMockData ( {
accounts : [
'EeJqWk5pczNjsqqY3jia9xfFNG1dD68te4s8gsdCuEk7' ,
'6tVrjJhFm5SAvvdh6tysjotQurCSELpxuW3JaAAYeC1m' ,
] ,
data : 'ai3535' ,
programId : 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' ,
} ) ,
} ) ;
const result2 = await connection . getParsedConfirmedTransaction (
confirmedTransaction ,
) ;
2020-12-14 19:22:22 -08:00
2021-03-14 22:08:10 -07:00
if ( result2 && result2 . meta && result2 . meta . innerInstructions ) {
const innerInstructions = result2 . meta . innerInstructions ;
const instruction = innerInstructions [ 0 ] . instructions [ 0 ] ;
expect ( instruction . programId ) . to . be . instanceOf ( PublicKey ) ;
if ( 'accounts' in instruction ) {
expect ( instruction . accounts [ 0 ] ) . to . be . instanceOf ( PublicKey ) ;
expect ( instruction . accounts [ 1 ] ) . to . be . instanceOf ( PublicKey ) ;
} else {
expect ( 'accounts' in instruction ) . to . be . true ;
}
}
2021-02-05 18:59:00 -08:00
} ) ;
}
2019-11-12 08:21:19 -08:00
2022-03-24 22:21:14 -07:00
describe ( 'get block' , function ( ) {
beforeEach ( async function ( ) {
await mockRpcResponse ( {
method : 'getSlot' ,
params : [ ] ,
value : 1 ,
} ) ;
2021-05-25 10:12:47 -07:00
2022-03-24 22:21:14 -07:00
while ( ( await connection . getSlot ( ) ) <= 0 ) {
continue ;
}
2021-05-25 10:12:47 -07:00
} ) ;
2022-03-24 22:21:14 -07:00
it ( 'gets the genesis block' , async function ( ) {
await mockRpcResponse ( {
method : 'getBlock' ,
params : [ 0 ] ,
value : {
blockHeight : 0 ,
blockTime : 1614281964 ,
blockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
previousBlockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
parentSlot : 0 ,
transactions : [ ] ,
} ,
} ) ;
2021-05-25 10:12:47 -07:00
2022-03-24 22:21:14 -07:00
let maybeBlock0 : BlockResponse | null ;
try {
maybeBlock0 = await connection . getBlock ( 0 ) ;
} catch ( e ) {
if ( process . env . TEST_LIVE ) {
console . warn (
'WARNING: We ran no assertions about the genesis block because block 0 ' +
'could not be found. See https://github.com/solana-labs/solana/issues/23853.' ,
) ;
this . skip ( ) ;
} else {
throw e ;
}
}
expect ( maybeBlock0 ) . not . to . be . null ;
const block0 = maybeBlock0 ! ;
2021-05-25 10:12:47 -07:00
2022-03-24 22:21:14 -07:00
// Block 0 never has any transactions in test validator
const blockhash0 = block0 . blockhash ;
expect ( block0 . transactions ) . to . have . length ( 0 ) ;
expect ( blockhash0 ) . not . to . be . null ;
expect ( block0 . previousBlockhash ) . not . to . be . null ;
expect ( block0 . parentSlot ) . to . eq ( 0 ) ;
} ) ;
it ( 'gets a block having a parent' , async function ( ) {
// Mock parent of block with transaction.
await mockRpcResponse ( {
method : 'getBlock' ,
params : [ 0 ] ,
value : {
blockHeight : 0 ,
blockTime : 1614281964 ,
blockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
previousBlockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
parentSlot : 0 ,
transactions : [ ] ,
} ,
} ) ;
// Mock block with transaction.
await mockRpcResponse ( {
method : 'getBlock' ,
params : [ 1 ] ,
value : {
blockHeight : 0 ,
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 ,
2021-05-25 10:12:47 -07:00
} ,
2022-03-24 22:21:14 -07:00
instructions : [
{
accounts : [ 1 , 2 , 3 ] ,
data : '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7' ,
programIdIndex : 4 ,
} ,
] ,
recentBlockhash :
'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE' ,
} ,
signatures : [
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ,
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG' ,
2021-05-25 10:12:47 -07:00
] ,
} ,
} ,
2022-03-24 22:21:14 -07:00
] ,
} ,
} ) ;
2021-05-25 10:12:47 -07:00
2022-03-24 22:21:14 -07:00
// Find a block that has a transaction *and* a parent.
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 0 ,
} ) ;
let candidateSlot = ( await connection . getFirstAvailableBlock ( ) ) + 1 ;
let result :
| {
blockWithTransaction : BlockResponse ;
parentBlock : BlockResponse ;
}
| undefined ;
while ( ! result ) {
const candidateBlock = await connection . getBlock ( candidateSlot ) ;
if ( candidateBlock && candidateBlock . transactions . length ) {
const parentBlock = await connection . getBlock ( candidateSlot - 1 ) ;
2022-02-08 13:58:50 -08:00
if ( parentBlock ) {
2022-03-24 22:21:14 -07:00
result = { blockWithTransaction : candidateBlock , parentBlock } ;
break ;
2022-02-08 13:58:50 -08:00
}
}
2022-03-24 22:21:14 -07:00
candidateSlot ++ ;
2021-05-25 10:12:47 -07:00
}
2022-03-24 22:21:14 -07:00
// Compare data with parent
expect ( result . blockWithTransaction . previousBlockhash ) . to . eq (
result . parentBlock . blockhash ,
) ;
expect ( result . blockWithTransaction . blockhash ) . not . to . be . null ;
expect ( result . blockWithTransaction . transactions [ 0 ] . transaction ) . not . to . be
. null ;
await mockRpcResponse ( {
method : 'getBlock' ,
params : [ Number . MAX_SAFE_INTEGER ] ,
error : {
message : ` Block not available for slot ${ Number . MAX_SAFE_INTEGER } ` ,
} ,
} ) ;
await expect (
connection . getBlock ( Number . MAX_SAFE_INTEGER ) ,
) . to . be . rejectedWith (
` Block not available for slot ${ Number . MAX_SAFE_INTEGER } ` ,
) ;
2021-05-25 10:12:47 -07:00
} ) ;
} ) ;
2022-03-24 22:21:14 -07:00
describe ( 'get confirmed block' , function ( ) {
beforeEach ( async function ( ) {
await mockRpcResponse ( {
method : 'getSlot' ,
params : [ ] ,
value : 1 ,
} ) ;
while ( ( await connection . getSlot ( ) ) <= 0 ) {
continue ;
}
2021-02-05 18:59:00 -08:00
} ) ;
2020-01-16 12:09:21 -08:00
2022-03-24 22:21:14 -07:00
it ( 'gets the genesis block' , async function ( ) {
await mockRpcResponse ( {
method : 'getConfirmedBlock' ,
params : [ 0 ] ,
value : {
blockHeight : 0 ,
blockTime : 1614281964 ,
blockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
previousBlockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
parentSlot : 0 ,
transactions : [ ] ,
} ,
} ) ;
2019-11-26 00:58:00 -08:00
2022-03-24 22:21:14 -07:00
let block0 : ConfirmedBlock ;
try {
block0 = await connection . getConfirmedBlock ( 0 ) ;
} catch ( e ) {
if ( process . env . TEST_LIVE ) {
console . warn (
'WARNING: We ran no assertions about the genesis block because block 0 ' +
'could not be found. See https://github.com/solana-labs/solana/issues/23853.' ,
) ;
this . skip ( ) ;
} else {
throw e ;
}
}
2021-02-05 18:59:00 -08:00
2022-03-24 22:21:14 -07:00
// Block 0 never has any transactions in test validator
const blockhash0 = block0 . blockhash ;
expect ( block0 . transactions ) . to . have . length ( 0 ) ;
expect ( blockhash0 ) . not . to . be . null ;
expect ( block0 . previousBlockhash ) . not . to . be . null ;
expect ( block0 . parentSlot ) . to . eq ( 0 ) ;
} ) ;
2021-02-05 18:59:00 -08:00
2022-03-24 22:21:14 -07:00
it ( 'gets a block having a parent' , async function ( ) {
// Mock parent of block with transaction.
await mockRpcResponse ( {
method : 'getConfirmedBlock' ,
params : [ 0 ] ,
value : {
blockHeight : 0 ,
blockTime : 1614281964 ,
blockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
previousBlockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
parentSlot : 0 ,
transactions : [ ] ,
} ,
} ) ;
// Mock block with transaction.
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 ,
2020-01-16 12:09:21 -08:00
} ,
2022-03-24 22:21:14 -07:00
instructions : [
{
accounts : [ 1 , 2 , 3 ] ,
data : '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7' ,
programIdIndex : 4 ,
} ,
] ,
recentBlockhash :
'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE' ,
} ,
signatures : [
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ,
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG' ,
2020-01-16 12:09:21 -08:00
] ,
} ,
} ,
2022-03-24 22:21:14 -07:00
] ,
} ,
} ) ;
2021-02-05 18:59:00 -08:00
2022-03-24 22:21:14 -07:00
// Find a block that has a transaction *and* a parent.
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 0 ,
} ) ;
let candidateSlot = ( await connection . getFirstAvailableBlock ( ) ) + 1 ;
let result :
| {
blockWithTransaction : ConfirmedBlock ;
parentBlock : ConfirmedBlock ;
}
| undefined ;
while ( ! result ) {
const candidateBlock = await connection . getConfirmedBlock (
candidateSlot ,
) ;
if ( candidateBlock && candidateBlock . transactions . length ) {
const parentBlock = await connection . getConfirmedBlock (
candidateSlot - 1 ,
) ;
2022-02-08 13:58:50 -08:00
if ( parentBlock ) {
2022-03-24 22:21:14 -07:00
result = { blockWithTransaction : candidateBlock , parentBlock } ;
break ;
2022-02-08 13:58:50 -08:00
}
}
2022-03-24 22:21:14 -07:00
candidateSlot ++ ;
2021-02-05 18:59:00 -08:00
}
2020-01-22 12:05:19 -08:00
2022-03-24 22:21:14 -07:00
// Compare data with parent
expect ( result . blockWithTransaction . previousBlockhash ) . to . eq (
result . parentBlock . blockhash ,
) ;
expect ( result . blockWithTransaction . blockhash ) . not . to . be . null ;
expect ( result . blockWithTransaction . transactions [ 0 ] . transaction ) . not . to . be
. null ;
await mockRpcResponse ( {
method : 'getConfirmedBlock' ,
params : [ Number . MAX_SAFE_INTEGER ] ,
error : {
message : ` Block not available for slot ${ Number . MAX_SAFE_INTEGER } ` ,
} ,
} ) ;
await expect (
connection . getConfirmedBlock ( Number . MAX_SAFE_INTEGER ) ,
) . to . be . rejectedWith (
` Block not available for slot ${ Number . MAX_SAFE_INTEGER } ` ,
) ;
2021-02-05 18:59:00 -08:00
} ) ;
} ) ;
2020-06-04 03:12:59 -07:00
2021-09-20 20:08:12 -07:00
it ( 'get blocks between two slots' , async ( ) = > {
await mockRpcResponse ( {
2022-01-27 15:43:01 -08:00
method : 'getBlocks' ,
2022-04-28 16:09:08 -07:00
params : [ 0 , 9 ] ,
value : [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] ,
} ) ;
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 0 ,
2021-09-20 20:08:12 -07:00
} ) ;
await mockRpcResponse ( {
method : 'getSlot' ,
params : [ ] ,
2022-04-28 16:09:08 -07:00
value : 9 ,
2021-09-20 20:08:12 -07:00
} ) ;
2022-04-28 16:09:08 -07:00
while ( ( await connection . getSlot ( ) ) <= 1 ) {
continue ;
}
const [ startSlot , latestSlot ] = await Promise . all ( [
connection . getFirstAvailableBlock ( ) ,
connection . getSlot ( ) ,
] ) ;
const blocks = await connection . getBlocks ( startSlot , latestSlot ) ;
expect ( blocks ) . to . have . length ( latestSlot - startSlot + 1 ) ;
expect ( blocks [ 0 ] ) . to . eq ( startSlot ) ;
2021-09-20 20:08:12 -07:00
expect ( blocks ) . to . contain ( latestSlot ) ;
2022-04-28 16:09:08 -07:00
} ) . timeout ( 20 * 1000 ) ;
2021-09-20 20:08:12 -07:00
it ( 'get blocks from starting slot' , async ( ) = > {
await mockRpcResponse ( {
2022-01-27 15:43:01 -08:00
method : 'getBlocks' ,
2021-09-20 20:08:12 -07:00
params : [ 0 ] ,
value : [
2022-04-28 16:09:08 -07:00
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 ,
20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 ,
38 , 39 , 40 , 41 , 42 ,
2021-09-20 20:08:12 -07:00
] ,
} ) ;
2022-04-28 16:09:08 -07:00
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 0 ,
} ) ;
2021-09-20 20:08:12 -07:00
await mockRpcResponse ( {
method : 'getSlot' ,
params : [ ] ,
value : 20 ,
} ) ;
2022-04-28 16:09:08 -07:00
while ( ( await connection . getSlot ( ) ) <= 1 ) {
2021-09-20 20:08:12 -07:00
continue ;
}
2022-04-28 16:09:08 -07:00
const startSlot = await connection . getFirstAvailableBlock ( ) ;
const [ blocks , latestSlot ] = await Promise . all ( [
connection . getBlocks ( startSlot ) ,
connection . getSlot ( ) ,
] ) ;
if ( mockServer ) {
expect ( blocks ) . to . have . length ( 43 ) ;
} else {
expect ( blocks ) . to . have . length ( latestSlot - startSlot + 1 ) ;
}
expect ( blocks [ 0 ] ) . to . eq ( startSlot ) ;
2021-09-20 20:08:12 -07:00
expect ( blocks ) . to . contain ( latestSlot ) ;
2022-04-28 16:09:08 -07:00
} ) . timeout ( 20 * 1000 ) ;
2021-09-20 20:08:12 -07:00
2022-03-24 22:21:14 -07:00
describe ( 'get block signatures' , function ( ) {
beforeEach ( async function ( ) {
await mockRpcResponse ( {
method : 'getSlot' ,
params : [ ] ,
value : 1 ,
} ) ;
2021-04-13 23:56:08 -07:00
2022-03-24 22:21:14 -07:00
while ( ( await connection . getSlot ( ) ) <= 0 ) {
continue ;
}
} ) ;
2021-04-13 23:56:08 -07:00
2022-03-24 22:21:14 -07:00
it ( 'gets the genesis block' , async function ( ) {
await mockRpcResponse ( {
method : 'getBlock' ,
params : [
0 ,
{
transactionDetails : 'signatures' ,
rewards : false ,
} ,
] ,
value : {
blockHeight : 0 ,
blockTime : 1614281964 ,
blockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
previousBlockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
parentSlot : 0 ,
signatures : [ ] ,
2021-04-13 23:56:08 -07:00
} ,
2022-03-24 22:21:14 -07:00
} ) ;
2021-04-13 23:56:08 -07:00
2022-03-24 22:21:14 -07:00
let block0 : BlockSignatures ;
try {
block0 = await connection . getBlockSignatures ( 0 ) ;
} catch ( e ) {
if ( process . env . TEST_LIVE ) {
console . warn (
'WARNING: We ran no assertions about the genesis block because block 0 ' +
'could not be found. See https://github.com/solana-labs/solana/issues/23853.' ,
) ;
this . skip ( ) ;
} else {
throw e ;
}
}
2021-04-13 23:56:08 -07:00
2022-03-24 22:21:14 -07:00
// Block 0 never has any transactions in test validator
const blockhash0 = block0 . blockhash ;
expect ( block0 . signatures ) . to . have . length ( 0 ) ;
expect ( blockhash0 ) . not . to . be . null ;
expect ( block0 . previousBlockhash ) . not . to . be . null ;
expect ( block0 . parentSlot ) . to . eq ( 0 ) ;
expect ( block0 ) . to . not . have . property ( 'rewards' ) ;
} ) ;
it ( 'gets a block having a parent' , async function ( ) {
// Mock parent of block with transaction.
await mockRpcResponse ( {
method : 'getBlock' ,
params : [
0 ,
{
transactionDetails : 'signatures' ,
rewards : false ,
} ,
] ,
value : {
blockHeight : 0 ,
blockTime : 1614281964 ,
blockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
previousBlockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
parentSlot : 0 ,
signatures : [ ] ,
2021-04-13 23:56:08 -07:00
} ,
2022-03-24 22:21:14 -07:00
} ) ;
// Mock block with transaction.
await mockRpcResponse ( {
method : 'getBlock' ,
params : [
1 ,
{
transactionDetails : 'signatures' ,
rewards : false ,
} ,
2021-04-13 23:56:08 -07:00
] ,
2022-03-24 22:21:14 -07:00
value : {
blockHeight : 1 ,
blockTime : 1614281964 ,
blockhash : '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy' ,
previousBlockhash : 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo' ,
parentSlot : 0 ,
signatures : [
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt' ,
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG' ,
] ,
} ,
} ) ;
2021-04-13 23:56:08 -07:00
2022-03-24 22:21:14 -07:00
// Find a block that has a transaction *and* a parent.
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 0 ,
} ) ;
let candidateSlot = ( await connection . getFirstAvailableBlock ( ) ) + 1 ;
let result :
| {
blockWithTransaction : BlockSignatures ;
parentBlock : BlockSignatures ;
}
| undefined ;
while ( ! result ) {
const candidateBlock = await connection . getBlockSignatures (
candidateSlot ,
) ;
if ( candidateBlock && candidateBlock . signatures . length ) {
const parentBlock = await connection . getBlockSignatures (
candidateSlot - 1 ,
) ;
2022-02-08 13:58:50 -08:00
if ( parentBlock ) {
2022-03-24 22:21:14 -07:00
result = { blockWithTransaction : candidateBlock , parentBlock } ;
break ;
2022-02-08 13:58:50 -08:00
}
}
2022-03-24 22:21:14 -07:00
candidateSlot ++ ;
2021-04-13 23:56:08 -07:00
}
2022-03-24 22:21:14 -07:00
// Compare data with parent
expect ( result . blockWithTransaction . previousBlockhash ) . to . eq (
result . parentBlock . blockhash ,
) ;
expect ( result . blockWithTransaction . blockhash ) . not . to . be . null ;
expect ( result . blockWithTransaction . signatures [ 0 ] ) . not . to . be . null ;
expect ( result . blockWithTransaction ) . to . not . have . property ( 'rewards' ) ;
await mockRpcResponse ( {
method : 'getBlock' ,
params : [ Number . MAX_SAFE_INTEGER ] ,
error : {
message : ` Block not available for slot ${ Number . MAX_SAFE_INTEGER } ` ,
} ,
} ) ;
await expect (
connection . getBlockSignatures ( Number . MAX_SAFE_INTEGER ) ,
) . to . be . rejectedWith (
` Block not available for slot ${ Number . MAX_SAFE_INTEGER } ` ,
) ;
2021-04-13 23:56:08 -07:00
} ) ;
} ) ;
2021-02-05 18:59:00 -08:00
it ( 'get recent blockhash' , async ( ) = > {
2021-03-14 22:08:10 -07:00
const commitments : Commitment [ ] = [ 'processed' , 'confirmed' , 'finalized' ] ;
for ( const commitment of commitments ) {
2021-02-05 18:59:00 -08:00
const { blockhash , feeCalculator } = await helpers . recentBlockhash ( {
connection ,
commitment ,
} ) ;
expect ( bs58 . decode ( blockhash ) ) . to . have . length ( 32 ) ;
expect ( feeCalculator . lamportsPerSignature ) . to . be . at . least ( 0 ) ;
}
} ) ;
2020-06-04 03:12:59 -07:00
2022-01-27 15:43:01 -08:00
it ( 'get latest blockhash' , async ( ) = > {
const commitments : Commitment [ ] = [ 'processed' , 'confirmed' , 'finalized' ] ;
for ( const commitment of commitments ) {
const { blockhash , lastValidBlockHeight } = await helpers . latestBlockhash ( {
connection ,
commitment ,
} ) ;
expect ( bs58 . decode ( blockhash ) ) . to . have . length ( 32 ) ;
expect ( lastValidBlockHeight ) . to . be . at . least ( 0 ) ;
}
} ) ;
2021-02-05 18:59:00 -08:00
it ( 'get fee calculator' , async ( ) = > {
const { blockhash } = await helpers . recentBlockhash ( { connection } ) ;
await mockRpcResponse ( {
2020-06-04 03:12:59 -07:00
method : 'getFeeCalculatorForBlockhash' ,
2021-02-17 16:15:09 -08:00
params : [ blockhash , { commitment : 'confirmed' } ] ,
2021-02-05 18:59:00 -08:00
value : {
feeCalculator : {
lamportsPerSignature : 5000 ,
2020-06-04 03:12:59 -07:00
} ,
} ,
2021-02-05 18:59:00 -08:00
withContext : true ,
} ) ;
2020-06-04 03:12:59 -07:00
2021-02-05 18:59:00 -08:00
const feeCalculator = (
2021-02-17 16:15:09 -08:00
await connection . getFeeCalculatorForBlockhash ( blockhash , 'confirmed' )
2021-02-05 18:59:00 -08:00
) . value ;
if ( feeCalculator === null ) {
expect ( feeCalculator ) . not . to . be . null ;
return ;
}
expect ( feeCalculator . lamportsPerSignature ) . to . eq ( 5000 ) ;
} ) ;
2020-05-18 20:27:36 -07:00
2022-01-11 01:49:28 -08:00
it ( 'get fee for message' , async ( ) = > {
const accountFrom = Keypair . generate ( ) ;
const accountTo = Keypair . generate ( ) ;
2022-05-14 21:54:12 -07:00
const latestBlockhash = await helpers . latestBlockhash ( { connection } ) ;
2022-01-11 01:49:28 -08:00
const transaction = new Transaction ( {
feePayer : accountFrom.publicKey ,
2022-05-14 21:54:12 -07:00
. . . latestBlockhash ,
2022-01-11 01:49:28 -08:00
} ) . add (
SystemProgram . transfer ( {
fromPubkey : accountFrom.publicKey ,
toPubkey : accountTo.publicKey ,
lamports : 10 ,
} ) ,
) ;
const message = transaction . compileMessage ( ) ;
await mockRpcResponse ( {
method : 'getFeeForMessage' ,
params : [
message . serialize ( ) . toString ( 'base64' ) ,
{ commitment : 'confirmed' } ,
] ,
value : 5000 ,
withContext : true ,
} ) ;
const fee = ( await connection . getFeeForMessage ( message , 'confirmed' ) ) . value ;
expect ( fee ) . to . eq ( 5000 ) ;
} ) ;
2021-02-05 18:59:00 -08:00
it ( 'get block time' , async ( ) = > {
await mockRpcResponse ( {
2020-05-18 20:27:36 -07:00
method : 'getBlockTime' ,
2020-08-26 00:40:48 -07:00
params : [ 1 ] ,
2021-02-05 18:59:00 -08:00
value : 10000 ,
} ) ;
2020-05-18 20:27:36 -07:00
2022-03-24 22:21:14 -07:00
await mockRpcResponse ( {
method : 'getFirstAvailableBlock' ,
params : [ ] ,
value : 1 ,
} ) ;
const slot = await connection . getFirstAvailableBlock ( ) ;
const blockTime = await connection . getBlockTime ( slot ) ;
2021-02-05 18:59:00 -08:00
if ( blockTime === null ) {
expect ( blockTime ) . not . to . be . null ;
} else {
expect ( blockTime ) . to . be . greaterThan ( 0 ) ;
}
} ) ;
2020-05-21 01:58:17 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get minimum ledger slot' , async ( ) = > {
await mockRpcResponse ( {
2020-05-21 01:58:17 -07:00
method : 'minimumLedgerSlot' ,
params : [ ] ,
2021-02-05 18:59:00 -08:00
value : 0 ,
} ) ;
2020-05-21 01:58:17 -07:00
2021-02-05 18:59:00 -08:00
const minimumLedgerSlot = await connection . getMinimumLedgerSlot ( ) ;
expect ( minimumLedgerSlot ) . to . be . at . least ( 0 ) ;
} ) ;
2020-05-23 02:33:04 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get first available block' , async ( ) = > {
await mockRpcResponse ( {
2020-05-23 02:33:04 -07:00
method : 'getFirstAvailableBlock' ,
params : [ ] ,
2021-02-05 18:59:00 -08:00
value : 0 ,
} ) ;
2020-05-23 02:33:04 -07:00
2021-02-05 18:59:00 -08:00
const firstAvailableBlock = await connection . getFirstAvailableBlock ( ) ;
expect ( firstAvailableBlock ) . to . be . at . least ( 0 ) ;
} ) ;
2020-05-22 04:30:22 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get supply' , async ( ) = > {
await mockRpcResponse ( {
2020-05-22 04:30:22 -07:00
method : 'getSupply' ,
2021-10-22 13:12:49 -07:00
params : [ { commitment : 'finalized' } ] ,
2021-02-05 18:59:00 -08:00
value : {
total : 1000 ,
circulating : 100 ,
nonCirculating : 900 ,
2021-05-07 01:59:51 -07:00
nonCirculatingAccounts : [ Keypair . generate ( ) . publicKey . toBase58 ( ) ] ,
2020-05-22 04:30:22 -07:00
} ,
2021-02-05 18:59:00 -08:00
withContext : true ,
} ) ;
2020-10-08 20:26:58 -07:00
2021-10-22 13:12:49 -07:00
const supply = ( await connection . getSupply ( 'finalized' ) ) . value ;
2021-02-05 18:59:00 -08:00
expect ( supply . total ) . to . be . greaterThan ( 0 ) ;
expect ( supply . circulating ) . to . be . greaterThan ( 0 ) ;
expect ( supply . nonCirculating ) . to . be . at . least ( 0 ) ;
expect ( supply . nonCirculatingAccounts . length ) . to . be . at . least ( 0 ) ;
} ) ;
2020-10-08 20:26:58 -07:00
2021-10-22 13:12:49 -07:00
it ( 'get supply without accounts' , async ( ) = > {
await mockRpcResponse ( {
method : 'getSupply' ,
params : [ { commitment : 'finalized' } ] ,
value : {
total : 1000 ,
circulating : 100 ,
nonCirculating : 900 ,
nonCirculatingAccounts : [ ] ,
} ,
withContext : true ,
} ) ;
const supply = (
await connection . getSupply ( {
commitment : 'finalized' ,
excludeNonCirculatingAccountsList : true ,
} )
) . value ;
expect ( supply . total ) . to . be . greaterThan ( 0 ) ;
expect ( supply . circulating ) . to . be . greaterThan ( 0 ) ;
expect ( supply . nonCirculating ) . to . be . at . least ( 0 ) ;
expect ( supply . nonCirculatingAccounts . length ) . to . eq ( 0 ) ;
} ) ;
2022-07-01 22:23:25 -07:00
[ undefined , 'confirmed' as Commitment ] . forEach ( function ( commitment ) {
2022-07-01 22:31:02 -07:00
describe (
2022-07-01 22:23:25 -07:00
"when the connection's default commitment is `" + commitment + '`' ,
( ) = > {
let connectionWithCommitment : Connection ;
beforeEach ( ( ) = > {
connectionWithCommitment = new Connection ( url , commitment ) ;
} ) ;
it ( 'get performance samples' , async ( ) = > {
await mockRpcResponse ( {
method : 'getRecentPerformanceSamples' ,
params : [ ] ,
value : [
{
slot : 1234 ,
numTransactions : 1000 ,
numSlots : 60 ,
samplePeriodSecs : 60 ,
} ,
] ,
} ) ;
2020-10-08 20:26:58 -07:00
2022-07-01 22:23:25 -07:00
const perfSamples =
await connectionWithCommitment . getRecentPerformanceSamples ( ) ;
expect ( Array . isArray ( perfSamples ) ) . to . be . true ;
2020-10-08 20:26:58 -07:00
2022-07-01 22:23:25 -07:00
if ( perfSamples . length > 0 ) {
expect ( perfSamples [ 0 ] . slot ) . to . be . greaterThan ( 0 ) ;
expect ( perfSamples [ 0 ] . numTransactions ) . to . be . greaterThan ( 0 ) ;
expect ( perfSamples [ 0 ] . numSlots ) . to . be . greaterThan ( 0 ) ;
expect ( perfSamples [ 0 ] . samplePeriodSecs ) . to . be . greaterThan ( 0 ) ;
}
} ) ;
} ,
) ;
2021-02-05 18:59:00 -08:00
} ) ;
2020-10-08 20:26:58 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get performance samples limit too high' , async ( ) = > {
await mockRpcResponse ( {
method : 'getRecentPerformanceSamples' ,
params : [ 100000 ] ,
error : mockErrorResponse ,
} ) ;
2020-10-08 20:26:58 -07:00
2021-02-05 18:59:00 -08:00
await expect ( connection . getRecentPerformanceSamples ( 100000 ) ) . to . be . rejected ;
} ) ;
2020-10-08 20:26:58 -07:00
2021-02-05 18:59:00 -08:00
const TOKEN_PROGRAM_ID = new PublicKey (
'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' ,
) ;
2020-07-30 21:33:54 -07:00
2021-02-05 18:59:00 -08:00
if ( process . env . TEST_LIVE ) {
describe ( 'token methods' , ( ) = > {
2021-02-17 16:15:09 -08:00
const connection = new Connection ( url , 'confirmed' ) ;
2022-10-16 00:26:08 -07:00
const newAccount = PublicKey . unique ( ) ;
2020-07-30 21:33:54 -07:00
2022-10-16 00:26:08 -07:00
let payerKeypair = new Keypair ( ) ;
2022-05-06 09:14:11 -07:00
let testTokenMintPubkey : PublicKey ;
let testOwnerKeypair : Keypair ;
let testTokenAccountPubkey : PublicKey ;
2021-02-05 18:59:00 -08:00
let testSignature : TransactionSignature ;
2020-08-06 04:16:01 -07:00
2021-02-05 18:59:00 -08:00
// Setup token mints and accounts for token tests
before ( async function ( ) {
this . timeout ( 30 * 1000 ) ;
2020-08-06 04:16:01 -07:00
2021-02-05 18:59:00 -08:00
await connection . confirmTransaction (
2022-05-06 09:14:11 -07:00
await connection . requestAirdrop ( payerKeypair . publicKey , 100000000000 ) ,
2021-02-05 18:59:00 -08:00
) ;
2020-07-30 21:33:54 -07:00
2022-05-06 09:14:11 -07:00
const mintOwnerKeypair = new Keypair ( ) ;
const accountOwnerKeypair = new Keypair ( ) ;
const mintPubkey = await splToken . createMint (
2021-05-07 01:59:51 -07:00
connection as any ,
2022-05-06 09:14:11 -07:00
payerKeypair ,
mintOwnerKeypair . publicKey ,
null , // freeze authority
2 , // decimals
2021-02-05 18:59:00 -08:00
) ;
2020-07-30 21:33:54 -07:00
2022-05-06 09:14:11 -07:00
const tokenAccountPubkey = await splToken . createAccount (
connection as any ,
payerKeypair ,
mintPubkey ,
accountOwnerKeypair . publicKey ,
) ;
2020-09-01 10:58:40 -07:00
2022-05-06 09:14:11 -07:00
await splToken . mintTo (
2021-05-07 01:59:51 -07:00
connection as any ,
2022-05-06 09:14:11 -07:00
payerKeypair ,
mintPubkey ,
tokenAccountPubkey ,
mintOwnerKeypair ,
11111 ,
2021-02-05 18:59:00 -08:00
) ;
2020-07-30 21:33:54 -07:00
2022-05-06 09:14:11 -07:00
const mintPubkey2 = await splToken . createMint (
connection as any ,
payerKeypair ,
mintOwnerKeypair . publicKey ,
null , // freeze authority
2 , // decimals
2021-02-05 18:59:00 -08:00
) ;
2020-09-01 10:58:40 -07:00
2022-05-06 09:14:11 -07:00
const tokenAccountPubkey2 = await splToken . createAccount (
connection as any ,
payerKeypair ,
mintPubkey2 ,
accountOwnerKeypair . publicKey ,
2021-02-05 18:59:00 -08:00
) ;
2022-05-06 09:14:11 -07:00
await splToken . mintTo (
connection as any ,
payerKeypair ,
mintPubkey2 ,
tokenAccountPubkey2 ,
mintOwnerKeypair ,
100 ,
2021-02-05 18:59:00 -08:00
) ;
2020-07-30 21:33:54 -07:00
2022-05-06 09:14:11 -07:00
const tokenAccountDestPubkey = await splToken . createAccount (
connection as any ,
payerKeypair ,
mintPubkey ,
accountOwnerKeypair . publicKey ,
new Keypair ( ) as any ,
) ;
2021-02-05 18:59:00 -08:00
2022-05-06 09:14:11 -07:00
testSignature = await splToken . transfer (
connection as any ,
payerKeypair ,
tokenAccountPubkey ,
tokenAccountDestPubkey ,
accountOwnerKeypair ,
1 ,
) ;
testTokenMintPubkey = mintPubkey as PublicKey ;
testOwnerKeypair = accountOwnerKeypair ;
testTokenAccountPubkey = tokenAccountPubkey as PublicKey ;
2021-02-05 18:59:00 -08:00
} ) ;
it ( 'get token supply' , async ( ) = > {
2022-05-06 09:14:11 -07:00
const supply = ( await connection . getTokenSupply ( testTokenMintPubkey ) )
. value ;
2021-02-05 18:59:00 -08:00
expect ( supply . uiAmount ) . to . eq ( 111.11 ) ;
expect ( supply . decimals ) . to . eq ( 2 ) ;
expect ( supply . amount ) . to . eq ( '11111' ) ;
await expect ( connection . getTokenSupply ( newAccount ) ) . to . be . rejected ;
} ) ;
it ( 'get token largest accounts' , async ( ) = > {
const largestAccounts = (
2022-05-06 09:14:11 -07:00
await connection . getTokenLargestAccounts ( testTokenMintPubkey )
2021-02-05 18:59:00 -08:00
) . value ;
expect ( largestAccounts ) . to . have . length ( 2 ) ;
const largestAccount = largestAccounts [ 0 ] ;
2022-05-06 09:14:11 -07:00
expect ( largestAccount . address ) . to . eql ( testTokenAccountPubkey ) ;
2021-02-05 18:59:00 -08:00
expect ( largestAccount . amount ) . to . eq ( '11110' ) ;
expect ( largestAccount . decimals ) . to . eq ( 2 ) ;
expect ( largestAccount . uiAmount ) . to . eq ( 111.1 ) ;
await expect ( connection . getTokenLargestAccounts ( newAccount ) ) . to . be
. rejected ;
} ) ;
it ( 'get confirmed token transaction' , async ( ) = > {
const parsedTx = await connection . getParsedConfirmedTransaction (
testSignature ,
) ;
if ( parsedTx === null ) {
expect ( parsedTx ) . not . to . be . null ;
return ;
}
const { signatures , message } = parsedTx . transaction ;
expect ( signatures [ 0 ] ) . to . eq ( testSignature ) ;
const ix = message . instructions [ 0 ] ;
2021-03-14 22:08:10 -07:00
if ( 'parsed' in ix ) {
2021-02-05 18:59:00 -08:00
expect ( ix . program ) . to . eq ( 'spl-token' ) ;
expect ( ix . programId ) . to . eql ( TOKEN_PROGRAM_ID ) ;
} else {
expect ( 'parsed' in ix ) . to . be . true ;
}
const missingSignature =
'45pGoC4Rr3fJ1TKrsiRkhHRbdUeX7633XAGVec6XzVdpRbzQgHhe6ZC6Uq164MPWtiqMg7wCkC6Wy3jy2BqsDEKf' ;
const nullResponse = await connection . getParsedConfirmedTransaction (
missingSignature ,
) ;
2020-07-30 21:33:54 -07:00
2021-02-05 18:59:00 -08:00
expect ( nullResponse ) . to . be . null ;
} ) ;
it ( 'get token account balance' , async ( ) = > {
const balance = (
2022-05-06 09:14:11 -07:00
await connection . getTokenAccountBalance ( testTokenAccountPubkey )
2021-02-05 18:59:00 -08:00
) . value ;
expect ( balance . amount ) . to . eq ( '11110' ) ;
expect ( balance . decimals ) . to . eq ( 2 ) ;
expect ( balance . uiAmount ) . to . eq ( 111.1 ) ;
await expect ( connection . getTokenAccountBalance ( newAccount ) ) . to . be
. rejected ;
} ) ;
it ( 'get parsed token account info' , async ( ) = > {
const accountInfo = (
2022-05-06 09:14:11 -07:00
await connection . getParsedAccountInfo ( testTokenAccountPubkey )
2021-02-05 18:59:00 -08:00
) . value ;
if ( accountInfo ) {
const data = accountInfo . data ;
2021-07-08 18:01:11 -07:00
if ( Buffer . isBuffer ( data ) ) {
expect ( Buffer . isBuffer ( data ) ) . to . eq ( false ) ;
2021-02-05 18:59:00 -08:00
} else {
expect ( data . program ) . to . eq ( 'spl-token' ) ;
expect ( data . parsed ) . to . be . ok ;
}
}
} ) ;
2022-10-16 00:26:08 -07:00
it ( 'get multiple parsed token accounts' , async ( ) = > {
const accounts = (
await connection . getMultipleParsedAccounts ( [
testTokenAccountPubkey ,
testTokenMintPubkey ,
payerKeypair . publicKey ,
newAccount ,
] )
) . value ;
expect ( accounts . length ) . to . eq ( 4 ) ;
const parsedTokenAccount = accounts [ 0 ] ;
if ( parsedTokenAccount ) {
const data = parsedTokenAccount . data ;
if ( Buffer . isBuffer ( data ) ) {
expect ( Buffer . isBuffer ( data ) ) . to . eq ( false ) ;
} else {
expect ( data . program ) . to . eq ( 'spl-token' ) ;
expect ( data . parsed ) . to . be . ok ;
}
} else {
expect ( parsedTokenAccount ) . to . be . ok ;
}
const parsedTokenMint = accounts [ 1 ] ;
if ( parsedTokenMint ) {
const data = parsedTokenMint . data ;
if ( Buffer . isBuffer ( data ) ) {
expect ( Buffer . isBuffer ( data ) ) . to . eq ( false ) ;
} else {
expect ( data . program ) . to . eq ( 'spl-token' ) ;
expect ( data . parsed ) . to . be . ok ;
}
} else {
expect ( parsedTokenMint ) . to . be . ok ;
}
const unparsedPayerAccount = accounts [ 2 ] ;
if ( unparsedPayerAccount ) {
const data = unparsedPayerAccount . data ;
expect ( Buffer . isBuffer ( data ) ) . to . be . true ;
} else {
expect ( unparsedPayerAccount ) . to . be . ok ;
}
const unknownAccount = accounts [ 3 ] ;
expect ( unknownAccount ) . to . not . be . ok ;
} ) ;
2021-02-05 18:59:00 -08:00
it ( 'get parsed token program accounts' , async ( ) = > {
const tokenAccounts = await connection . getParsedProgramAccounts (
TOKEN_PROGRAM_ID ,
) ;
tokenAccounts . forEach ( ( { account } ) = > {
expect ( account . owner ) . to . eql ( TOKEN_PROGRAM_ID ) ;
const data = account . data ;
2021-07-08 18:01:11 -07:00
if ( Buffer . isBuffer ( data ) ) {
expect ( Buffer . isBuffer ( data ) ) . to . eq ( false ) ;
2021-02-05 18:59:00 -08:00
} else {
expect ( data . parsed ) . to . be . ok ;
expect ( data . program ) . to . eq ( 'spl-token' ) ;
}
} ) ;
} ) ;
it ( 'get parsed token accounts by owner' , async ( ) = > {
const tokenAccounts = (
2022-05-06 09:14:11 -07:00
await connection . getParsedTokenAccountsByOwner (
testOwnerKeypair . publicKey ,
{
mint : testTokenMintPubkey ,
} ,
)
2021-02-05 18:59:00 -08:00
) . value ;
tokenAccounts . forEach ( ( { account } ) = > {
expect ( account . owner ) . to . eql ( TOKEN_PROGRAM_ID ) ;
const data = account . data ;
2021-07-08 18:01:11 -07:00
if ( Buffer . isBuffer ( data ) ) {
expect ( Buffer . isBuffer ( data ) ) . to . eq ( false ) ;
2021-02-05 18:59:00 -08:00
} else {
expect ( data . parsed ) . to . be . ok ;
expect ( data . program ) . to . eq ( 'spl-token' ) ;
}
} ) ;
} ) ;
it ( 'get token accounts by owner' , async ( ) = > {
const accountsWithMintFilter = (
2022-05-06 09:14:11 -07:00
await connection . getTokenAccountsByOwner ( testOwnerKeypair . publicKey , {
mint : testTokenMintPubkey ,
2021-02-05 18:59:00 -08:00
} )
) . value ;
expect ( accountsWithMintFilter ) . to . have . length ( 2 ) ;
const accountsWithProgramFilter = (
2022-05-06 09:14:11 -07:00
await connection . getTokenAccountsByOwner ( testOwnerKeypair . publicKey , {
2021-02-05 18:59:00 -08:00
programId : TOKEN_PROGRAM_ID ,
} )
) . value ;
expect ( accountsWithProgramFilter ) . to . have . length ( 3 ) ;
const noAccounts = (
await connection . getTokenAccountsByOwner ( newAccount , {
2022-05-06 09:14:11 -07:00
mint : testTokenMintPubkey ,
2021-02-05 18:59:00 -08:00
} )
) . value ;
expect ( noAccounts ) . to . have . length ( 0 ) ;
await expect (
2022-05-06 09:14:11 -07:00
connection . getTokenAccountsByOwner ( testOwnerKeypair . publicKey , {
2021-02-05 18:59:00 -08:00
mint : newAccount ,
} ) ,
) . to . be . rejected ;
await expect (
2022-05-06 09:14:11 -07:00
connection . getTokenAccountsByOwner ( testOwnerKeypair . publicKey , {
2021-02-05 18:59:00 -08:00
programId : newAccount ,
} ) ,
) . to . be . rejected ;
} ) ;
} ) ;
2021-02-12 17:29:26 -08:00
it ( 'consistent preflightCommitment' , async ( ) = > {
const connection = new Connection ( url , 'singleGossip' ) ;
2021-05-07 01:59:51 -07:00
const sender = Keypair . generate ( ) ;
const recipient = Keypair . generate ( ) ;
2021-02-12 17:29:26 -08:00
let signature = await connection . requestAirdrop (
sender . publicKey ,
2 * LAMPORTS_PER_SOL ,
) ;
await connection . confirmTransaction ( signature , 'singleGossip' ) ;
const transaction = new Transaction ( ) . add (
SystemProgram . transfer ( {
fromPubkey : sender.publicKey ,
toPubkey : recipient.publicKey ,
lamports : LAMPORTS_PER_SOL ,
} ) ,
) ;
await sendAndConfirmTransaction ( connection , transaction , [ sender ] ) ;
} ) ;
2021-02-05 18:59:00 -08:00
}
2020-07-30 21:33:54 -07:00
2021-02-05 18:59:00 -08:00
it ( 'get largest accounts' , async ( ) = > {
await mockRpcResponse ( {
method : 'getLargestAccounts' ,
params : [ ] ,
value : new Array ( 20 ) . fill ( 0 ) . map ( ( ) = > ( {
2021-05-07 01:59:51 -07:00
address : Keypair.generate ( ) . publicKey . toBase58 ( ) ,
2021-02-05 18:59:00 -08:00
lamports : 1000 ,
} ) ) ,
withContext : true ,
} ) ;
2020-07-30 21:33:54 -07:00
2021-02-05 18:59:00 -08:00
const largestAccounts = ( await connection . getLargestAccounts ( ) ) . value ;
expect ( largestAccounts ) . to . have . length ( 20 ) ;
2020-08-06 04:16:01 -07:00
} ) ;
2020-07-30 21:33:54 -07:00
2021-02-05 18:59:00 -08:00
it ( 'stake activation should throw when called for not delegated account' , async ( ) = > {
2021-05-07 01:59:51 -07:00
const publicKey = Keypair . generate ( ) . publicKey ;
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
method : 'getStakeActivation' ,
params : [ publicKey . toBase58 ( ) , { } ] ,
error : { message : 'account not delegated' } ,
} ) ;
2020-08-11 02:28:07 -07:00
2021-02-05 18:59:00 -08:00
await expect ( connection . getStakeActivation ( publicKey ) ) . to . be . rejected ;
2020-08-11 02:28:07 -07:00
} ) ;
2021-02-05 18:59:00 -08:00
if ( process . env . TEST_LIVE ) {
it ( 'stake activation should return activating for new accounts' , async ( ) = > {
2022-05-10 09:37:15 -07:00
// todo: use `Connection.getMinimumStakeDelegation` when implemented
const MIN_STAKE_DELEGATION = LAMPORTS_PER_SOL ;
const STAKE_ACCOUNT_MIN_BALANCE =
await connection . getMinimumBalanceForRentExemption ( StakeProgram . space ) ;
2021-02-05 18:59:00 -08:00
const voteAccounts = await connection . getVoteAccounts ( ) ;
const voteAccount = voteAccounts . current . concat (
voteAccounts . delinquent ,
) [ 0 ] ;
const votePubkey = new PublicKey ( voteAccount . votePubkey ) ;
2021-05-07 01:59:51 -07:00
const authorized = Keypair . generate ( ) ;
2021-02-05 18:59:00 -08:00
let signature = await connection . requestAirdrop (
authorized . publicKey ,
2 * LAMPORTS_PER_SOL ,
) ;
2021-02-17 16:15:09 -08:00
await connection . confirmTransaction ( signature , 'confirmed' ) ;
2020-07-30 21:33:54 -07:00
2021-05-07 01:59:51 -07:00
const newStakeAccount = Keypair . generate ( ) ;
2021-02-05 18:59:00 -08:00
let createAndInitialize = StakeProgram . createAccount ( {
fromPubkey : authorized.publicKey ,
stakePubkey : newStakeAccount.publicKey ,
authorized : new Authorized ( authorized . publicKey , authorized . publicKey ) ,
lockup : new Lockup ( 0 , 0 , new PublicKey ( 0 ) ) ,
2022-05-10 09:37:15 -07:00
lamports : STAKE_ACCOUNT_MIN_BALANCE + MIN_STAKE_DELEGATION ,
2021-02-05 18:59:00 -08:00
} ) ;
await sendAndConfirmTransaction (
connection ,
createAndInitialize ,
[ authorized , newStakeAccount ] ,
{
2021-02-17 16:15:09 -08:00
preflightCommitment : 'confirmed' ,
commitment : 'confirmed' ,
2021-02-05 18:59:00 -08:00
} ,
) ;
let delegation = StakeProgram . delegate ( {
stakePubkey : newStakeAccount.publicKey ,
authorizedPubkey : authorized.publicKey ,
votePubkey ,
} ) ;
await sendAndConfirmTransaction ( connection , delegation , [ authorized ] , {
2021-02-17 16:15:09 -08:00
preflightCommitment : 'confirmed' ,
commitment : 'confirmed' ,
2021-02-05 18:59:00 -08:00
} ) ;
const LARGE_EPOCH = 4000 ;
await expect (
connection . getStakeActivation (
newStakeAccount . publicKey ,
2021-02-17 16:15:09 -08:00
'confirmed' ,
2021-02-05 18:59:00 -08:00
LARGE_EPOCH ,
) ,
) . to . be . rejectedWith (
` failed to get Stake Activation ${ newStakeAccount . publicKey . toBase58 ( ) } : Invalid param: epoch ${ LARGE_EPOCH } has not yet started ` ,
) ;
2020-07-30 21:33:54 -07:00
2021-02-05 18:59:00 -08:00
const activationState = await connection . getStakeActivation (
newStakeAccount . publicKey ,
2021-02-17 16:15:09 -08:00
'confirmed' ,
2021-02-05 18:59:00 -08:00
) ;
expect ( activationState . state ) . to . eq ( 'activating' ) ;
2022-05-10 09:37:15 -07:00
expect ( activationState . inactive ) . to . eq ( MIN_STAKE_DELEGATION ) ;
2021-02-05 18:59:00 -08:00
expect ( activationState . active ) . to . eq ( 0 ) ;
} ) ;
}
2020-08-06 04:16:01 -07:00
2021-03-14 22:08:10 -07:00
if ( mockServer ) {
2021-02-05 18:59:00 -08:00
it ( 'stake activation should only accept state with valid string literals' , async ( ) = > {
2021-05-07 01:59:51 -07:00
const publicKey = Keypair . generate ( ) . publicKey ;
2021-02-05 18:59:00 -08:00
2021-03-14 22:08:10 -07:00
const addStakeActivationMock = async ( state : any ) = > {
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
method : 'getStakeActivation' ,
params : [ publicKey . toBase58 ( ) , { } ] ,
value : {
state : state ,
active : 0 ,
inactive : 80 ,
} ,
} ) ;
} ;
2020-08-06 04:16:01 -07:00
2021-02-05 18:59:00 -08:00
await addStakeActivationMock ( 'active' ) ;
let activation = await connection . getStakeActivation (
publicKey ,
2021-02-17 16:15:09 -08:00
'confirmed' ,
2021-02-05 18:59:00 -08:00
) ;
expect ( activation . state ) . to . eq ( 'active' ) ;
expect ( activation . active ) . to . eq ( 0 ) ;
expect ( activation . inactive ) . to . eq ( 80 ) ;
2020-08-06 08:47:22 -07:00
2021-02-05 18:59:00 -08:00
await addStakeActivationMock ( 'invalid' ) ;
2021-02-17 16:15:09 -08:00
await expect ( connection . getStakeActivation ( publicKey , 'confirmed' ) ) . to . be
. rejected ;
2020-08-06 08:47:22 -07:00
} ) ;
2021-02-05 18:59:00 -08:00
}
2020-08-06 08:47:22 -07:00
2021-02-05 18:59:00 -08:00
it ( 'getVersion' , async ( ) = > {
await mockRpcResponse ( {
method : 'getVersion' ,
params : [ ] ,
value : { 'solana-core' : '0.20.4' } ,
2020-08-06 08:47:22 -07:00
} ) ;
2021-02-05 18:59:00 -08:00
const version = await connection . getVersion ( ) ;
expect ( version [ 'solana-core' ] ) . to . be . ok ;
2020-08-06 08:47:22 -07:00
} ) ;
2021-09-09 10:34:43 -07:00
it ( 'getGenesisHash' , async ( ) = > {
await mockRpcResponse ( {
method : 'getGenesisHash' ,
params : [ ] ,
value : 'GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC' ,
} ) ;
const genesisHash = await connection . getGenesisHash ( ) ;
expect ( genesisHash ) . not . to . be . empty ;
} ) ;
2021-02-05 18:59:00 -08:00
it ( 'request airdrop' , async ( ) = > {
2021-05-07 01:59:51 -07:00
const account = Keypair . generate ( ) ;
2020-08-06 04:16:01 -07:00
2021-02-05 18:59:00 -08:00
await helpers . airdrop ( {
connection ,
address : account.publicKey ,
amount : LAMPORTS_PER_SOL ,
} ) ;
2020-08-06 04:16:01 -07:00
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
method : 'getBalance' ,
2021-02-17 16:15:09 -08:00
params : [ account . publicKey . toBase58 ( ) , { commitment : 'confirmed' } ] ,
2021-02-05 18:59:00 -08:00
value : LAMPORTS_PER_SOL ,
withContext : true ,
} ) ;
2020-08-06 04:16:01 -07:00
2021-02-17 16:15:09 -08:00
const balance = await connection . getBalance ( account . publicKey , 'confirmed' ) ;
2021-02-05 18:59:00 -08:00
expect ( balance ) . to . eq ( LAMPORTS_PER_SOL ) ;
2020-08-06 04:16:01 -07:00
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
method : 'getAccountInfo' ,
params : [
account . publicKey . toBase58 ( ) ,
2021-02-17 16:15:09 -08:00
{ commitment : 'confirmed' , encoding : 'base64' } ,
2021-02-05 18:59:00 -08:00
] ,
value : {
owner : '11111111111111111111111111111111' ,
lamports : LAMPORTS_PER_SOL ,
data : [ '' , 'base64' ] ,
executable : false ,
2021-02-25 23:06:12 -08:00
rentEpoch : 20 ,
2021-02-05 18:59:00 -08:00
} ,
withContext : true ,
} ) ;
2020-07-30 21:33:54 -07:00
2021-02-05 18:59:00 -08:00
const accountInfo = await connection . getAccountInfo (
account . publicKey ,
2021-02-17 16:15:09 -08:00
'confirmed' ,
2021-02-05 18:59:00 -08:00
) ;
if ( accountInfo === null ) {
expect ( accountInfo ) . not . to . be . null ;
return ;
}
expect ( accountInfo . lamports ) . to . eq ( LAMPORTS_PER_SOL ) ;
expect ( accountInfo . data ) . to . have . length ( 0 ) ;
expect ( accountInfo . owner ) . to . eql ( SystemProgram . programId ) ;
2020-05-22 10:23:29 -07:00
2021-02-05 18:59:00 -08:00
await mockRpcResponse ( {
2020-08-06 08:47:22 -07:00
method : 'getAccountInfo' ,
params : [
account . publicKey . toBase58 ( ) ,
2021-02-17 16:15:09 -08:00
{ commitment : 'confirmed' , encoding : 'jsonParsed' } ,
2020-08-06 08:47:22 -07:00
] ,
2021-02-05 18:59:00 -08:00
value : {
owner : '11111111111111111111111111111111' ,
lamports : LAMPORTS_PER_SOL ,
data : [ '' , 'base64' ] ,
executable : false ,
2021-02-25 23:06:12 -08:00
rentEpoch : 20 ,
2020-08-06 08:47:22 -07:00
} ,
2021-02-05 18:59:00 -08:00
withContext : true ,
} ) ;
2020-04-04 23:54:48 -07:00
2021-02-05 18:59:00 -08:00
const parsedAccountInfo = (
2021-02-17 16:15:09 -08:00
await connection . getParsedAccountInfo ( account . publicKey , 'confirmed' )
2021-02-05 18:59:00 -08:00
) . value ;
if ( parsedAccountInfo === null ) {
expect ( parsedAccountInfo ) . not . to . be . null ;
return ;
2021-03-14 22:08:10 -07:00
} else if ( 'parsed' in parsedAccountInfo . data ) {
2021-02-05 18:59:00 -08:00
expect ( parsedAccountInfo . data . parsed ) . not . to . be . ok ;
return ;
}
expect ( parsedAccountInfo . lamports ) . to . eq ( LAMPORTS_PER_SOL ) ;
expect ( parsedAccountInfo . data ) . to . have . length ( 0 ) ;
expect ( parsedAccountInfo . owner ) . to . eql ( SystemProgram . programId ) ;
} ) ;
2020-07-22 06:58:04 -07:00
2021-02-05 18:59:00 -08:00
it ( 'transaction failure' , async ( ) = > {
2021-05-07 01:59:51 -07:00
const payer = Keypair . generate ( ) ;
2020-07-22 06:58:04 -07:00
2021-02-05 18:59:00 -08:00
await helpers . airdrop ( {
connection ,
address : payer.publicKey ,
amount : LAMPORTS_PER_SOL ,
} ) ;
2020-04-04 23:54:48 -07:00
2021-05-07 01:59:51 -07:00
const newAccount = Keypair . generate ( ) ;
2021-02-05 18:59:00 -08:00
let transaction = new Transaction ( ) . add (
SystemProgram . createAccount ( {
fromPubkey : payer.publicKey ,
newAccountPubkey : newAccount.publicKey ,
lamports : LAMPORTS_PER_SOL / 2 ,
space : 0 ,
programId : SystemProgram.programId ,
} ) ,
) ;
2020-09-07 22:12:47 -07:00
2021-02-05 18:59:00 -08:00
await helpers . processTransaction ( {
connection ,
transaction ,
signers : [ payer , newAccount ] ,
2021-02-17 16:15:09 -08:00
commitment : 'confirmed' ,
2021-02-05 18:59:00 -08:00
} ) ;
2020-06-03 04:55:42 -07:00
2021-02-05 18:59:00 -08:00
// This should fail because the account is already created
const expectedErr = { InstructionError : [ 0 , { Custom : 0 } ] } ;
const confirmResult = (
await helpers . processTransaction ( {
connection ,
transaction ,
signers : [ payer , newAccount ] ,
2021-02-17 16:15:09 -08:00
commitment : 'confirmed' ,
2021-02-05 18:59:00 -08:00
err : expectedErr ,
} )
) . value ;
expect ( confirmResult . err ) . to . eql ( expectedErr ) ;
2020-04-04 23:54:48 -07:00
2021-03-14 22:08:10 -07:00
invariant ( transaction . signature ) ;
2021-02-05 18:59:00 -08:00
const signature = bs58 . encode ( transaction . signature ) ;
await mockRpcResponse ( {
2020-04-04 23:54:48 -07:00
method : 'getSignatureStatuses' ,
2021-02-05 18:59:00 -08:00
params : [ [ signature ] ] ,
value : [
{
slot : 0 ,
confirmations : 11 ,
status : { Err : expectedErr } ,
err : expectedErr ,
2020-01-08 12:59:58 -08:00
} ,
2021-02-05 18:59:00 -08:00
] ,
withContext : true ,
} ) ;
2020-07-08 05:46:16 -07:00
2021-02-05 18:59:00 -08:00
const response = ( await connection . getSignatureStatus ( signature ) ) . value ;
verifySignatureStatus ( response , expectedErr ) ;
} ) ;
2020-06-11 00:00:59 -07:00
2022-07-12 05:07:17 -07:00
if ( mockServer ) {
it ( 'returnData on simulateTransaction' , async ( ) = > {
const tx = new Transaction ( ) ;
tx . feePayer = Keypair . generate ( ) . publicKey ;
const getLatestBlockhashResponse = {
method : 'getLatestBlockhash' ,
params : [ ] ,
value : {
blockhash : 'CSymwgTNX1j3E4qhKfJAUE41nBWEwXufoYryPbkde5RR' ,
feeCalculator : {
lamportsPerSignature : 5000 ,
} ,
lastValidBlockHeight : 51 ,
} ,
withContext : true ,
} ;
const simulateTransactionResponse = {
method : 'simulateTransaction' ,
params : [ ] ,
value : {
err : null ,
accounts : null ,
logs : [
'Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri invoke [1]' ,
'Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri consumed 2366 of 1400000 compute units' ,
'Program return: 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri KgAAAAAAAAA=' ,
'Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success' ,
] ,
returnData : {
data : [ 'KgAAAAAAAAA==' , 'base64' ] ,
programId : '83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri' ,
} ,
unitsConsumed : 2366 ,
} ,
withContext : true ,
} ;
await mockRpcResponse ( getLatestBlockhashResponse ) ;
await mockRpcResponse ( simulateTransactionResponse ) ;
const response = ( await connection . simulateTransaction ( tx ) ) . value ;
expect ( response . returnData ) . to . eql ( {
data : [ 'KgAAAAAAAAA==' , 'base64' ] ,
programId : '83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri' ,
} ) ;
} ) ;
}
2021-02-05 18:59:00 -08:00
if ( process . env . TEST_LIVE ) {
2022-07-22 01:02:49 -07:00
it ( 'getStakeMinimumDelegation' , async ( ) = > {
const { value } = await connection . getStakeMinimumDelegation ( ) ;
expect ( value ) . to . be . a ( 'number' ) ;
} ) ;
2022-09-06 20:53:42 -07:00
it ( 'sendTransaction' , async ( ) = > {
const connection = new Connection ( url , 'confirmed' ) ;
const payer = Keypair . generate ( ) ;
await helpers . airdrop ( {
connection ,
address : payer.publicKey ,
amount : LAMPORTS_PER_SOL ,
} ) ;
const recentBlockhash = await (
await helpers . latestBlockhash ( { connection } )
) . blockhash ;
const versionedTx = new VersionedTransaction (
new Message ( {
header : {
numRequiredSignatures : 1 ,
numReadonlySignedAccounts : 0 ,
numReadonlyUnsignedAccounts : 0 ,
} ,
recentBlockhash ,
instructions : [ ] ,
accountKeys : [ payer . publicKey . toBase58 ( ) ] ,
} ) ,
) ;
versionedTx . sign ( [ payer ] ) ;
await connection . sendTransaction ( versionedTx ) ;
} ) ;
it ( 'simulateTransaction' , async ( ) = > {
const connection = new Connection ( url , 'confirmed' ) ;
const payer = Keypair . generate ( ) ;
await helpers . airdrop ( {
connection ,
address : payer.publicKey ,
amount : LAMPORTS_PER_SOL ,
} ) ;
const recentBlockhash = await (
await helpers . latestBlockhash ( { connection } )
) . blockhash ;
const versionedTx = new VersionedTransaction (
new Message ( {
header : {
numRequiredSignatures : 1 ,
numReadonlySignedAccounts : 0 ,
numReadonlyUnsignedAccounts : 0 ,
} ,
recentBlockhash ,
instructions : [ ] ,
accountKeys : [ payer . publicKey . toBase58 ( ) ] ,
} ) ,
) ;
const response = await connection . simulateTransaction ( versionedTx , {
accounts : {
encoding : 'base64' ,
addresses : [ payer . publicKey . toBase58 ( ) ] ,
} ,
} ) ;
expect ( response . value . err ) . to . be . null ;
expect ( response . value . accounts ) . to . eql ( [
{
data : [ '' , 'base64' ] ,
executable : false ,
lamports : LAMPORTS_PER_SOL - 5000 ,
owner : SystemProgram.programId.toBase58 ( ) ,
rentEpoch : 0 ,
2022-10-20 13:37:55 -07:00
space : 0 ,
2022-09-06 20:53:42 -07:00
} ,
] ) ;
} ) ;
2021-09-16 14:10:28 -07:00
it ( 'simulate transaction with message' , async ( ) = > {
connection . _commitment = 'confirmed' ;
const account1 = Keypair . generate ( ) ;
const account2 = Keypair . generate ( ) ;
await helpers . airdrop ( {
connection ,
address : account1.publicKey ,
amount : LAMPORTS_PER_SOL ,
} ) ;
await helpers . airdrop ( {
connection ,
address : account2.publicKey ,
amount : LAMPORTS_PER_SOL ,
} ) ;
const recentBlockhash = await (
2022-01-27 15:43:01 -08:00
await helpers . latestBlockhash ( { connection } )
2021-09-16 14:10:28 -07:00
) . blockhash ;
const message = new Message ( {
accountKeys : [
account1 . publicKey . toString ( ) ,
account2 . publicKey . toString ( ) ,
'Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo' ,
] ,
header : {
numReadonlySignedAccounts : 1 ,
numReadonlyUnsignedAccounts : 2 ,
numRequiredSignatures : 1 ,
} ,
instructions : [
{
accounts : [ 0 , 1 ] ,
data : bs58.encode ( Buffer . alloc ( 5 ) . fill ( 9 ) ) ,
programIdIndex : 2 ,
} ,
] ,
recentBlockhash ,
} ) ;
const results1 = await connection . simulateTransaction (
message ,
[ account1 ] ,
true ,
) ;
expect ( results1 . value . accounts ) . lengthOf ( 2 ) ;
const results2 = await connection . simulateTransaction (
message ,
[ account1 ] ,
2022-02-20 22:20:11 -08:00
[
account1 . publicKey ,
new PublicKey ( 'Missing111111111111111111111111111111111111' ) ,
] ,
2021-09-16 14:10:28 -07:00
) ;
2022-02-20 22:20:11 -08:00
expect ( results2 . value . accounts ) . lengthOf ( 2 ) ;
if ( results2 . value . accounts ) {
expect ( results2 . value . accounts [ 1 ] ) . to . be . null ;
}
2021-09-16 14:10:28 -07:00
} ) . timeout ( 10000 ) ;
2021-02-05 18:59:00 -08:00
it ( 'transaction' , async ( ) = > {
2021-02-17 16:15:09 -08:00
connection . _commitment = 'confirmed' ;
2020-06-11 00:00:59 -07:00
2021-05-07 01:59:51 -07:00
const accountFrom = Keypair . generate ( ) ;
const accountTo = Keypair . generate ( ) ;
2021-02-05 18:59:00 -08:00
const minimumAmount = await connection . getMinimumBalanceForRentExemption (
0 ,
) ;
2020-06-11 00:00:59 -07:00
2021-02-05 18:59:00 -08:00
await helpers . airdrop ( {
connection ,
address : accountFrom.publicKey ,
amount : minimumAmount + 100010 ,
} ) ;
await helpers . airdrop ( {
connection ,
address : accountTo.publicKey ,
amount : minimumAmount ,
} ) ;
const transaction = new Transaction ( ) . add (
SystemProgram . transfer ( {
fromPubkey : accountFrom.publicKey ,
toPubkey : accountTo.publicKey ,
lamports : 10 ,
} ) ,
) ;
2020-03-26 06:37:45 -07:00
2021-02-05 18:59:00 -08:00
const signature = await sendAndConfirmTransaction (
connection ,
transaction ,
[ accountFrom ] ,
2021-02-17 16:15:09 -08:00
{ preflightCommitment : 'confirmed' } ,
2021-02-05 18:59:00 -08:00
) ;
2019-05-08 09:33:04 -07:00
2021-02-05 18:59:00 -08:00
// Send again and ensure that new blockhash is used
const lastFetch = Date . now ( ) ;
const transaction2 = new Transaction ( ) . add (
SystemProgram . transfer ( {
fromPubkey : accountFrom.publicKey ,
toPubkey : accountTo.publicKey ,
lamports : 10 ,
} ) ,
) ;
2018-08-23 10:52:48 -07:00
2021-02-05 18:59:00 -08:00
const signature2 = await sendAndConfirmTransaction (
connection ,
transaction2 ,
[ accountFrom ] ,
2021-02-17 16:15:09 -08:00
{ preflightCommitment : 'confirmed' } ,
2021-02-05 18:59:00 -08:00
) ;
2018-10-23 19:13:59 -07:00
2021-02-05 18:59:00 -08:00
expect ( signature ) . not . to . eq ( signature2 ) ;
expect ( transaction . recentBlockhash ) . not . to . eq (
transaction2 . recentBlockhash ,
) ;
2018-10-23 19:13:59 -07:00
2021-02-05 18:59:00 -08:00
// Send new transaction and ensure that same blockhash is used
const transaction3 = new Transaction ( ) . add (
SystemProgram . transfer ( {
fromPubkey : accountFrom.publicKey ,
toPubkey : accountTo.publicKey ,
lamports : 9 ,
} ) ,
) ;
2021-02-07 08:57:12 -08:00
await sendAndConfirmTransaction ( connection , transaction3 , [ accountFrom ] , {
2021-02-17 16:15:09 -08:00
preflightCommitment : 'confirmed' ,
2021-02-07 08:57:12 -08:00
} ) ;
2021-02-05 18:59:00 -08:00
expect ( transaction2 . recentBlockhash ) . to . eq ( transaction3 . recentBlockhash ) ;
// Sleep until blockhash cache times out
await sleep (
Math . max (
0 ,
1000 + BLOCKHASH_CACHE_TIMEOUT_MS - ( Date . now ( ) - lastFetch ) ,
) ,
) ;
2018-10-23 19:13:59 -07:00
2021-02-05 18:59:00 -08:00
const transaction4 = new Transaction ( ) . add (
SystemProgram . transfer ( {
fromPubkey : accountFrom.publicKey ,
toPubkey : accountTo.publicKey ,
lamports : 13 ,
} ) ,
) ;
2018-10-23 19:13:59 -07:00
2021-02-05 18:59:00 -08:00
await sendAndConfirmTransaction ( connection , transaction4 , [ accountFrom ] , {
2021-02-17 16:15:09 -08:00
preflightCommitment : 'confirmed' ,
2021-02-05 18:59:00 -08:00
} ) ;
2020-01-09 09:18:14 -08:00
2021-02-05 18:59:00 -08:00
expect ( transaction4 . recentBlockhash ) . not . to . eq (
transaction3 . recentBlockhash ,
) ;
2018-10-23 19:13:59 -07:00
2021-02-05 18:59:00 -08:00
// accountFrom may have less than 100000 due to transaction fees
const balance = await connection . getBalance ( accountFrom . publicKey ) ;
expect ( balance ) . to . be . greaterThan ( 0 ) ;
expect ( balance ) . to . be . at . most ( minimumAmount + 100000 ) ;
expect ( await connection . getBalance ( accountTo . publicKey ) ) . to . eq (
minimumAmount + 42 ,
) ;
} ) . timeout ( 45 * 1000 ) ; // waits 30s for cache timeout
2018-10-23 19:13:59 -07:00
2021-02-05 18:59:00 -08:00
it ( 'multi-instruction transaction' , async ( ) = > {
2021-02-17 16:15:09 -08:00
connection . _commitment = 'confirmed' ;
2020-03-23 08:01:12 -07:00
2021-05-07 01:59:51 -07:00
const accountFrom = Keypair . generate ( ) ;
const accountTo = Keypair . generate ( ) ;
2018-10-23 19:13:59 -07:00
2021-02-05 18:59:00 -08:00
let signature = await connection . requestAirdrop (
accountFrom . publicKey ,
LAMPORTS_PER_SOL ,
) ;
await connection . confirmTransaction ( signature ) ;
expect ( await connection . getBalance ( accountFrom . publicKey ) ) . to . eq (
LAMPORTS_PER_SOL ,
) ;
2019-05-08 09:33:04 -07:00
2021-02-05 18:59:00 -08:00
const minimumAmount = await connection . getMinimumBalanceForRentExemption (
0 ,
) ;
2018-10-23 19:13:59 -07:00
2021-02-05 18:59:00 -08:00
signature = await connection . requestAirdrop (
accountTo . publicKey ,
minimumAmount + 21 ,
) ;
await connection . confirmTransaction ( signature ) ;
expect ( await connection . getBalance ( accountTo . publicKey ) ) . to . eq (
minimumAmount + 21 ,
) ;
2018-10-26 21:37:39 -07:00
2021-02-05 18:59:00 -08:00
// 1. Move(accountFrom, accountTo)
// 2. Move(accountTo, accountFrom)
const transaction = new Transaction ( )
. add (
SystemProgram . transfer ( {
fromPubkey : accountFrom.publicKey ,
toPubkey : accountTo.publicKey ,
lamports : 100 ,
} ) ,
)
. add (
SystemProgram . transfer ( {
fromPubkey : accountTo.publicKey ,
toPubkey : accountFrom.publicKey ,
lamports : 100 ,
} ) ,
) ;
signature = await connection . sendTransaction (
transaction ,
[ accountFrom , accountTo ] ,
{ skipPreflight : true } ,
) ;
2018-10-26 21:37:39 -07:00
2022-05-14 21:54:12 -07:00
await connection . confirmTransaction ( {
blockhash : transaction.recentBlockhash ,
lastValidBlockHeight : transaction.lastValidBlockHeight ,
signature ,
} ) ;
2018-10-26 21:37:39 -07:00
2021-02-05 18:59:00 -08:00
const response = ( await connection . getSignatureStatus ( signature ) ) . value ;
if ( response !== null ) {
expect ( typeof response . slot ) . to . eq ( 'number' ) ;
expect ( response . err ) . to . be . null ;
} else {
expect ( response ) . not . to . be . null ;
}
2018-10-26 21:37:39 -07:00
2021-02-05 18:59:00 -08:00
// accountFrom may have less than LAMPORTS_PER_SOL due to transaction fees
expect (
await connection . getBalance ( accountFrom . publicKey ) ,
) . to . be . greaterThan ( 0 ) ;
expect ( await connection . getBalance ( accountFrom . publicKey ) ) . to . be . at . most (
LAMPORTS_PER_SOL ,
) ;
2019-12-10 23:13:15 -08:00
2021-02-05 18:59:00 -08:00
expect ( await connection . getBalance ( accountTo . publicKey ) ) . to . eq (
minimumAmount + 21 ,
) ;
2020-06-03 04:55:42 -07:00
} ) ;
2018-11-16 19:29:14 -08:00
2022-04-09 18:39:32 -07:00
describe ( 'given an open websocket connection' , ( ) = > {
beforeEach ( async ( ) = > {
// Open the socket connection and wait for it to become pingable.
connection . _rpcWebSocket . connect ( ) ;
// eslint-disable-next-line no-constant-condition
while ( true ) {
try {
await connection . _rpcWebSocket . notify ( 'ping' ) ;
break ;
// eslint-disable-next-line no-empty
2022-05-11 20:32:02 -07:00
} catch ( _err ) { }
2022-04-09 18:39:32 -07:00
await sleep ( 100 ) ;
}
} ) ;
2022-04-09 12:48:58 -07:00
2022-04-09 18:39:32 -07:00
it ( 'account change notification' , async ( ) = > {
const connection = new Connection ( url , 'confirmed' ) ;
const owner = Keypair . generate ( ) ;
let subscriptionId : number | undefined ;
try {
const accountInfoPromise = new Promise < AccountInfo < Buffer > > (
resolve = > {
subscriptionId = connection . onAccountChange (
owner . publicKey ,
resolve ,
'confirmed' ,
) ;
} ,
) ;
connection . requestAirdrop ( owner . publicKey , LAMPORTS_PER_SOL ) ;
const accountInfo = await accountInfoPromise ;
expect ( accountInfo . lamports ) . to . eq ( LAMPORTS_PER_SOL ) ;
expect ( accountInfo . owner . equals ( SystemProgram . programId ) ) . to . be . true ;
} finally {
if ( subscriptionId != null ) {
await connection . removeAccountChangeListener ( subscriptionId ) ;
}
2022-04-09 12:48:58 -07:00
}
2022-04-09 18:39:32 -07:00
} ) ;
2021-02-05 18:59:00 -08:00
2022-04-09 18:39:32 -07:00
it ( 'program account change notification' , async ( ) = > {
connection . _commitment = 'confirmed' ;
2021-02-05 18:59:00 -08:00
2022-04-09 18:39:32 -07:00
const owner = Keypair . generate ( ) ;
const programAccount = Keypair . generate ( ) ;
const balanceNeeded =
await connection . getMinimumBalanceForRentExemption ( 0 ) ;
let subscriptionId : number | undefined ;
try {
const keyedAccountInfoPromise = new Promise < KeyedAccountInfo > (
resolve = > {
subscriptionId = connection . onProgramAccountChange (
SystemProgram . programId ,
resolve ,
) ;
} ,
) ;
2019-12-10 23:13:15 -08:00
2022-04-09 18:39:32 -07:00
await helpers . airdrop ( {
connection ,
address : owner.publicKey ,
amount : LAMPORTS_PER_SOL ,
} ) ;
const transaction = new Transaction ( ) . add (
SystemProgram . transfer ( {
fromPubkey : owner.publicKey ,
toPubkey : programAccount.publicKey ,
lamports : balanceNeeded ,
} ) ,
) ;
await sendAndConfirmTransaction ( connection , transaction , [ owner ] , {
commitment : 'confirmed' ,
} ) ;
const keyedAccountInfo = await keyedAccountInfoPromise ;
2021-02-25 23:06:12 -08:00
if ( keyedAccountInfo . accountId . equals ( programAccount . publicKey ) ) {
2021-02-05 18:59:00 -08:00
expect ( keyedAccountInfo . accountInfo . lamports ) . to . eq ( balanceNeeded ) ;
expect (
keyedAccountInfo . accountInfo . owner . equals (
SystemProgram . programId ,
) ,
) . to . be . true ;
}
2022-04-09 18:39:32 -07:00
} finally {
if ( subscriptionId != null ) {
await connection . removeProgramAccountChangeListener ( subscriptionId ) ;
}
2021-02-05 18:59:00 -08:00
}
} ) ;
2022-04-09 18:39:32 -07:00
it ( 'slot notification' , async ( ) = > {
let subscriptionId : number | undefined ;
try {
const notifiedSlotInfo = await new Promise < SlotInfo > ( resolve = > {
subscriptionId = connection . onSlotChange ( resolve ) ;
} ) ;
expect ( notifiedSlotInfo . parent ) . to . be . at . least ( 0 ) ;
expect ( notifiedSlotInfo . root ) . to . be . at . least ( 0 ) ;
expect ( notifiedSlotInfo . slot ) . to . be . at . least ( 1 ) ;
} finally {
if ( subscriptionId != null ) {
await connection . removeSlotChangeListener ( subscriptionId ) ;
}
2021-02-05 18:59:00 -08:00
}
} ) ;
2022-04-09 18:39:32 -07:00
it ( 'root notification' , async ( ) = > {
let subscriptionId : number | undefined ;
try {
const atLeastTwoRoots = await new Promise < number [ ] > ( resolve = > {
const roots : number [ ] = [ ] ;
subscriptionId = connection . onRootChange ( root = > {
if ( roots . length === 2 ) {
return ;
}
roots . push ( root ) ;
if ( roots . length === 2 ) {
// Collect at least two, then resolve.
resolve ( roots ) ;
}
} ) ;
} ) ;
expect ( atLeastTwoRoots [ 1 ] ) . to . be . greaterThan ( atLeastTwoRoots [ 0 ] ) ;
} finally {
if ( subscriptionId != null ) {
await connection . removeRootChangeListener ( subscriptionId ) ;
}
2021-02-05 18:59:00 -08:00
}
2022-04-09 18:39:32 -07:00
} ) ;
2021-04-04 03:02:36 -07:00
2022-04-09 19:03:29 -07:00
it ( 'signature notification' , async ( ) = > {
const owner = Keypair . generate ( ) ;
const signature = await connection . requestAirdrop (
owner . publicKey ,
LAMPORTS_PER_SOL ,
) ;
const signatureResult = await new Promise < SignatureResult > ( resolve = > {
// NOTE: Signature subscriptions auto-remove themselves, so there's no
// need to track the subscription id and remove it when the test ends.
connection . onSignature ( signature , resolve , 'processed' ) ;
} ) ;
expect ( signatureResult . err ) . to . be . null ;
} ) ;
2022-04-09 18:39:32 -07:00
it ( 'logs notification' , async ( ) = > {
let subscriptionId : number | undefined ;
const owner = Keypair . generate ( ) ;
try {
const logPromise = new Promise < [ Logs , Context ] > ( resolve = > {
subscriptionId = connection . onLogs (
2022-04-08 16:17:21 -07:00
owner . publicKey ,
2022-04-09 18:39:32 -07:00
( logs , ctx ) = > {
if ( ! logs . err ) {
resolve ( [ logs , ctx ] ) ;
}
} ,
'processed' ,
2022-04-08 16:17:21 -07:00
) ;
2022-04-09 18:39:32 -07:00
} ) ;
// Execute a transaction so that we can pickup its logs.
await connection . requestAirdrop ( owner . publicKey , LAMPORTS_PER_SOL ) ;
const [ logsRes , ctx ] = await logPromise ;
expect ( ctx . slot ) . to . be . greaterThan ( 0 ) ;
expect ( logsRes . logs . length ) . to . eq ( 2 ) ;
expect ( logsRes . logs [ 0 ] ) . to . eq (
'Program 11111111111111111111111111111111 invoke [1]' ,
) ;
expect ( logsRes . logs [ 1 ] ) . to . eq (
'Program 11111111111111111111111111111111 success' ,
) ;
} finally {
if ( subscriptionId != null ) {
await connection . removeOnLogsListener ( subscriptionId ) ;
2021-04-04 03:02:36 -07:00
}
2022-04-09 18:39:32 -07:00
}
2021-03-23 20:05:17 -07:00
} ) ;
2022-04-09 18:39:32 -07:00
} ) ;
2021-03-23 20:05:17 -07:00
2021-02-05 18:59:00 -08:00
it ( 'https request' , async ( ) = > {
2021-03-25 02:18:00 -07:00
const connection = new Connection ( 'https://api.mainnet-beta.solana.com' ) ;
2021-02-05 18:59:00 -08:00
const version = await connection . getVersion ( ) ;
expect ( version [ 'solana-core' ] ) . to . be . ok ;
2022-01-21 13:01:48 -08:00
} ) . timeout ( 20 * 1000 ) ;
2022-08-14 03:11:49 -07:00
2022-08-31 05:46:24 -07:00
let lookupTableKey : PublicKey ;
const lookupTableAddresses = new Array ( 10 )
. fill ( 0 )
. map ( ( ) = > Keypair . generate ( ) . publicKey ) ;
describe ( 'address lookup table program' , ( ) = > {
const connection = new Connection ( url ) ;
2022-08-14 03:11:49 -07:00
const payer = Keypair . generate ( ) ;
2022-08-31 05:46:24 -07:00
before ( async ( ) = > {
await helpers . airdrop ( {
connection ,
address : payer.publicKey ,
amount : 10 * LAMPORTS_PER_SOL ,
} ) ;
2022-08-14 03:11:49 -07:00
} ) ;
2022-08-31 05:46:24 -07:00
it ( 'createLookupTable' , async ( ) = > {
const recentSlot = await connection . getSlot ( 'finalized' ) ;
let createIx : TransactionInstruction ;
[ createIx , lookupTableKey ] =
AddressLookupTableProgram . createLookupTable ( {
recentSlot ,
payer : payer.publicKey ,
authority : payer.publicKey ,
} ) ;
2022-08-14 03:11:49 -07:00
2022-08-31 05:46:24 -07:00
await helpers . processTransaction ( {
connection ,
transaction : new Transaction ( ) . add ( createIx ) ,
signers : [ payer ] ,
commitment : 'processed' ,
2022-08-14 03:11:49 -07:00
} ) ;
2022-08-31 05:46:24 -07:00
} ) ;
2022-08-14 03:11:49 -07:00
2022-08-31 05:46:24 -07:00
it ( 'extendLookupTable' , async ( ) = > {
const transaction = new Transaction ( ) . add (
2022-08-14 03:11:49 -07:00
AddressLookupTableProgram . extendLookupTable ( {
lookupTable : lookupTableKey ,
addresses : lookupTableAddresses ,
authority : payer.publicKey ,
payer : payer.publicKey ,
} ) ,
) ;
2022-08-31 05:46:24 -07:00
2022-08-14 03:11:49 -07:00
await helpers . processTransaction ( {
connection ,
transaction ,
signers : [ payer ] ,
commitment : 'processed' ,
} ) ;
2022-08-31 05:46:24 -07:00
} ) ;
2022-08-14 03:11:49 -07:00
2022-08-31 05:46:24 -07:00
it ( 'freezeLookupTable' , async ( ) = > {
2022-08-14 03:11:49 -07:00
const transaction = new Transaction ( ) . add (
AddressLookupTableProgram . freezeLookupTable ( {
lookupTable : lookupTableKey ,
authority : payer.publicKey ,
} ) ,
) ;
2022-08-31 05:46:24 -07:00
2022-08-14 03:11:49 -07:00
await helpers . processTransaction ( {
connection ,
transaction ,
signers : [ payer ] ,
commitment : 'processed' ,
} ) ;
2022-08-31 05:46:24 -07:00
} ) ;
2022-08-14 03:11:49 -07:00
2022-08-31 05:46:24 -07:00
it ( 'getAddressLookupTable' , async ( ) = > {
2022-08-14 03:11:49 -07:00
const lookupTableResponse = await connection . getAddressLookupTable (
lookupTableKey ,
{
commitment : 'processed' ,
} ,
) ;
const lookupTableAccount = lookupTableResponse . value ;
if ( ! lookupTableAccount ) {
expect ( lookupTableAccount ) . to . be . ok ;
return ;
}
expect ( lookupTableAccount . isActive ( ) ) . to . be . true ;
expect ( lookupTableAccount . state . authority ) . to . be . undefined ;
2022-08-31 05:46:24 -07:00
expect ( lookupTableAccount . state . addresses ) . to . eql ( lookupTableAddresses ) ;
} ) ;
2022-08-14 03:11:49 -07:00
} ) ;
2022-08-25 06:42:54 -07:00
2022-08-31 05:46:24 -07:00
describe ( 'v0 transaction' , ( ) = > {
const connection = new Connection ( url ) ;
2022-08-25 06:42:54 -07:00
const payer = Keypair . generate ( ) ;
2022-08-31 05:46:24 -07:00
before ( async ( ) = > {
await helpers . airdrop ( {
2022-08-25 06:42:54 -07:00
connection ,
2022-08-31 05:46:24 -07:00
address : payer.publicKey ,
amount : 10 * LAMPORTS_PER_SOL ,
2022-08-25 06:42:54 -07:00
} ) ;
2022-08-31 05:46:24 -07:00
} ) ;
2022-08-25 06:42:54 -07:00
2022-08-31 05:46:24 -07:00
// wait for lookup table to be usable
before ( async ( ) = > {
2022-08-25 06:42:54 -07:00
const lookupTableResponse = await connection . getAddressLookupTable (
lookupTableKey ,
{
commitment : 'processed' ,
} ,
) ;
2022-08-31 05:46:24 -07:00
2022-08-25 06:42:54 -07:00
const lookupTableAccount = lookupTableResponse . value ;
if ( ! lookupTableAccount ) {
expect ( lookupTableAccount ) . to . be . ok ;
return ;
}
// eslint-disable-next-line no-constant-condition
while ( true ) {
2022-08-31 05:46:24 -07:00
const latestSlot = await connection . getSlot ( 'confirmed' ) ;
2022-08-25 06:42:54 -07:00
if ( latestSlot > lookupTableAccount . state . lastExtendedSlot ) {
break ;
} else {
console . log ( 'Waiting for next slot...' ) ;
await sleep ( 500 ) ;
}
}
2022-08-31 05:46:24 -07:00
} ) ;
2022-08-25 06:42:54 -07:00
2022-08-31 05:46:24 -07:00
let signature ;
let addressTableLookups ;
it ( 'send and confirm' , async ( ) = > {
2022-08-25 06:42:54 -07:00
const { blockhash , lastValidBlockHeight } =
await connection . getLatestBlockhash ( ) ;
const transferIxData = encodeData ( SYSTEM_INSTRUCTION_LAYOUTS . Transfer , {
lamports : BigInt ( LAMPORTS_PER_SOL ) ,
} ) ;
2022-08-31 05:46:24 -07:00
addressTableLookups = [
{
accountKey : lookupTableKey ,
writableIndexes : [ 0 ] ,
readonlyIndexes : [ ] ,
} ,
] ;
2022-08-25 06:42:54 -07:00
const transaction = new VersionedTransaction (
new MessageV0 ( {
header : {
numRequiredSignatures : 1 ,
numReadonlySignedAccounts : 0 ,
numReadonlyUnsignedAccounts : 1 ,
} ,
staticAccountKeys : [ payer . publicKey , SystemProgram . programId ] ,
recentBlockhash : blockhash ,
compiledInstructions : [
{
programIdIndex : 1 ,
accountKeyIndexes : [ 0 , 2 ] ,
data : transferIxData ,
} ,
] ,
2022-08-31 05:46:24 -07:00
addressTableLookups ,
2022-08-25 06:42:54 -07:00
} ) ,
) ;
transaction . sign ( [ payer ] ) ;
2022-08-31 05:46:24 -07:00
signature = bs58 . encode ( transaction . signatures [ 0 ] ) ;
2022-08-25 06:42:54 -07:00
const serializedTransaction = transaction . serialize ( ) ;
await connection . sendRawTransaction ( serializedTransaction , {
2022-08-31 05:46:24 -07:00
preflightCommitment : 'confirmed' ,
2022-08-25 06:42:54 -07:00
} ) ;
await connection . confirmTransaction (
{
signature ,
blockhash ,
lastValidBlockHeight ,
} ,
2022-08-31 05:46:24 -07:00
'confirmed' ,
2022-08-25 06:42:54 -07:00
) ;
const transferToKey = lookupTableAddresses [ 0 ] ;
const transferToAccount = await connection . getAccountInfo (
transferToKey ,
2022-10-13 20:28:00 -07:00
{ commitment : 'confirmed' , dataSlice : { length : 0 , offset : 0 } } ,
2022-08-25 06:42:54 -07:00
) ;
2022-10-13 20:28:00 -07:00
expect ( transferToAccount ? . data . length ) . to . be . eq ( 0 ) ;
2022-08-25 06:42:54 -07:00
expect ( transferToAccount ? . lamports ) . to . be . eq ( LAMPORTS_PER_SOL ) ;
2022-08-31 05:46:24 -07:00
} ) ;
it ( 'getTransaction (failure)' , async ( ) = > {
await expect (
connection . getTransaction ( signature , {
commitment : 'confirmed' ,
} ) ,
) . to . be . rejectedWith (
'failed to get transaction: Transaction version (0) is not supported' ,
) ;
} ) ;
let transactionSlot ;
it ( 'getTransaction' , async ( ) = > {
// fetch v0 transaction
const fetchedTransaction = await connection . getTransaction ( signature , {
commitment : 'confirmed' ,
maxSupportedTransactionVersion : 0 ,
} ) ;
if ( fetchedTransaction === null ) {
expect ( fetchedTransaction ) . to . not . be . null ;
return ;
}
transactionSlot = fetchedTransaction . slot ;
expect ( fetchedTransaction . version ) . to . eq ( 0 ) ;
expect ( fetchedTransaction . meta ? . loadedAddresses ) . to . eql ( {
readonly : [ ] ,
writable : [ lookupTableAddresses [ 0 ] ] ,
} ) ;
2022-09-01 11:18:43 -07:00
expect ( fetchedTransaction . meta ? . computeUnitsConsumed ) . to . not . be
. undefined ;
2022-08-31 05:46:24 -07:00
expect (
fetchedTransaction . transaction . message . addressTableLookups ,
) . to . eql ( addressTableLookups ) ;
} ) ;
it ( 'getParsedTransaction (failure)' , async ( ) = > {
await expect (
connection . getParsedTransaction ( signature , {
commitment : 'confirmed' ,
} ) ,
) . to . be . rejectedWith (
'failed to get transaction: Transaction version (0) is not supported' ,
) ;
} ) ;
it ( 'getParsedTransaction' , async ( ) = > {
const parsedTransaction = await connection . getParsedTransaction (
signature ,
{
commitment : 'confirmed' ,
maxSupportedTransactionVersion : 0 ,
} ,
) ;
expect ( parsedTransaction ) . to . not . be . null ;
expect ( parsedTransaction ? . version ) . to . eq ( 0 ) ;
2022-09-09 14:06:54 -07:00
// loaded addresses are not returned for parsed transactions
expect ( parsedTransaction ? . meta ? . loadedAddresses ) . to . be . undefined ;
2022-09-01 11:18:43 -07:00
expect ( parsedTransaction ? . meta ? . computeUnitsConsumed ) . to . not . be
. undefined ;
2022-08-31 05:46:24 -07:00
expect (
parsedTransaction ? . transaction . message . addressTableLookups ,
) . to . eql ( addressTableLookups ) ;
2022-09-09 14:06:54 -07:00
expect ( parsedTransaction ? . transaction . message . accountKeys ) . to . eql ( [
{
pubkey : payer.publicKey ,
signer : true ,
writable : true ,
source : 'transaction' ,
} ,
{
pubkey : SystemProgram.programId ,
signer : false ,
writable : false ,
source : 'transaction' ,
} ,
{
pubkey : lookupTableAddresses [ 0 ] ,
signer : false ,
writable : true ,
source : 'lookupTable' ,
} ,
] ) ;
2022-08-31 05:46:24 -07:00
} ) ;
it ( 'getBlock (failure)' , async ( ) = > {
await expect (
connection . getBlock ( transactionSlot , {
maxSupportedTransactionVersion : undefined ,
commitment : 'confirmed' ,
} ) ,
) . to . be . rejectedWith (
'failed to get confirmed block: Transaction version (0) is not supported' ,
) ;
} ) ;
it ( 'getBlock' , async ( ) = > {
const block = await connection . getBlock ( transactionSlot , {
maxSupportedTransactionVersion : 0 ,
commitment : 'confirmed' ,
} ) ;
expect ( block ) . to . not . be . null ;
if ( block === null ) throw new Error ( ) ; // unreachable
let foundTx = false ;
for ( const tx of block . transactions ) {
if ( tx . transaction . signatures [ 0 ] === signature ) {
foundTx = true ;
expect ( tx . version ) . to . eq ( 0 ) ;
}
}
expect ( foundTx ) . to . be . true ;
} ) ;
2022-10-11 01:13:10 -07:00
it ( 'getParsedBlock' , async ( ) = > {
const block = await connection . getParsedBlock ( transactionSlot , {
maxSupportedTransactionVersion : 0 ,
commitment : 'confirmed' ,
} ) ;
expect ( block ) . to . not . be . null ;
if ( block === null ) throw new Error ( ) ; // unreachable
let foundTx = false ;
for ( const tx of block . transactions ) {
if ( tx . transaction . signatures [ 0 ] === signature ) {
foundTx = true ;
expect ( tx . version ) . to . eq ( 0 ) ;
}
}
expect ( foundTx ) . to . be . true ;
} ) ;
2022-08-31 05:46:24 -07:00
} ) . timeout ( 5 * 1000 ) ;
2020-10-06 09:41:18 -07:00
}
} ) ;