mirror of
https://github.com/alexgo-io/stacks-blockchain-api.git
synced 2026-01-12 22:43:34 +08:00
@@ -19,6 +19,7 @@
|
||||
"canonical",
|
||||
"tx_status",
|
||||
"tx_result",
|
||||
"events",
|
||||
"event_count",
|
||||
"parent_block_hash",
|
||||
"is_unanchored",
|
||||
@@ -128,6 +129,13 @@
|
||||
"execution_cost_write_length": {
|
||||
"type": "integer",
|
||||
"description": "Execution cost write length."
|
||||
},
|
||||
"events" : {
|
||||
"type": "array",
|
||||
"description": "List of transaction events",
|
||||
"items": {
|
||||
"$ref": "../transaction-events/transaction-event.schema.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"title": "TransactionWithEvents",
|
||||
"description": "Describes all transaction types on Stacks 2.0 blockchain",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "./transaction.schema.json"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"required": ["events"],
|
||||
"properties": {
|
||||
"events": {
|
||||
"type": "array",
|
||||
"description": "List of transaction events",
|
||||
"items": {
|
||||
"$ref": "../transaction-events/transaction-event.schema.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
14
docs/generated.d.ts
vendored
14
docs/generated.d.ts
vendored
@@ -235,7 +235,6 @@ export type SchemaMergeRootStub =
|
||||
| TransactionNotFound
|
||||
| TransactionStatus1
|
||||
| TransactionType
|
||||
| TransactionWithEvents
|
||||
| Transaction
|
||||
| InboundStxTransfer
|
||||
| RpcAddressBalanceNotificationParams
|
||||
@@ -487,6 +486,10 @@ export type AbstractTransaction = BaseTransaction & {
|
||||
* Execution cost write length.
|
||||
*/
|
||||
execution_cost_write_length: number;
|
||||
/**
|
||||
* List of transaction events
|
||||
*/
|
||||
events: TransactionEvent[];
|
||||
};
|
||||
export type PostConditionMode = "allow" | "deny";
|
||||
/**
|
||||
@@ -767,15 +770,6 @@ export type TransactionStatus1 = "success" | "abort_by_response" | "abort_by_pos
|
||||
* String literal of all Stacks 2.0 transaction types
|
||||
*/
|
||||
export type TransactionType = "token_transfer" | "smart_contract" | "contract_call" | "poison_microblock" | "coinbase";
|
||||
/**
|
||||
* Describes all transaction types on Stacks 2.0 blockchain
|
||||
*/
|
||||
export type TransactionWithEvents = Transaction & {
|
||||
/**
|
||||
* List of transaction events
|
||||
*/
|
||||
events: TransactionEvent[];
|
||||
};
|
||||
export type RpcSubscriptionType =
|
||||
| "tx_update"
|
||||
| "address_tx_update"
|
||||
|
||||
@@ -371,7 +371,7 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ./entities/transactions/transaction-with-events.schema.json
|
||||
$ref: ./entities/transactions/transaction.schema.json
|
||||
example:
|
||||
$ref: ./entities/transactions/transaction-4-coinbase.example.json
|
||||
404:
|
||||
|
||||
@@ -28,7 +28,6 @@ import {
|
||||
SmartContractTransaction,
|
||||
SmartContractTransactionMetadata,
|
||||
TokenTransferTransactionMetadata,
|
||||
TransactionWithEvents,
|
||||
Transaction,
|
||||
TransactionAnchorModeType,
|
||||
TransactionEvent,
|
||||
@@ -754,6 +753,7 @@ function parseDbAbstractTx(dbTx: DbTx, baseTx: BaseTransaction): AbstractTransac
|
||||
microblock_sequence: dbTx.microblock_sequence,
|
||||
microblock_canonical: dbTx.microblock_canonical,
|
||||
event_count: dbTx.event_count,
|
||||
events: [],
|
||||
execution_cost_read_count: dbTx.execution_cost_read_count,
|
||||
execution_cost_read_length: dbTx.execution_cost_read_length,
|
||||
execution_cost_runtime: dbTx.execution_cost_runtime,
|
||||
@@ -819,7 +819,7 @@ export async function getMempoolTxsFromDataStore(
|
||||
async function getTxsFromDataStore(
|
||||
db: DataStore,
|
||||
args: GetTxsArgs | GetTxsWithEventsArgs
|
||||
): Promise<Transaction[] | TransactionWithEvents[]> {
|
||||
): Promise<Transaction[]> {
|
||||
// fetching all requested transactions from db
|
||||
const txQuery = await db.getTxListDetails({
|
||||
txIds: args.txIds,
|
||||
@@ -831,8 +831,10 @@ async function getTxsFromDataStore(
|
||||
return [];
|
||||
}
|
||||
|
||||
let events: DbEvent[] = [];
|
||||
// parsing txQuery
|
||||
const parsedTxs = txQuery.map(tx => parseDbTx(tx));
|
||||
|
||||
// incase transaction events are requested
|
||||
if ('eventLimit' in args) {
|
||||
const txIdsAndIndexHash = txQuery.map(tx => {
|
||||
return {
|
||||
@@ -840,39 +842,30 @@ async function getTxsFromDataStore(
|
||||
indexBlockHash: tx.index_block_hash,
|
||||
};
|
||||
});
|
||||
events = (
|
||||
await db.getTxListEvents({
|
||||
txs: txIdsAndIndexHash,
|
||||
limit: args.eventLimit,
|
||||
offset: args.eventOffset,
|
||||
})
|
||||
).results;
|
||||
}
|
||||
|
||||
// parsing txQuery
|
||||
const parsedTxs = txQuery.map(tx => parseDbTx(tx));
|
||||
|
||||
// incase transaction events are requested
|
||||
if ('eventLimit' in args) {
|
||||
// this will insert all events in a single parsedTransaction. Only specific ones are to be added.
|
||||
const txsWithEvents: TransactionWithEvents[] = parsedTxs.map(ptx => {
|
||||
return { ...ptx, events: [] };
|
||||
const txListEvents = await db.getTxListEvents({
|
||||
txs: txIdsAndIndexHash,
|
||||
limit: args.eventLimit,
|
||||
offset: args.eventOffset,
|
||||
});
|
||||
txsWithEvents.forEach(
|
||||
ptx =>
|
||||
(ptx.events = events
|
||||
// this will insert all events in a single parsedTransaction. Only specific ones are to be added.
|
||||
const txsWithEvents: Transaction[] = parsedTxs.map(ptx => {
|
||||
return {
|
||||
...ptx,
|
||||
events: txListEvents.results
|
||||
.filter(event => event.tx_id === ptx.tx_id)
|
||||
.map(event => parseDbEvent(event)))
|
||||
);
|
||||
.map(event => parseDbEvent(event)),
|
||||
};
|
||||
});
|
||||
return txsWithEvents;
|
||||
} else {
|
||||
return parsedTxs;
|
||||
}
|
||||
return parsedTxs;
|
||||
}
|
||||
|
||||
export async function getTxFromDataStore(
|
||||
db: DataStore,
|
||||
args: GetTxArgs | GetTxWithEventsArgs | GetTxFromDbTxArgs
|
||||
): Promise<FoundOrNot<TransactionWithEvents | Transaction>> {
|
||||
): Promise<FoundOrNot<Transaction>> {
|
||||
let dbTx: DbTx;
|
||||
if ('dbTx' in args) {
|
||||
dbTx = args.dbTx;
|
||||
@@ -888,20 +881,23 @@ export async function getTxFromDataStore(
|
||||
|
||||
// If tx events are requested
|
||||
if ('eventLimit' in args) {
|
||||
const txWithEvents: TransactionWithEvents = { ...parsedTx, events: [] };
|
||||
const eventsQuery = await db.getTxEvents({
|
||||
txId: args.txId,
|
||||
indexBlockHash: dbTx.index_block_hash,
|
||||
limit: args.eventLimit,
|
||||
offset: args.eventOffset,
|
||||
});
|
||||
txWithEvents.events = eventsQuery.results.map(event => parseDbEvent(event));
|
||||
const txWithEvents: Transaction = {
|
||||
...parsedTx,
|
||||
events: eventsQuery.results.map(event => parseDbEvent(event)),
|
||||
};
|
||||
return { found: true, result: txWithEvents };
|
||||
} else {
|
||||
return {
|
||||
found: true,
|
||||
result: parsedTx,
|
||||
};
|
||||
}
|
||||
return {
|
||||
found: true,
|
||||
result: parsedTx,
|
||||
};
|
||||
}
|
||||
|
||||
export async function searchTxs(
|
||||
@@ -965,7 +961,7 @@ export async function searchTxs(
|
||||
export async function searchTx(
|
||||
db: DataStore,
|
||||
args: GetTxArgs | GetTxWithEventsArgs
|
||||
): Promise<FoundOrNot<Transaction | TransactionWithEvents | MempoolTransaction>> {
|
||||
): Promise<FoundOrNot<Transaction | MempoolTransaction>> {
|
||||
// First, check the happy path: the tx is mined and in the canonical chain.
|
||||
const minedTxs = await getTxsFromDataStore(db, { ...args, txIds: [args.txId] });
|
||||
const minedTx = minedTxs[0] ?? undefined;
|
||||
|
||||
@@ -2278,6 +2278,7 @@ describe('api tests', () => {
|
||||
microblock_sequence: 2147483647,
|
||||
microblock_canonical: true,
|
||||
event_count: 0,
|
||||
events: [],
|
||||
execution_cost_read_count: 0,
|
||||
execution_cost_read_length: 0,
|
||||
execution_cost_runtime: 0,
|
||||
@@ -3221,6 +3222,7 @@ describe('api tests', () => {
|
||||
burn_block_time_iso: '1970-02-02T20:12:45.000Z',
|
||||
canonical: true,
|
||||
event_count: 0,
|
||||
events: [],
|
||||
execution_cost_read_count: 0,
|
||||
execution_cost_read_length: 0,
|
||||
execution_cost_runtime: 0,
|
||||
@@ -3545,6 +3547,7 @@ describe('api tests', () => {
|
||||
amount: '35',
|
||||
memo: '0x6869',
|
||||
},
|
||||
events: [],
|
||||
event_count: 0,
|
||||
execution_cost_read_count: 1,
|
||||
execution_cost_read_length: 2,
|
||||
@@ -3631,6 +3634,7 @@ describe('api tests', () => {
|
||||
amount: '250',
|
||||
memo: '0x6869',
|
||||
},
|
||||
events: [],
|
||||
event_count: 0,
|
||||
execution_cost_read_count: 1,
|
||||
execution_cost_read_length: 2,
|
||||
@@ -3691,6 +3695,7 @@ describe('api tests', () => {
|
||||
amount: '100',
|
||||
memo: '0x6869',
|
||||
},
|
||||
events: [],
|
||||
event_count: 0,
|
||||
execution_cost_read_count: 1,
|
||||
execution_cost_read_length: 2,
|
||||
@@ -3774,6 +3779,7 @@ describe('api tests', () => {
|
||||
amount: '35',
|
||||
memo: '0x6869',
|
||||
},
|
||||
events: [],
|
||||
event_count: 0,
|
||||
execution_cost_read_count: 1,
|
||||
execution_cost_read_length: 2,
|
||||
@@ -3845,6 +3851,7 @@ describe('api tests', () => {
|
||||
amount: '35',
|
||||
memo: '0x6869',
|
||||
},
|
||||
events: [],
|
||||
event_count: 0,
|
||||
execution_cost_read_count: 1,
|
||||
execution_cost_read_length: 2,
|
||||
@@ -3931,6 +3938,7 @@ describe('api tests', () => {
|
||||
amount: '15',
|
||||
memo: '0x6869',
|
||||
},
|
||||
events: [],
|
||||
event_count: 0,
|
||||
execution_cost_read_count: 1,
|
||||
execution_cost_read_length: 2,
|
||||
@@ -4594,6 +4602,7 @@ describe('api tests', () => {
|
||||
memo: '0x6869',
|
||||
},
|
||||
event_count: 0,
|
||||
events: [],
|
||||
execution_cost_read_count: 0,
|
||||
execution_cost_read_length: 0,
|
||||
execution_cost_runtime: 0,
|
||||
@@ -4650,6 +4659,7 @@ describe('api tests', () => {
|
||||
],
|
||||
},
|
||||
event_count: 5,
|
||||
events: [],
|
||||
execution_cost_read_count: 0,
|
||||
execution_cost_read_length: 0,
|
||||
execution_cost_runtime: 0,
|
||||
@@ -4690,6 +4700,7 @@ describe('api tests', () => {
|
||||
memo: '0x6869',
|
||||
},
|
||||
event_count: 0,
|
||||
events: [],
|
||||
execution_cost_read_count: 0,
|
||||
execution_cost_read_length: 0,
|
||||
execution_cost_runtime: 0,
|
||||
@@ -4730,6 +4741,7 @@ describe('api tests', () => {
|
||||
memo: '0x6869',
|
||||
},
|
||||
event_count: 0,
|
||||
events: [],
|
||||
execution_cost_read_count: 0,
|
||||
execution_cost_read_length: 0,
|
||||
execution_cost_runtime: 0,
|
||||
@@ -4800,6 +4812,7 @@ describe('api tests', () => {
|
||||
],
|
||||
},
|
||||
event_count: 5,
|
||||
events: [],
|
||||
execution_cost_read_count: 0,
|
||||
execution_cost_read_length: 0,
|
||||
execution_cost_runtime: 0,
|
||||
@@ -4860,6 +4873,7 @@ describe('api tests', () => {
|
||||
'(define-public (test-contract-fn (amount uint) (desc string-ascii)))',
|
||||
},
|
||||
event_count: 5,
|
||||
events: [],
|
||||
execution_cost_read_count: 0,
|
||||
execution_cost_read_length: 0,
|
||||
execution_cost_runtime: 0,
|
||||
@@ -4936,6 +4950,7 @@ describe('api tests', () => {
|
||||
'(define-public (test-contract-fn (amount uint) (desc string-ascii)))',
|
||||
},
|
||||
event_count: 5,
|
||||
events: [],
|
||||
execution_cost_read_count: 0,
|
||||
execution_cost_read_length: 0,
|
||||
execution_cost_runtime: 0,
|
||||
@@ -5016,6 +5031,7 @@ describe('api tests', () => {
|
||||
],
|
||||
},
|
||||
event_count: 5,
|
||||
events: [],
|
||||
execution_cost_read_count: 0,
|
||||
execution_cost_read_length: 0,
|
||||
execution_cost_runtime: 0,
|
||||
@@ -6891,12 +6907,11 @@ describe('api tests', () => {
|
||||
execution_cost_write_count: 0,
|
||||
execution_cost_write_length: 0,
|
||||
};
|
||||
const { events, ...excludedEvents } = expectedResp;
|
||||
const fetchTx = await supertest(api.server).get(`/extended/v1/tx/${dbTx.tx_id}`);
|
||||
expect(fetchTx.status).toBe(200);
|
||||
expect(fetchTx.type).toBe('application/json');
|
||||
expect(JSON.parse(fetchTx.text)).toEqual(expectedResp);
|
||||
expect(txQuery.result).toEqual(excludedEvents);
|
||||
expect(txQuery.result).toEqual(expectedResp);
|
||||
});
|
||||
|
||||
test('tx store and processing', async () => {
|
||||
@@ -7104,8 +7119,7 @@ describe('api tests', () => {
|
||||
execution_cost_write_count: 0,
|
||||
execution_cost_write_length: 0,
|
||||
};
|
||||
const { events, ...excludedEvents } = expectedResp;
|
||||
expect(txQuery.result).toEqual(excludedEvents);
|
||||
expect(txQuery.result).toEqual(expectedResp);
|
||||
|
||||
const fetchTx = await supertest(api.server).get(`/extended/v1/tx/${dbTx.tx_id}`);
|
||||
expect(fetchTx.status).toBe(200);
|
||||
@@ -7116,7 +7130,7 @@ describe('api tests', () => {
|
||||
limit: 96,
|
||||
offset: 0,
|
||||
total: 1,
|
||||
results: [excludedEvents],
|
||||
results: [expectedResp],
|
||||
};
|
||||
const fetchTxList = await supertest(api.server).get(`/extended/v1/tx`);
|
||||
expect(fetchTxList.status).toBe(200);
|
||||
@@ -7240,8 +7254,7 @@ describe('api tests', () => {
|
||||
execution_cost_write_count: 0,
|
||||
execution_cost_write_length: 0,
|
||||
};
|
||||
const { events, ...excludedEvents } = expectedResp;
|
||||
expect(txQuery.result).toEqual(excludedEvents);
|
||||
expect(txQuery.result).toEqual(expectedResp);
|
||||
|
||||
const fetchTx = await supertest(api.server).get(`/extended/v1/tx/${dbTx.tx_id}`);
|
||||
expect(fetchTx.status).toBe(200);
|
||||
@@ -7365,8 +7378,7 @@ describe('api tests', () => {
|
||||
execution_cost_write_count: 0,
|
||||
execution_cost_write_length: 0,
|
||||
};
|
||||
const { events, ...excludedEvents } = expectedResp;
|
||||
expect(txQuery.result).toEqual(excludedEvents);
|
||||
expect(txQuery.result).toEqual(expectedResp);
|
||||
|
||||
const fetchTx = await supertest(api.server).get(`/extended/v1/tx/${dbTx.tx_id}`);
|
||||
expect(fetchTx.status).toBe(200);
|
||||
|
||||
@@ -34,7 +34,6 @@ import {
|
||||
MicroblockListResponse,
|
||||
Transaction,
|
||||
TransactionResults,
|
||||
TransactionWithEvents,
|
||||
} from '@stacks/stacks-blockchain-api-types';
|
||||
import { useWithCleanup } from './test-helpers';
|
||||
import { startEventServer } from '../event-stream/event-server';
|
||||
@@ -160,7 +159,7 @@ describe('microblock tests', () => {
|
||||
}
|
||||
}
|
||||
const txResult2 = await supertest(api.server).get(`/extended/v1/tx/${lostTx}`);
|
||||
const { body: txBody }: { body: TransactionWithEvents } = txResult2;
|
||||
const { body: txBody }: { body: Transaction } = txResult2;
|
||||
expect(txBody.canonical).toBe(true);
|
||||
expect(txBody.microblock_canonical).toBe(true);
|
||||
expect(txBody.tx_id).toBe(lostTx);
|
||||
@@ -226,7 +225,7 @@ describe('microblock tests', () => {
|
||||
}
|
||||
}
|
||||
const txResult2 = await supertest(api.server).get(`/extended/v1/tx/${lostTx}`);
|
||||
const { body: txBody }: { body: TransactionWithEvents } = txResult2;
|
||||
const { body: txBody }: { body: Transaction } = txResult2;
|
||||
expect(txBody.canonical).toBe(true);
|
||||
expect(txBody.microblock_canonical).toBe(true);
|
||||
expect(txBody.tx_id).toBe(lostTx);
|
||||
@@ -603,7 +602,7 @@ describe('microblock tests', () => {
|
||||
const txResult2 = await supertest(api.server).get(
|
||||
`/extended/v1/tx/${mbTx1.tx_id}?unanchored`
|
||||
);
|
||||
const { body: txBody2 }: { body: TransactionWithEvents } = txResult2;
|
||||
const { body: txBody2 }: { body: Transaction } = txResult2;
|
||||
expect(txBody2.tx_id).toBe(mbTx1.tx_id);
|
||||
expect(txBody2.tx_status).toBe('success');
|
||||
expect(txBody2.events).toHaveLength(1);
|
||||
|
||||
Reference in New Issue
Block a user