fix: get abi for all tx queries

* chore: refactor abi column into helper

* fix: extend microblock tests

* fix: block txs

* chore: block with metadata

* chore: get tx strict

* chore: search

* chore: search principal

* chore: fixme, not todo

* fix: remove count

* fix: comma typo

* chore: block txs rows

* chore: tx search

* chore: get block from data store

* chore: get txs from block
This commit is contained in:
Rafael Cárdenas
2021-12-13 11:30:00 -06:00
committed by GitHub
parent ca1220c02b
commit 7d5940d20e
3 changed files with 290 additions and 114 deletions

View File

@@ -302,11 +302,6 @@ const MEMPOOL_TX_COLUMNS = `
coinbase_payload
`;
const MEMPOOL_TX_ID_COLUMNS = `
-- required columns
tx_id
`;
const BLOCK_COLUMNS = `
block_hash, index_block_hash,
parent_index_block_hash, parent_block_hash, parent_microblock_hash, parent_microblock_sequence,
@@ -322,6 +317,24 @@ const MICROBLOCK_COLUMNS = `
index_block_hash, block_hash
`;
/**
* Shorthand function that returns a column query to retrieve the smart contract abi when querying transactions
* that may be of type `contract_call`. Usually used alongside `TX_COLUMNS` or `MEMPOOL_TX_COLUMNS`.
* @param tableName - Name of the table that will determine the transaction type.
* @returns `string` - abi column select statement portion
*/
function abiColumn(tableName: string = 'txs'): string {
return `
CASE WHEN ${tableName}.type_id = ${DbTxTypeId.ContractCall} THEN (
SELECT abi
FROM smart_contracts
WHERE smart_contracts.contract_id = ${tableName}.contract_call_contract_id
ORDER BY abi != 'null' DESC, canonical DESC, microblock_canonical DESC, block_height DESC
LIMIT 1
) END as abi
`;
}
interface BlockQueryResult {
block_hash: Buffer;
index_block_hash: Buffer;
@@ -1690,9 +1703,9 @@ export class PgDataStore
// Get transactions that have been streamed in microblocks but not yet accepted or rejected in an anchor block.
const { blockHeight } = await this.getChainTip(client);
const unanchoredBlockHeight = blockHeight + 1;
const query = await client.query<TxQueryResult>(
const query = await client.query<ContractTxQueryResult>(
`
SELECT ${TX_COLUMNS}
SELECT ${TX_COLUMNS}, ${abiColumn()}
FROM txs
WHERE canonical = true AND microblock_canonical = true AND block_height = $1
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
@@ -2574,9 +2587,9 @@ export class PgDataStore
let microblocksAccepted: DbMicroblock[] | null = null;
let microblocksStreamed: DbMicroblock[] | null = null;
if (metadata?.txs) {
const txQuery = await client.query<TxQueryResult>(
const txQuery = await client.query<ContractTxQueryResult>(
`
SELECT ${TX_COLUMNS}
SELECT ${TX_COLUMNS}, ${abiColumn()}
FROM txs
WHERE index_block_hash = $1
ORDER BY microblock_sequence DESC, tx_index DESC
@@ -2833,9 +2846,9 @@ export class PgDataStore
async getBlockTxsRows(blockHash: string) {
return this.query(async client => {
const result = await client.query<TxQueryResult>(
const result = await client.query<ContractTxQueryResult>(
`
SELECT ${TX_COLUMNS}
SELECT ${TX_COLUMNS}, ${abiColumn()}
FROM txs
WHERE block_hash = $1 AND canonical = true AND microblock_canonical = true
`,
@@ -2969,10 +2982,9 @@ export class PgDataStore
`,
[hexToBuffer(blockQuery.result.index_block_hash)]
);
const result = await client.query<TxQueryResult>(
const result = await client.query<ContractTxQueryResult>(
`
SELECT ${TX_COLUMNS}
SELECT ${TX_COLUMNS}, ${abiColumn()}
FROM txs
WHERE canonical = true AND microblock_canonical = true AND index_block_hash = $1
LIMIT $2
@@ -2980,10 +2992,7 @@ export class PgDataStore
`,
[hexToBuffer(blockQuery.result.index_block_hash), limit, offset]
);
let total = 0;
if (totalQuery.rowCount > 0) {
total = totalQuery.rows[0].count;
}
const total = totalQuery.rowCount > 0 ? totalQuery.rows[0].count : 0;
const parsed = result.rows.map(r => this.parseTxQueryResult(r));
return { results: parsed, total };
});
@@ -3647,9 +3656,9 @@ export class PgDataStore
async getTxStrict(args: { txId: string; indexBlockHash: string }): Promise<FoundOrNot<DbTx>> {
return this.query(async client => {
const result = await client.query<TxQueryResult>(
const result = await client.query<ContractTxQueryResult>(
`
SELECT ${TX_COLUMNS}
SELECT ${TX_COLUMNS}, ${abiColumn()}
FROM txs
WHERE tx_id = $1 AND index_block_hash = $2
ORDER BY canonical DESC, microblock_canonical DESC, block_height DESC
@@ -3721,7 +3730,7 @@ export class PgDataStore
includeUnanchored: boolean;
}) {
let totalQuery: QueryResult<{ count: number }>;
let resultQuery: QueryResult<TxQueryResult>;
let resultQuery: QueryResult<ContractTxQueryResult>;
return this.queryTx(async client => {
const maxHeight = await this.getMaxBlockHeight(client, { includeUnanchored });
@@ -3734,23 +3743,16 @@ export class PgDataStore
`,
[maxHeight]
);
resultQuery = await client.query<TxQueryResult>(
resultQuery = await client.query<ContractTxQueryResult>(
`
SELECT ${TX_COLUMNS},
CASE WHEN txs.type_id = $4 THEN (
SELECT abi
FROM smart_contracts
WHERE smart_contracts.contract_id = txs.contract_call_contract_id
ORDER BY abi != 'null' DESC, canonical DESC, microblock_canonical DESC, block_height DESC
LIMIT 1
) END as abi
SELECT ${TX_COLUMNS}, ${abiColumn()}
FROM txs
WHERE canonical = true AND microblock_canonical = true AND block_height <= $3
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
LIMIT $1
OFFSET $2
`,
[limit, offset, maxHeight, DbTxTypeId.ContractCall]
[limit, offset, maxHeight]
);
} else {
const txTypeIds = txTypeFilter.map<number>(t => getTxTypeId(t));
@@ -3762,23 +3764,16 @@ export class PgDataStore
`,
[txTypeIds, maxHeight]
);
resultQuery = await client.query<TxQueryResult>(
resultQuery = await client.query<ContractTxQueryResult>(
`
SELECT ${TX_COLUMNS}
CASE WHEN txs.type_id = $5 THEN (
SELECT abi
FROM smart_contracts
WHERE smart_contracts.contract_id = txs.contract_call_contract_id
ORDER BY abi != 'null' DESC, canonical DESC, microblock_canonical DESC, block_height DESC
LIMIT 1
) END as abi
SELECT ${TX_COLUMNS}, ${abiColumn()}
FROM txs
WHERE canonical = true AND microblock_canonical = true AND type_id = ANY($1) AND block_height <= $4
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
LIMIT $2
OFFSET $3
`,
[txTypeIds, limit, offset, maxHeight, DbTxTypeId.ContractCall]
[txTypeIds, limit, offset, maxHeight]
);
}
const parsed = resultQuery.rows.map(r => this.parseTxQueryResult(r));
@@ -5298,24 +5293,14 @@ export class PgDataStore
ON txs.tx_id = event_txs.tx_id
WHERE txs.canonical = true AND txs.microblock_canonical = true
)
SELECT ${TX_COLUMNS},
CASE
WHEN principal_txs.type_id = $5 THEN (
SELECT abi
FROM smart_contracts
WHERE smart_contracts.contract_id = principal_txs.contract_call_contract_id
ORDER BY abi != 'null' DESC, canonical DESC, microblock_canonical DESC, block_height DESC
LIMIT 1
)
END as abi,
(COUNT(*) OVER())::integer as count
SELECT ${TX_COLUMNS}, ${abiColumn('principal_txs')}, (COUNT(*) OVER())::integer as count
FROM principal_txs
${args.atSingleBlock ? 'WHERE block_height = $4' : 'WHERE block_height <= $4'}
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
LIMIT $2
OFFSET $3
`,
[args.stxAddress, args.limit, args.offset, args.blockHeight, DbTxTypeId.ContractCall]
[args.stxAddress, args.limit, args.offset, args.blockHeight]
);
const count = resultQuery.rowCount > 0 ? resultQuery.rows[0].count : 0;
const parsed = resultQuery.rows.map(r => this.parseTxQueryResult(r));
@@ -5331,11 +5316,7 @@ export class PgDataStore
tx_id: string;
}): Promise<DbTxWithAssetTransfers> {
return this.query(async client => {
const queryParams: (string | Buffer | DbTxTypeId)[] = [
stxAddress,
hexToBuffer(tx_id),
DbTxTypeId.ContractCall,
];
const queryParams: (string | Buffer)[] = [stxAddress, hexToBuffer(tx_id)];
const resultQuery = await client.query<
ContractTxQueryResult & {
count: number;
@@ -5380,13 +5361,7 @@ export class PgDataStore
events.amount as event_amount,
events.sender as event_sender,
events.recipient as event_recipient,
CASE WHEN transactions.type_id = $3 THEN (
SELECT abi
FROM smart_contracts
WHERE smart_contracts.contract_id = transactions.contract_call_contract_id
ORDER BY abi != 'null' DESC, canonical DESC, microblock_canonical DESC, block_height DESC
LIMIT 1
) END as abi
${abiColumn('transactions')}
FROM transactions
LEFT JOIN events ON transactions.tx_id = events.tx_id AND transactions.tx_id = $2
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC, event_index DESC
@@ -5408,7 +5383,7 @@ export class PgDataStore
offset?: number;
}): Promise<{ results: DbTxWithAssetTransfers[]; total: number }> {
return this.queryTx(async client => {
const queryParams: (string | number)[] = [args.stxAddress, DbTxTypeId.ContractCall];
const queryParams: (string | number)[] = [args.stxAddress];
if (args.atSingleBlock) {
queryParams.push(args.blockHeight);
@@ -5419,7 +5394,7 @@ export class PgDataStore
}
// Use a JOIN to include stx_events associated with the address's txs
const resultQuery = await client.query<
TxQueryResult & {
ContractTxQueryResult & {
count: number;
event_index?: number;
event_type?: number;
@@ -5454,9 +5429,9 @@ export class PgDataStore
)
SELECT ${TX_COLUMNS}, (COUNT(*) OVER())::integer as count
FROM principal_txs
${args.atSingleBlock ? 'WHERE block_height = $3' : 'WHERE block_height <= $5'}
${args.atSingleBlock ? 'WHERE block_height = $2' : 'WHERE block_height <= $4'}
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
${!args.atSingleBlock ? 'LIMIT $3 OFFSET $4' : ''}
${!args.atSingleBlock ? 'LIMIT $2 OFFSET $3' : ''}
), events AS (
SELECT
tx_id, sender, recipient, event_index, amount,
@@ -5481,13 +5456,7 @@ export class PgDataStore
)
SELECT
transactions.*,
CASE WHEN transactions.type_id = $2 THEN (
SELECT abi
FROM smart_contracts
WHERE smart_contracts.contract_id = transactions.contract_call_contract_id
ORDER BY abi != 'null' DESC, canonical DESC, microblock_canonical DESC, block_height DESC
LIMIT 1
) END as abi,
${abiColumn('transactions')},
events.event_index as event_index,
events.event_type_id as event_type,
events.amount as event_amount,
@@ -5703,8 +5672,8 @@ export class PgDataStore
async searchHash({ hash }: { hash: string }): Promise<FoundOrNot<DbSearchResult>> {
// TODO(mb): add support for searching for microblock by hash
return this.query(async client => {
const txQuery = await client.query<TxQueryResult>(
`SELECT ${TX_COLUMNS} FROM txs WHERE tx_id = $1 LIMIT 1`,
const txQuery = await client.query<ContractTxQueryResult>(
`SELECT ${TX_COLUMNS}, ${abiColumn()} FROM txs WHERE tx_id = $1 LIMIT 1`,
[hexToBuffer(hash)]
);
if (txQuery.rowCount > 0) {
@@ -5781,9 +5750,9 @@ export class PgDataStore
},
};
}
const contractTxResult = await client.query<TxQueryResult>(
const contractTxResult = await client.query<ContractTxQueryResult>(
`
SELECT ${TX_COLUMNS}
SELECT ${TX_COLUMNS}, ${abiColumn()}
FROM txs
WHERE smart_contract_contract_id = $1
ORDER BY canonical DESC, microblock_canonical DESC, block_height DESC
@@ -6135,20 +6104,11 @@ export class PgDataStore
const maxBlockHeight = await this.getMaxBlockHeight(client, { includeUnanchored });
const result = await client.query<ContractTxQueryResult>(
`
SELECT ${TX_COLUMNS},
CASE
WHEN txs.type_id = $3 THEN (
SELECT abi
FROM smart_contracts
WHERE smart_contracts.contract_id = txs.contract_call_contract_id
ORDER BY abi != 'null' DESC, canonical DESC, microblock_canonical DESC, block_height DESC
LIMIT 1
)
END as abi
SELECT ${TX_COLUMNS}, ${abiColumn()}
FROM txs
WHERE tx_id = ANY($1) AND block_height <= $2 AND canonical = true AND microblock_canonical = true
`,
[values, maxBlockHeight, DbTxTypeId.ContractCall]
[values, maxBlockHeight]
);
if (result.rowCount === 0) {
return [];

View File

@@ -4164,7 +4164,7 @@ describe('api tests', () => {
abi: JSON.stringify(contractJsonAbi),
};
const contractCall: DbTx = {
tx_id: '0x1232',
tx_id: '0x1232000000000000000000000000000000000000000000000000000000000000',
tx_index: 5,
anchor_mode: 3,
nonce: 0,
@@ -4175,7 +4175,6 @@ describe('api tests', () => {
burn_block_time: block.burn_block_time,
parent_burn_block_time: 1626122935,
type_id: DbTxTypeId.ContractCall,
coinbase_payload: Buffer.from('coinbase hi'),
status: 1,
raw_result: '0x0100000000000000000000000000000001', // u1
canonical: true,
@@ -4532,7 +4531,7 @@ describe('api tests', () => {
execution_cost_write_length: 0,
},
{
tx_id: '0x1232',
tx_id: '0x1232000000000000000000000000000000000000000000000000000000000000',
tx_status: 'success',
tx_result: {
hex: '0x0100000000000000000000000000000001', // u1
@@ -4682,7 +4681,7 @@ describe('api tests', () => {
total: 1,
results: [
{
tx_id: '0x1232',
tx_id: '0x1232000000000000000000000000000000000000000000000000000000000000',
tx_status: 'success',
tx_result: {
hex: '0x0100000000000000000000000000000001', // u1
@@ -4810,7 +4809,7 @@ describe('api tests', () => {
sender_address: 'ST27W5M8BRKA7C5MZE2R1S1F4XTPHFWFRNHA9M04Y.hello-world',
sponsor_address: 'ST3J8EVYHVKH6XXPD61EE8XEHW4Y2K83861225AB1',
sponsored: false,
tx_id: '0x1232',
tx_id: '0x1232000000000000000000000000000000000000000000000000000000000000',
tx_index: 5,
tx_result: {
hex: '0x0100000000000000000000000000000001',
@@ -4825,7 +4824,7 @@ describe('api tests', () => {
expect(JSON.parse(fetchAddrTx3.text)).toEqual(expectedResp6);
const fetchAddrTx4 = await supertest(api.server).get(
`/extended/v1/address/${testAddr5}/0x1232/with_transfers`
`/extended/v1/address/${testAddr5}/0x1232000000000000000000000000000000000000000000000000000000000000/with_transfers`
);
expect(fetchAddrTx4.status).toBe(200);
expect(fetchAddrTx4.type).toBe('application/json');
@@ -4886,7 +4885,7 @@ describe('api tests', () => {
sender_address: 'ST27W5M8BRKA7C5MZE2R1S1F4XTPHFWFRNHA9M04Y.hello-world',
sponsor_address: 'ST3J8EVYHVKH6XXPD61EE8XEHW4Y2K83861225AB1',
sponsored: false,
tx_id: '0x1232',
tx_id: '0x1232000000000000000000000000000000000000000000000000000000000000',
tx_index: 5,
tx_result: {
hex: '0x0100000000000000000000000000000001',
@@ -4897,6 +4896,77 @@ describe('api tests', () => {
},
};
expect(JSON.parse(fetchAddrTx4.text)).toEqual(expectedResp7);
const contractCallExpectedResults = {
tx_id: '0x1232000000000000000000000000000000000000000000000000000000000000',
tx_status: 'success',
tx_result: {
hex: '0x0100000000000000000000000000000001', // u1
repr: 'u1',
},
tx_type: 'contract_call',
fee_rate: '10',
is_unanchored: false,
nonce: 0,
anchor_mode: 'any',
sender_address: 'ST27W5M8BRKA7C5MZE2R1S1F4XTPHFWFRNHA9M04Y.hello-world',
sponsor_address: 'ST3J8EVYHVKH6XXPD61EE8XEHW4Y2K83861225AB1',
sponsored: false,
post_condition_mode: 'allow',
post_conditions: [],
block_hash: '0x1234',
block_height: 1,
burn_block_time: 39486,
burn_block_time_iso: '1970-01-01T10:58:06.000Z',
canonical: true,
microblock_canonical: true,
microblock_hash: '',
microblock_sequence: I32_MAX,
parent_block_hash: '',
parent_burn_block_time: 1626122935,
parent_burn_block_time_iso: '2021-07-12T20:48:55.000Z',
tx_index: 5,
contract_call: {
contract_id: 'ST27W5M8BRKA7C5MZE2R1S1F4XTPHFWFRNHA9M04Y.hello-world',
function_name: 'test-contract-fn',
function_signature: '(define-public (test-contract-fn (amount uint) (desc string-ascii)))',
function_args: [
{
hex: '0x010000000000000000000000000001e240',
name: 'amount',
repr: 'u123456',
type: 'uint',
},
{
hex: '0x0d0000000568656c6c6f',
name: 'desc',
repr: '"hello"',
type: 'string-ascii',
},
],
},
event_count: 5,
execution_cost_read_count: 0,
execution_cost_read_length: 0,
execution_cost_runtime: 0,
execution_cost_write_count: 0,
execution_cost_write_length: 0,
};
const blockTxsRows = await api.datastore.getBlockTxsRows(block.block_hash);
expect(blockTxsRows.found).toBe(true);
const blockTxsRowsResult = blockTxsRows.result as DbTx[];
expect(blockTxsRowsResult[6]).toEqual({ ...contractCall, ...{ abi: contractJsonAbi } });
const searchResult8 = await supertest(api.server).get(
`/extended/v1/search/0x1232000000000000000000000000000000000000000000000000000000000000?include_metadata`
);
expect(searchResult8.status).toBe(200);
expect(searchResult8.type).toBe('application/json');
expect(JSON.parse(searchResult8.text).result.metadata).toEqual(contractCallExpectedResults);
const blockTxResult = await db.getTxsFromBlock('0x1234', 20, 0);
expect(blockTxResult.results[6]).toEqual({ ...contractCall, ...{ abi: contractJsonAbi } });
});
test('list contract log events', async () => {

View File

@@ -1,5 +1,11 @@
import * as supertest from 'supertest';
import { ChainID } from '@stacks/transactions';
import {
bufferCVFromString,
ChainID,
serializeCV,
stringAsciiCV,
uintCV,
} from '@stacks/transactions';
import {
DbBlock,
DbTx,
@@ -9,6 +15,8 @@ import {
DbAssetEventTypeId,
DbMempoolTx,
DbMicroblockPartial,
DbSmartContractEvent,
DbSmartContract,
} from '../datastore/common';
import { startApiServer } from '../api/init';
import { PgDataStore, cycleMigrations, runMigrations } from '../datastore/postgres-store';
@@ -19,6 +27,7 @@ import {
AddressStxInboundListResponse,
AddressTransactionsListResponse,
AddressTransactionsWithTransfersListResponse,
ContractCallTransaction,
MempoolTransaction,
MempoolTransactionListResponse,
Microblock,
@@ -30,6 +39,7 @@ import {
import { useWithCleanup } from './test-helpers';
import { startEventServer } from '../event-stream/event-server';
import * as fs from 'fs';
import { createClarityValueArray } from '../p2p/tx';
describe('microblock tests', () => {
let db: PgDataStore;
@@ -248,6 +258,7 @@ describe('microblock tests', () => {
async (_, api) => {
const addr1 = 'ST28D4Q6RCQSJ6F7TEYWQDS4N1RXYEP9YBWMYSB97';
const addr2 = 'STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6';
const contractAddr = 'ST27W5M8BRKA7C5MZE2R1S1F4XTPHFWFRNHA9M04Y.hello-world';
const block1: DbBlock = {
block_hash: '0x11',
@@ -303,6 +314,49 @@ describe('microblock tests', () => {
execution_cost_write_count: 0,
execution_cost_write_length: 0,
};
const contractJsonAbi = {
maps: [],
functions: [
{
args: [
{ type: 'uint128', name: 'amount' },
{ type: 'string-ascii', name: 'desc' },
],
name: 'test-contract-fn',
access: 'public',
outputs: {
type: {
response: {
ok: 'uint128',
error: 'none',
},
},
},
},
],
variables: [],
fungible_tokens: [],
non_fungible_tokens: [],
};
const contractLogEvent1: DbSmartContractEvent = {
event_index: 4,
tx_id: tx1.tx_id,
tx_index: 0,
block_height: block1.block_height,
canonical: true,
event_type: DbEventTypeId.SmartContractLog,
contract_identifier: contractAddr,
topic: 'some-topic',
value: serializeCV(bufferCVFromString('some val')),
};
const smartContract1: DbSmartContract = {
tx_id: tx1.tx_id,
canonical: true,
block_height: block1.block_height,
contract_id: contractAddr,
source_code: '(some-contract-src)',
abi: JSON.stringify(contractJsonAbi),
};
await db.update({
block: block1,
@@ -315,8 +369,8 @@ describe('microblock tests', () => {
stxEvents: [],
ftEvents: [],
nftEvents: [],
contractLogEvents: [],
smartContracts: [],
contractLogEvents: [contractLogEvent1],
smartContracts: [smartContract1],
names: [],
namespaces: [],
},
@@ -381,13 +435,65 @@ describe('microblock tests', () => {
// These properties can be determined with a db query, they are set while the db is inserting them.
block_height: -1,
};
const mbTx2: DbTx = {
tx_id: '0x03',
tx_index: 1,
anchor_mode: 3,
nonce: 0,
raw_tx: Buffer.alloc(0),
type_id: DbTxTypeId.ContractCall,
status: 1,
raw_result: '0x0100000000000000000000000000000001', // u1
canonical: true,
post_conditions: Buffer.from([0x01, 0xf5]),
fee_rate: 1234n,
sponsored: false,
sender_address: addr1,
sponsor_address: undefined,
origin_hash_mode: 1,
token_transfer_amount: 50n,
token_transfer_memo: Buffer.from('hi'),
token_transfer_recipient_address: addr2,
event_count: 1,
parent_index_block_hash: block1.index_block_hash,
parent_block_hash: block1.block_hash,
microblock_canonical: true,
microblock_sequence: mb1.microblock_sequence,
microblock_hash: mb1.microblock_hash,
parent_burn_block_time: mb1.parent_burn_block_time,
execution_cost_read_count: 0,
execution_cost_read_length: 0,
execution_cost_runtime: 0,
execution_cost_write_count: 0,
execution_cost_write_length: 0,
contract_call_contract_id: contractAddr,
contract_call_function_name: 'test-contract-fn',
contract_call_function_args: createClarityValueArray(
uintCV(123456),
stringAsciiCV('hello')
),
abi: JSON.stringify(contractJsonAbi),
// These properties aren't known until the next anchor block that accepts this microblock.
index_block_hash: '',
block_hash: '',
burn_block_time: -1,
// These properties can be determined with a db query, they are set while the db is inserting them.
block_height: -1,
};
const mempoolTx1: DbMempoolTx = {
...mbTx1,
pruned: false,
receipt_time: 123456789,
};
await db.updateMempoolTxs({ mempoolTxs: [mempoolTx1] });
const mempoolTx2: DbMempoolTx = {
...mbTx2,
pruned: false,
receipt_time: 123456789,
};
await db.updateMempoolTxs({ mempoolTxs: [mempoolTx1, mempoolTx2] });
const mbTxStxEvent1: DbStxEvent = {
canonical: true,
@@ -416,6 +522,17 @@ describe('microblock tests', () => {
names: [],
namespaces: [],
},
{
tx: mbTx2,
stxLockEvents: [],
stxEvents: [],
ftEvents: [],
nftEvents: [],
contractLogEvents: [],
smartContracts: [],
names: [],
namespaces: [],
},
],
});
@@ -434,12 +551,41 @@ describe('microblock tests', () => {
const txListResult2 = await supertest(api.server).get(`/extended/v1/tx?unanchored`);
const { body: txListBody2 }: { body: TransactionResults } = txListResult2;
expect(txListBody2.results).toHaveLength(2);
expect(txListBody2.results[0].tx_id).toBe(mbTx1.tx_id);
expect(txListBody2.results).toHaveLength(3);
expect(txListBody2.results[0].tx_id).toBe(mbTx2.tx_id);
const txListResult3 = await supertest(api.server).get(
`/extended/v1/microblock/unanchored/txs`
);
const { body: txListBody3 }: { body: TransactionResults } = txListResult3;
expect(txListBody3.results).toHaveLength(2);
expect(txListBody3.results[0].tx_id).toBe(mbTx2.tx_id);
const expectedContractCallResp = {
contract_id: 'ST27W5M8BRKA7C5MZE2R1S1F4XTPHFWFRNHA9M04Y.hello-world',
function_args: [
{
hex: '0x010000000000000000000000000001e240',
name: 'amount',
repr: 'u123456',
type: 'uint',
},
{
hex: '0x0d0000000568656c6c6f',
name: 'desc',
repr: '"hello"',
type: 'string-ascii',
},
],
function_name: 'test-contract-fn',
function_signature:
'(define-public (test-contract-fn (amount uint) (desc string-ascii)))',
};
const contractCallResults = txListBody3.results[0] as ContractCallTransaction;
expect(contractCallResults.contract_call).toEqual(expectedContractCallResp);
const mempoolResult1 = await supertest(api.server).get(`/extended/v1/tx/mempool`);
const { body: mempoolBody1 }: { body: MempoolTransactionListResponse } = mempoolResult1;
expect(mempoolBody1.results).toHaveLength(1);
expect(mempoolBody1.results).toHaveLength(2);
expect(mempoolBody1.results[0].tx_id).toBe(mempoolTx1.tx_id);
expect(mempoolBody1.results[0].tx_status).toBe('pending');
@@ -471,16 +617,16 @@ describe('microblock tests', () => {
const { body: mbListBody1 }: { body: MicroblockListResponse } = mbListResult1;
expect(mbListBody1.results).toHaveLength(1);
expect(mbListBody1.results[0].microblock_hash).toBe(mb1.microblock_hash);
expect(mbListBody1.results[0].txs).toHaveLength(1);
expect(mbListBody1.results[0].txs[0]).toBe(mbTx1.tx_id);
expect(mbListBody1.results[0].txs).toHaveLength(2);
expect(mbListBody1.results[0].txs[0]).toBe(mbTx2.tx_id);
const mbResult1 = await supertest(api.server).get(
`/extended/v1/microblock/${mb1.microblock_hash}`
);
const { body: mbBody1 }: { body: Microblock } = mbResult1;
expect(mbBody1.microblock_hash).toBe(mb1.microblock_hash);
expect(mbBody1.txs).toHaveLength(1);
expect(mbBody1.txs[0]).toBe(mbTx1.tx_id);
expect(mbBody1.txs).toHaveLength(2);
expect(mbBody1.txs[0]).toBe(mbTx2.tx_id);
const addrTxsTransfers1 = await supertest(api.server).get(
`/extended/v1/address/${addr2}/transactions_with_transfers`
@@ -496,9 +642,9 @@ describe('microblock tests', () => {
const {
body: addrTxsTransfersBody2,
}: { body: AddressTransactionsWithTransfersListResponse } = addrTxsTransfers2;
expect(addrTxsTransfersBody2.results).toHaveLength(1);
expect(addrTxsTransfersBody2.results[0].tx.tx_id).toBe(mbTx1.tx_id);
expect(addrTxsTransfersBody2.results[0].stx_received).toBe(mbTxStxEvent1.amount.toString());
expect(addrTxsTransfersBody2.results).toHaveLength(2);
expect(addrTxsTransfersBody2.results[1].tx.tx_id).toBe(mbTx1.tx_id);
expect(addrTxsTransfersBody2.results[1].stx_received).toBe(mbTxStxEvent1.amount.toString());
const addrTxs1 = await supertest(api.server).get(
`/extended/v1/address/${addr2}/transactions`
@@ -510,8 +656,8 @@ describe('microblock tests', () => {
`/extended/v1/address/${addr2}/transactions?unanchored`
);
const { body: addrTxsBody2 }: { body: AddressTransactionsListResponse } = addrTxs2;
expect(addrTxsBody2.results).toHaveLength(1);
expect(addrTxsBody2.results[0].tx_id).toBe(mbTx1.tx_id);
expect(addrTxsBody2.results).toHaveLength(2);
expect(addrTxsBody2.results[0].tx_id).toBe(mbTx2.tx_id);
const addrBalance1 = await supertest(api.server).get(`/extended/v1/address/${addr2}/stx`);
const { body: addrBalanceBody1 }: { body: AddressStxBalanceResponse } = addrBalance1;