fix: repair web3 connection tests by making fewer assumptions about the existence of particular blocks (#23921)
* fix: repair 'get confirmed signatures for address' test in web3.js * fix: repair 'get signatures for address' test in web3.js * fix: repair 'get parsed confirmed transactions' test in web3.js * fix: repair 'get transaction' test in web3.js * fix: repair 'get confirmed transaction' test in web3.js * fix: repair 'get block' test in web3.js * fix: repair 'get confirmed block' test in web3.js * fix: repair 'get block signatures' test in web3.js * fix: repair 'get block time' test in web3.js Co-authored-by: steveluscher <github@steveluscher.com>
This commit is contained in:
parent
c8c3c4359f
commit
412d9be445
|
@ -24,7 +24,10 @@ import {DEFAULT_TICKS_PER_SLOT, NUM_TICKS_PER_SECOND} from '../src/timing';
|
|||
import {MOCK_PORT, url} from './url';
|
||||
import {
|
||||
BLOCKHASH_CACHE_TIMEOUT_MS,
|
||||
BlockResponse,
|
||||
BlockSignatures,
|
||||
Commitment,
|
||||
ConfirmedBlock,
|
||||
EpochInfo,
|
||||
InflationGovernor,
|
||||
SlotInfo,
|
||||
|
@ -71,7 +74,7 @@ const verifySignatureStatus = (
|
|||
return status;
|
||||
};
|
||||
|
||||
describe('Connection', () => {
|
||||
describe('Connection', function () {
|
||||
let connection: Connection;
|
||||
beforeEach(() => {
|
||||
connection = new Connection(url);
|
||||
|
@ -999,12 +1002,17 @@ describe('Connection', () => {
|
|||
},
|
||||
});
|
||||
|
||||
// Find a block that has a transaction, usually Block 1
|
||||
let slot = 0;
|
||||
// Find a block that has a transaction.
|
||||
await mockRpcResponse({
|
||||
method: 'getFirstAvailableBlock',
|
||||
params: [],
|
||||
value: 1,
|
||||
});
|
||||
let slot = await connection.getFirstAvailableBlock();
|
||||
|
||||
let address: PublicKey | undefined;
|
||||
let expectedSignature: string | undefined;
|
||||
while (!address || !expectedSignature) {
|
||||
slot++;
|
||||
const block = await connection.getConfirmedBlock(slot);
|
||||
if (block.transactions.length > 0) {
|
||||
const {signature, publicKey} =
|
||||
|
@ -1012,8 +1020,10 @@ describe('Connection', () => {
|
|||
if (signature) {
|
||||
address = publicKey;
|
||||
expectedSignature = bs58.encode(signature);
|
||||
break;
|
||||
}
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
|
||||
// getConfirmedSignaturesForAddress tests...
|
||||
|
@ -1174,12 +1184,17 @@ describe('Connection', () => {
|
|||
},
|
||||
});
|
||||
|
||||
// Find a block that has a transaction, usually Block 1
|
||||
let slot = 0;
|
||||
// Find a block that has a transaction.
|
||||
await mockRpcResponse({
|
||||
method: 'getFirstAvailableBlock',
|
||||
params: [],
|
||||
value: 1,
|
||||
});
|
||||
let slot = await connection.getFirstAvailableBlock();
|
||||
|
||||
let address: PublicKey | undefined;
|
||||
let expectedSignature: string | undefined;
|
||||
while (!address || !expectedSignature) {
|
||||
slot++;
|
||||
const block = await connection.getConfirmedBlock(slot);
|
||||
if (block.transactions.length > 0) {
|
||||
const {signature, publicKey} =
|
||||
|
@ -1187,8 +1202,10 @@ describe('Connection', () => {
|
|||
if (signature) {
|
||||
address = publicKey;
|
||||
expectedSignature = bs58.encode(signature);
|
||||
break;
|
||||
}
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
|
||||
// getSignaturesForAddress tests...
|
||||
|
@ -1278,17 +1295,24 @@ describe('Connection', () => {
|
|||
},
|
||||
});
|
||||
|
||||
// Find a block that has a transaction, usually Block 1
|
||||
let slot = 0;
|
||||
// Find a block that has a transaction.
|
||||
await mockRpcResponse({
|
||||
method: 'getFirstAvailableBlock',
|
||||
params: [],
|
||||
value: 1,
|
||||
});
|
||||
let slot = await connection.getFirstAvailableBlock();
|
||||
|
||||
let confirmedTransaction: string | undefined;
|
||||
while (!confirmedTransaction) {
|
||||
slot++;
|
||||
const block = await connection.getConfirmedBlock(slot);
|
||||
for (const tx of block.transactions) {
|
||||
if (tx.transaction.signature) {
|
||||
confirmedTransaction = bs58.encode(tx.transaction.signature);
|
||||
break;
|
||||
}
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
|
||||
await mockRpcBatchResponse({
|
||||
|
@ -1551,15 +1575,22 @@ describe('Connection', () => {
|
|||
},
|
||||
});
|
||||
|
||||
// Find a block that has a transaction, usually Block 1
|
||||
let slot = 0;
|
||||
// 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) {
|
||||
slot++;
|
||||
const block = await connection.getBlock(slot);
|
||||
if (block && block.transactions.length > 0) {
|
||||
transaction = block.transactions[0].transaction.signatures[0];
|
||||
continue;
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
|
||||
await mockRpcResponse({
|
||||
|
@ -1694,17 +1725,24 @@ describe('Connection', () => {
|
|||
},
|
||||
});
|
||||
|
||||
// Find a block that has a transaction, usually Block 1
|
||||
let slot = 0;
|
||||
// Find a block that has a transaction.
|
||||
await mockRpcResponse({
|
||||
method: 'getFirstAvailableBlock',
|
||||
params: [],
|
||||
value: 1,
|
||||
});
|
||||
let slot = await connection.getFirstAvailableBlock();
|
||||
|
||||
let confirmedTransaction: string | undefined;
|
||||
while (!confirmedTransaction) {
|
||||
slot++;
|
||||
const block = await connection.getConfirmedBlock(slot);
|
||||
for (const tx of block.transactions) {
|
||||
if (tx.transaction.signature) {
|
||||
confirmedTransaction = bs58.encode(tx.transaction.signature);
|
||||
break;
|
||||
}
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
|
||||
await mockRpcResponse({
|
||||
|
@ -1885,243 +1923,339 @@ describe('Connection', () => {
|
|||
});
|
||||
}
|
||||
|
||||
it('get block', async () => {
|
||||
await mockRpcResponse({
|
||||
method: 'getSlot',
|
||||
params: [],
|
||||
value: 1,
|
||||
describe('get block', function () {
|
||||
beforeEach(async function () {
|
||||
await mockRpcResponse({
|
||||
method: 'getSlot',
|
||||
params: [],
|
||||
value: 1,
|
||||
});
|
||||
|
||||
while ((await connection.getSlot()) <= 0) {
|
||||
continue;
|
||||
}
|
||||
});
|
||||
|
||||
while ((await connection.getSlot()) <= 0) {
|
||||
continue;
|
||||
}
|
||||
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: [],
|
||||
},
|
||||
});
|
||||
|
||||
await mockRpcResponse({
|
||||
method: 'getBlock',
|
||||
params: [0],
|
||||
value: {
|
||||
blockHeight: 0,
|
||||
blockTime: 1614281964,
|
||||
blockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo',
|
||||
previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo',
|
||||
parentSlot: 0,
|
||||
transactions: [],
|
||||
},
|
||||
});
|
||||
|
||||
// Block 0 never has any transactions in test validator
|
||||
const block0 = await connection.getBlock(0);
|
||||
if (!block0) {
|
||||
expect(block0).not.to.be.null;
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
// Compare data with parent
|
||||
let x = 1;
|
||||
while (x < 10) {
|
||||
const block1 = await connection.getBlock(x);
|
||||
if (block1 && block1.transactions.length >= 1) {
|
||||
if (block1.parentSlot == 0) {
|
||||
expect(block1.previousBlockhash).to.eq(blockhash0);
|
||||
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 {
|
||||
const parentBlock = await connection.getBlock(block1.parentSlot);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
expect(maybeBlock0).not.to.be.null;
|
||||
const block0 = maybeBlock0!;
|
||||
|
||||
// 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,
|
||||
},
|
||||
instructions: [
|
||||
{
|
||||
accounts: [1, 2, 3],
|
||||
data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7',
|
||||
programIdIndex: 4,
|
||||
},
|
||||
],
|
||||
recentBlockhash:
|
||||
'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE',
|
||||
},
|
||||
signatures: [
|
||||
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt',
|
||||
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
// 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);
|
||||
if (parentBlock) {
|
||||
expect(block1.previousBlockhash).to.eq(parentBlock.blockhash);
|
||||
result = {blockWithTransaction: candidateBlock, parentBlock};
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(block1.blockhash).not.to.be.null;
|
||||
expect(block1.transactions[0].transaction).not.to.be.null;
|
||||
break;
|
||||
candidateSlot++;
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
await mockRpcResponse({
|
||||
method: 'getBlock',
|
||||
params: [Number.MAX_SAFE_INTEGER],
|
||||
error: {
|
||||
message: `Block not available for slot ${Number.MAX_SAFE_INTEGER}`,
|
||||
},
|
||||
// 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}`,
|
||||
);
|
||||
});
|
||||
await expect(
|
||||
connection.getBlock(Number.MAX_SAFE_INTEGER),
|
||||
).to.be.rejectedWith(
|
||||
`Block not available for slot ${Number.MAX_SAFE_INTEGER}`,
|
||||
);
|
||||
});
|
||||
|
||||
it('get confirmed block', async () => {
|
||||
await mockRpcResponse({
|
||||
method: 'getSlot',
|
||||
params: [],
|
||||
value: 1,
|
||||
describe('get confirmed block', function () {
|
||||
beforeEach(async function () {
|
||||
await mockRpcResponse({
|
||||
method: 'getSlot',
|
||||
params: [],
|
||||
value: 1,
|
||||
});
|
||||
|
||||
while ((await connection.getSlot()) <= 0) {
|
||||
continue;
|
||||
}
|
||||
});
|
||||
|
||||
while ((await connection.getSlot()) <= 0) {
|
||||
continue;
|
||||
}
|
||||
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: [],
|
||||
},
|
||||
});
|
||||
|
||||
await mockRpcResponse({
|
||||
method: 'getConfirmedBlock',
|
||||
params: [0],
|
||||
value: {
|
||||
blockTime: 1614281964,
|
||||
blockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo',
|
||||
previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo',
|
||||
parentSlot: 0,
|
||||
transactions: [],
|
||||
},
|
||||
});
|
||||
|
||||
// Block 0 never has any transactions in test validator
|
||||
const block0 = await connection.getConfirmedBlock(0);
|
||||
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);
|
||||
|
||||
await mockRpcResponse({
|
||||
method: 'getConfirmedBlock',
|
||||
params: [1],
|
||||
value: {
|
||||
blockTime: 1614281964,
|
||||
blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy',
|
||||
previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo',
|
||||
parentSlot: 0,
|
||||
transactions: [
|
||||
{
|
||||
meta: {
|
||||
fee: 10000,
|
||||
postBalances: [499260347380, 15298080, 1, 1, 1],
|
||||
preBalances: [499260357380, 15298080, 1, 1, 1],
|
||||
status: {Ok: null},
|
||||
err: null,
|
||||
},
|
||||
transaction: {
|
||||
message: {
|
||||
accountKeys: [
|
||||
'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf',
|
||||
'57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy',
|
||||
'SysvarS1otHashes111111111111111111111111111',
|
||||
'SysvarC1ock11111111111111111111111111111111',
|
||||
'Vote111111111111111111111111111111111111111',
|
||||
],
|
||||
header: {
|
||||
numReadonlySignedAccounts: 0,
|
||||
numReadonlyUnsignedAccounts: 3,
|
||||
numRequiredSignatures: 2,
|
||||
},
|
||||
instructions: [
|
||||
{
|
||||
accounts: [1, 2, 3],
|
||||
data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7',
|
||||
programIdIndex: 4,
|
||||
},
|
||||
],
|
||||
recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE',
|
||||
},
|
||||
signatures: [
|
||||
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt',
|
||||
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
// Find a block that has a transaction
|
||||
// Compare data with parent
|
||||
let x = 1;
|
||||
while (x < 10) {
|
||||
const block1 = await connection.getConfirmedBlock(x);
|
||||
if (block1.transactions.length >= 1) {
|
||||
if (block1.parentSlot == 0) {
|
||||
expect(block1.previousBlockhash).to.eq(blockhash0);
|
||||
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 {
|
||||
const parentBlock = await connection.getBlock(block1.parentSlot);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// 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: '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,
|
||||
},
|
||||
instructions: [
|
||||
{
|
||||
accounts: [1, 2, 3],
|
||||
data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7',
|
||||
programIdIndex: 4,
|
||||
},
|
||||
],
|
||||
recentBlockhash:
|
||||
'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE',
|
||||
},
|
||||
signatures: [
|
||||
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt',
|
||||
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
// 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,
|
||||
);
|
||||
if (parentBlock) {
|
||||
expect(block1.previousBlockhash).to.eq(parentBlock.blockhash);
|
||||
result = {blockWithTransaction: candidateBlock, parentBlock};
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(block1.blockhash).not.to.be.null;
|
||||
expect(block1.transactions[0].transaction).not.to.be.null;
|
||||
break;
|
||||
candidateSlot++;
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
await mockRpcResponse({
|
||||
method: 'getConfirmedBlock',
|
||||
params: [Number.MAX_SAFE_INTEGER],
|
||||
error: {
|
||||
message: `Block not available for slot ${Number.MAX_SAFE_INTEGER}`,
|
||||
},
|
||||
// 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}`,
|
||||
);
|
||||
});
|
||||
await expect(
|
||||
connection.getConfirmedBlock(Number.MAX_SAFE_INTEGER),
|
||||
).to.be.rejectedWith(
|
||||
`Block not available for slot ${Number.MAX_SAFE_INTEGER}`,
|
||||
);
|
||||
});
|
||||
|
||||
it('get blocks between two slots', async () => {
|
||||
|
@ -2172,101 +2306,156 @@ describe('Connection', () => {
|
|||
expect(blocks).to.contain(latestSlot);
|
||||
});
|
||||
|
||||
it('get block signatures', async () => {
|
||||
await mockRpcResponse({
|
||||
method: 'getSlot',
|
||||
params: [],
|
||||
value: 1,
|
||||
describe('get block signatures', function () {
|
||||
beforeEach(async function () {
|
||||
await mockRpcResponse({
|
||||
method: 'getSlot',
|
||||
params: [],
|
||||
value: 1,
|
||||
});
|
||||
|
||||
while ((await connection.getSlot()) <= 0) {
|
||||
continue;
|
||||
}
|
||||
});
|
||||
|
||||
while ((await connection.getSlot()) <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await mockRpcResponse({
|
||||
method: 'getBlock',
|
||||
params: [
|
||||
0,
|
||||
{
|
||||
transactionDetails: 'signatures',
|
||||
rewards: false,
|
||||
},
|
||||
],
|
||||
value: {
|
||||
blockHeight: 0,
|
||||
blockTime: 1614281964,
|
||||
blockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo',
|
||||
previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo',
|
||||
parentSlot: 0,
|
||||
signatures: [],
|
||||
},
|
||||
});
|
||||
|
||||
// Block 0 never has any transactions in test validator
|
||||
const block0 = await connection.getBlockSignatures(0);
|
||||
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');
|
||||
|
||||
await mockRpcResponse({
|
||||
method: 'getBlock',
|
||||
params: [
|
||||
1,
|
||||
{
|
||||
transactionDetails: 'signatures',
|
||||
rewards: false,
|
||||
},
|
||||
],
|
||||
value: {
|
||||
blockHeight: 1,
|
||||
blockTime: 1614281964,
|
||||
blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy',
|
||||
previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo',
|
||||
parentSlot: 0,
|
||||
signatures: [
|
||||
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt',
|
||||
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG',
|
||||
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: [],
|
||||
},
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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');
|
||||
});
|
||||
|
||||
// Find a block that has a transaction
|
||||
// Compare data with parent
|
||||
let x = 1;
|
||||
while (x < 10) {
|
||||
const block1 = await connection.getBlockSignatures(x);
|
||||
if (block1.signatures.length >= 1) {
|
||||
if (block1.parentSlot == 0) {
|
||||
expect(block1.previousBlockhash).to.eq(blockhash0);
|
||||
} else {
|
||||
const parentBlock = await connection.getBlock(block1.parentSlot);
|
||||
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: [],
|
||||
},
|
||||
});
|
||||
// Mock block with transaction.
|
||||
await mockRpcResponse({
|
||||
method: 'getBlock',
|
||||
params: [
|
||||
1,
|
||||
{
|
||||
transactionDetails: 'signatures',
|
||||
rewards: false,
|
||||
},
|
||||
],
|
||||
value: {
|
||||
blockHeight: 1,
|
||||
blockTime: 1614281964,
|
||||
blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy',
|
||||
previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo',
|
||||
parentSlot: 0,
|
||||
signatures: [
|
||||
'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt',
|
||||
'4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG',
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
// 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,
|
||||
);
|
||||
if (parentBlock) {
|
||||
expect(block1.previousBlockhash).to.eq(parentBlock.blockhash);
|
||||
result = {blockWithTransaction: candidateBlock, parentBlock};
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(block1.blockhash).not.to.be.null;
|
||||
expect(block1.signatures[0]).not.to.be.null;
|
||||
expect(block1).to.not.have.property('rewards');
|
||||
break;
|
||||
candidateSlot++;
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
await mockRpcResponse({
|
||||
method: 'getBlock',
|
||||
params: [Number.MAX_SAFE_INTEGER],
|
||||
error: {
|
||||
message: `Block not available for slot ${Number.MAX_SAFE_INTEGER}`,
|
||||
},
|
||||
// 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}`,
|
||||
);
|
||||
});
|
||||
await expect(
|
||||
connection.getBlockSignatures(Number.MAX_SAFE_INTEGER),
|
||||
).to.be.rejectedWith(
|
||||
`Block not available for slot ${Number.MAX_SAFE_INTEGER}`,
|
||||
);
|
||||
});
|
||||
|
||||
it('get recent blockhash', async () => {
|
||||
|
@ -2355,7 +2544,13 @@ describe('Connection', () => {
|
|||
value: 10000,
|
||||
});
|
||||
|
||||
const blockTime = await connection.getBlockTime(1);
|
||||
await mockRpcResponse({
|
||||
method: 'getFirstAvailableBlock',
|
||||
params: [],
|
||||
value: 1,
|
||||
});
|
||||
const slot = await connection.getFirstAvailableBlock();
|
||||
const blockTime = await connection.getBlockTime(slot);
|
||||
if (blockTime === null) {
|
||||
expect(blockTime).not.to.be.null;
|
||||
} else {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue