mirror of
https://github.com/alexgo-io/stacks-blockchain-api.git
synced 2026-04-29 05:15:32 +08:00
fix: address txs abi and reported total
* fix: get abi info when querying address txs * fix: query return type * fix: only parse abi json if it is a string * fix: keep stringify * fix: broken test * feat: move abi query to materialized view, fix count * chore: add test with contract call * chore: create incremental migration for materialized view changes * fix: undo vscode temp changes * chore: test contract-call function decoding in `/extended/v1/address/<contract-principal>/transactions` * chore: test contract-call function decoding in `/extended/v1/address/<standard-principal>/transactions` Co-authored-by: Matthew Little <zone117x@gmail.com>
This commit is contained in:
@@ -663,7 +663,7 @@ function parseDbTxTypeMetadata(dbTx: DbTx | DbMempoolTx): TransactionMetadata {
|
|||||||
let functionAbi: ClarityAbiFunction | undefined;
|
let functionAbi: ClarityAbiFunction | undefined;
|
||||||
const abi = dbTx.abi;
|
const abi = dbTx.abi;
|
||||||
if (abi) {
|
if (abi) {
|
||||||
const contractAbi: ClarityAbi = JSON.parse(JSON.stringify(abi));
|
const contractAbi: ClarityAbi = typeof abi === 'string' ? JSON.parse(abi) : abi;
|
||||||
functionAbi = contractAbi.functions.find(fn => fn.name === functionName);
|
functionAbi = contractAbi.functions.find(fn => fn.name === functionName);
|
||||||
if (!functionAbi) {
|
if (!functionAbi) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
@@ -5267,9 +5267,9 @@ export class PgDataStore
|
|||||||
!args.atSingleBlock &&
|
!args.atSingleBlock &&
|
||||||
args.limit + args.offset <= 50;
|
args.limit + args.offset <= 50;
|
||||||
const resultQuery = useMaterializedView
|
const resultQuery = useMaterializedView
|
||||||
? await client.query<TxQueryResult & { count: number }>(
|
? await client.query<ContractTxQueryResult & { count: number }>(
|
||||||
`
|
`
|
||||||
SELECT ${TX_COLUMNS}, (COUNT(*) OVER())::integer as count
|
SELECT ${TX_COLUMNS}, abi, count
|
||||||
FROM latest_contract_txs
|
FROM latest_contract_txs
|
||||||
WHERE contract_id = $1 AND block_height <= $4
|
WHERE contract_id = $1 AND block_height <= $4
|
||||||
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
|
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
|
||||||
@@ -5278,7 +5278,7 @@ export class PgDataStore
|
|||||||
`,
|
`,
|
||||||
[args.stxAddress, args.limit, args.offset, args.blockHeight]
|
[args.stxAddress, args.limit, args.offset, args.blockHeight]
|
||||||
)
|
)
|
||||||
: await client.query<TxQueryResult & { count: number }>(
|
: await client.query<ContractTxQueryResult & { count: number }>(
|
||||||
`
|
`
|
||||||
WITH principal_txs AS (
|
WITH principal_txs AS (
|
||||||
WITH event_txs AS (
|
WITH event_txs AS (
|
||||||
@@ -5298,14 +5298,24 @@ export class PgDataStore
|
|||||||
ON txs.tx_id = event_txs.tx_id
|
ON txs.tx_id = event_txs.tx_id
|
||||||
WHERE txs.canonical = true AND txs.microblock_canonical = true
|
WHERE txs.canonical = true AND txs.microblock_canonical = true
|
||||||
)
|
)
|
||||||
SELECT ${TX_COLUMNS}, (COUNT(*) OVER())::integer as count
|
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
|
||||||
FROM principal_txs
|
FROM principal_txs
|
||||||
${args.atSingleBlock ? 'WHERE block_height = $4' : 'WHERE block_height <= $4'}
|
${args.atSingleBlock ? 'WHERE block_height = $4' : 'WHERE block_height <= $4'}
|
||||||
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
|
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
|
||||||
LIMIT $2
|
LIMIT $2
|
||||||
OFFSET $3
|
OFFSET $3
|
||||||
`,
|
`,
|
||||||
[args.stxAddress, args.limit, args.offset, args.blockHeight]
|
[args.stxAddress, args.limit, args.offset, args.blockHeight, DbTxTypeId.ContractCall]
|
||||||
);
|
);
|
||||||
const count = resultQuery.rowCount > 0 ? resultQuery.rows[0].count : 0;
|
const count = resultQuery.rowCount > 0 ? resultQuery.rows[0].count : 0;
|
||||||
const parsed = resultQuery.rows.map(r => this.parseTxQueryResult(r));
|
const parsed = resultQuery.rows.map(r => this.parseTxQueryResult(r));
|
||||||
|
|||||||
146
src/migrations/1639152689764_latest_contract_txs_abi.ts
Normal file
146
src/migrations/1639152689764_latest_contract_txs_abi.ts
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
|
import { MigrationBuilder, ColumnDefinitions } from 'node-pg-migrate';
|
||||||
|
|
||||||
|
export const shorthands: ColumnDefinitions | undefined = undefined;
|
||||||
|
|
||||||
|
export async function up(pgm: MigrationBuilder): Promise<void> {
|
||||||
|
pgm.dropMaterializedView('latest_contract_txs', { ifExists: true, cascade: true });
|
||||||
|
pgm.createMaterializedView('latest_contract_txs', {}, `
|
||||||
|
WITH contract_txs AS (
|
||||||
|
SELECT
|
||||||
|
contract_call_contract_id AS contract_id, tx_id,
|
||||||
|
block_height, microblock_sequence, tx_index
|
||||||
|
FROM txs
|
||||||
|
WHERE
|
||||||
|
contract_call_contract_id IS NOT NULL
|
||||||
|
AND canonical = TRUE
|
||||||
|
AND microblock_canonical = TRUE
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
smart_contract_contract_id AS contract_id, tx_id,
|
||||||
|
block_height, microblock_sequence, tx_index
|
||||||
|
FROM txs
|
||||||
|
WHERE
|
||||||
|
smart_contract_contract_id IS NOT NULL
|
||||||
|
AND canonical = TRUE
|
||||||
|
AND microblock_canonical = TRUE
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
sender_address AS contract_id, tx_id,
|
||||||
|
block_height, microblock_sequence, tx_index
|
||||||
|
FROM txs
|
||||||
|
WHERE
|
||||||
|
sender_address LIKE '%.%'
|
||||||
|
AND canonical = TRUE
|
||||||
|
AND microblock_canonical = TRUE
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
token_transfer_recipient_address AS contract_id, tx_id,
|
||||||
|
block_height, microblock_sequence, tx_index
|
||||||
|
FROM txs
|
||||||
|
WHERE
|
||||||
|
token_transfer_recipient_address LIKE '%.%'
|
||||||
|
AND canonical = TRUE
|
||||||
|
AND microblock_canonical = TRUE
|
||||||
|
),
|
||||||
|
numbered_txs AS (
|
||||||
|
SELECT
|
||||||
|
ROW_NUMBER() OVER (
|
||||||
|
PARTITION BY contract_id
|
||||||
|
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
|
||||||
|
) AS r,
|
||||||
|
COUNT(*) OVER (
|
||||||
|
PARTITION BY contract_id
|
||||||
|
)::integer AS count,
|
||||||
|
contract_txs.*
|
||||||
|
FROM contract_txs
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
numbered_txs.contract_id,
|
||||||
|
txs.*,
|
||||||
|
CASE
|
||||||
|
WHEN txs.type_id = 2 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,
|
||||||
|
numbered_txs.count
|
||||||
|
FROM numbered_txs
|
||||||
|
INNER JOIN txs USING (tx_id)
|
||||||
|
WHERE numbered_txs.r <= 50
|
||||||
|
`);
|
||||||
|
|
||||||
|
pgm.createIndex('latest_contract_txs', 'contract_id');
|
||||||
|
pgm.createIndex('latest_contract_txs', [
|
||||||
|
{ name: 'block_height', sort: 'DESC' },
|
||||||
|
{ name: 'microblock_sequence', sort: 'DESC'},
|
||||||
|
{ name: 'tx_index', sort: 'DESC' }
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(pgm: MigrationBuilder): Promise<void> {
|
||||||
|
// Go back to the previous materialized view version, otherwise `pgm` complains it can't infer the down migration.
|
||||||
|
pgm.dropMaterializedView('latest_contract_txs', { ifExists: true, cascade: true });
|
||||||
|
pgm.createMaterializedView('latest_contract_txs', {}, `
|
||||||
|
WITH contract_txs AS (
|
||||||
|
SELECT
|
||||||
|
contract_call_contract_id AS contract_id, tx_id,
|
||||||
|
block_height, microblock_sequence, tx_index
|
||||||
|
FROM txs
|
||||||
|
WHERE
|
||||||
|
contract_call_contract_id IS NOT NULL
|
||||||
|
AND canonical = TRUE
|
||||||
|
AND microblock_canonical = TRUE
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
smart_contract_contract_id AS contract_id, tx_id,
|
||||||
|
block_height, microblock_sequence, tx_index
|
||||||
|
FROM txs
|
||||||
|
WHERE
|
||||||
|
smart_contract_contract_id IS NOT NULL
|
||||||
|
AND canonical = TRUE
|
||||||
|
AND microblock_canonical = TRUE
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
sender_address AS contract_id, tx_id,
|
||||||
|
block_height, microblock_sequence, tx_index
|
||||||
|
FROM txs
|
||||||
|
WHERE
|
||||||
|
sender_address LIKE '%.%'
|
||||||
|
AND canonical = TRUE
|
||||||
|
AND microblock_canonical = TRUE
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
token_transfer_recipient_address AS contract_id, tx_id,
|
||||||
|
block_height, microblock_sequence, tx_index
|
||||||
|
FROM txs
|
||||||
|
WHERE
|
||||||
|
token_transfer_recipient_address LIKE '%.%'
|
||||||
|
AND canonical = TRUE
|
||||||
|
AND microblock_canonical = TRUE
|
||||||
|
),
|
||||||
|
numbered_txs AS (
|
||||||
|
SELECT
|
||||||
|
ROW_NUMBER() OVER (
|
||||||
|
PARTITION BY contract_id
|
||||||
|
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
|
||||||
|
) AS r,
|
||||||
|
contract_txs.*
|
||||||
|
FROM contract_txs
|
||||||
|
)
|
||||||
|
SELECT numbered_txs.contract_id, txs.*
|
||||||
|
FROM numbered_txs
|
||||||
|
INNER JOIN txs USING (tx_id)
|
||||||
|
WHERE numbered_txs.r <= 50
|
||||||
|
`);
|
||||||
|
|
||||||
|
pgm.createIndex('latest_contract_txs', 'contract_id');
|
||||||
|
pgm.createIndex('latest_contract_txs', [
|
||||||
|
{ name: 'block_height', sort: 'DESC' },
|
||||||
|
{ name: 'microblock_sequence', sort: 'DESC'},
|
||||||
|
{ name: 'tx_index', sort: 'DESC' }
|
||||||
|
]);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { getEnumDescription } from '../helpers';
|
import { getEnumDescription } from '../helpers';
|
||||||
import { StacksMessageParsingError, NotImplementedError } from '../errors';
|
import { StacksMessageParsingError, NotImplementedError } from '../errors';
|
||||||
import { ClarityValue, deserializeCV, BufferReader } from '@stacks/transactions';
|
import { ClarityValue, deserializeCV, BufferReader, serializeCV } from '@stacks/transactions';
|
||||||
|
|
||||||
const MICROBLOCK_HEADER_SIZE =
|
const MICROBLOCK_HEADER_SIZE =
|
||||||
// 1-byte version number
|
// 1-byte version number
|
||||||
@@ -430,6 +430,17 @@ export function readClarityValueArray(input: BufferReader | Buffer): ClarityValu
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createClarityValueArray(...input: ClarityValue[]): Buffer {
|
||||||
|
const buffers = new Array<Buffer>(input.length);
|
||||||
|
for (let i = 0; i < input.length; i++) {
|
||||||
|
buffers[i] = serializeCV(input[i]);
|
||||||
|
}
|
||||||
|
const valueCountBuffer = Buffer.alloc(4);
|
||||||
|
valueCountBuffer.writeUInt32BE(input.length);
|
||||||
|
buffers.unshift(valueCountBuffer);
|
||||||
|
return Buffer.concat(buffers);
|
||||||
|
}
|
||||||
|
|
||||||
function readString(reader: BufferReader): string {
|
function readString(reader: BufferReader): string {
|
||||||
const length = reader.readUInt32BE();
|
const length = reader.readUInt32BE();
|
||||||
const str = reader.readString(length, 'ascii');
|
const str = reader.readString(length, 'ascii');
|
||||||
|
|||||||
@@ -16,9 +16,11 @@ import {
|
|||||||
ChainID,
|
ChainID,
|
||||||
AnchorMode,
|
AnchorMode,
|
||||||
intCV,
|
intCV,
|
||||||
|
uintCV,
|
||||||
|
stringAsciiCV,
|
||||||
} from '@stacks/transactions';
|
} from '@stacks/transactions';
|
||||||
import * as BN from 'bn.js';
|
import * as BN from 'bn.js';
|
||||||
import { readTransaction } from '../p2p/tx';
|
import { createClarityValueArray, readTransaction } from '../p2p/tx';
|
||||||
import { getTxFromDataStore, getBlockFromDataStore } from '../api/controllers/db-controller';
|
import { getTxFromDataStore, getBlockFromDataStore } from '../api/controllers/db-controller';
|
||||||
import {
|
import {
|
||||||
createDbTxFromCoreMsg,
|
createDbTxFromCoreMsg,
|
||||||
@@ -3877,6 +3879,8 @@ describe('api tests', () => {
|
|||||||
const testAddr2 = 'ST1HB64MAJ1MBV4CQ80GF01DZS4T1DSMX20ADCRA4';
|
const testAddr2 = 'ST1HB64MAJ1MBV4CQ80GF01DZS4T1DSMX20ADCRA4';
|
||||||
const testContractAddr = 'ST27W5M8BRKA7C5MZE2R1S1F4XTPHFWFRNHA9M04Y.hello-world';
|
const testContractAddr = 'ST27W5M8BRKA7C5MZE2R1S1F4XTPHFWFRNHA9M04Y.hello-world';
|
||||||
const testAddr4 = 'ST3DWSXBPYDB484QXFTR81K4AWG4ZB5XZNFF3H70C';
|
const testAddr4 = 'ST3DWSXBPYDB484QXFTR81K4AWG4ZB5XZNFF3H70C';
|
||||||
|
const testAddr5 = 'ST3V11C6X2EBFN72RMS3B1NYQ1BX98F61GVYRDRXW';
|
||||||
|
const testAddr6 = 'ST2F8G7616B2F8PYG216BX9AJCHP7YRK7ND7M0ZN3';
|
||||||
|
|
||||||
const block: DbBlock = {
|
const block: DbBlock = {
|
||||||
block_hash: '0x1234',
|
block_hash: '0x1234',
|
||||||
@@ -4098,6 +4102,88 @@ describe('api tests', () => {
|
|||||||
createNFtEvents(testAddr2, testAddr1, 'tendies', 100),
|
createNFtEvents(testAddr2, testAddr1, 'tendies', 100),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
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: '0x421234',
|
||||||
|
tx_index: 0,
|
||||||
|
block_height: block.block_height,
|
||||||
|
canonical: true,
|
||||||
|
event_type: DbEventTypeId.SmartContractLog,
|
||||||
|
contract_identifier: testContractAddr,
|
||||||
|
topic: 'some-topic',
|
||||||
|
value: serializeCV(bufferCVFromString('some val')),
|
||||||
|
};
|
||||||
|
const smartContract1: DbSmartContract = {
|
||||||
|
tx_id: '0x421234',
|
||||||
|
canonical: true,
|
||||||
|
block_height: block.block_height,
|
||||||
|
contract_id: testContractAddr,
|
||||||
|
source_code: '(some-contract-src)',
|
||||||
|
abi: JSON.stringify(contractJsonAbi),
|
||||||
|
};
|
||||||
|
const contractCall: DbTx = {
|
||||||
|
tx_id: '0x1232',
|
||||||
|
tx_index: 5,
|
||||||
|
anchor_mode: 3,
|
||||||
|
nonce: 0,
|
||||||
|
raw_tx: Buffer.alloc(0),
|
||||||
|
index_block_hash: block.index_block_hash,
|
||||||
|
block_hash: block.block_hash,
|
||||||
|
block_height: block.block_height,
|
||||||
|
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,
|
||||||
|
microblock_canonical: true,
|
||||||
|
microblock_sequence: I32_MAX,
|
||||||
|
microblock_hash: '',
|
||||||
|
parent_index_block_hash: '',
|
||||||
|
parent_block_hash: '',
|
||||||
|
post_conditions: Buffer.from([0x01, 0xf5]),
|
||||||
|
fee_rate: 10n,
|
||||||
|
sponsored: false,
|
||||||
|
sponsor_address: testAddr1,
|
||||||
|
sender_address: testContractAddr,
|
||||||
|
origin_hash_mode: 1,
|
||||||
|
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,
|
||||||
|
contract_call_contract_id: testContractAddr,
|
||||||
|
contract_call_function_name: 'test-contract-fn',
|
||||||
|
contract_call_function_args: createClarityValueArray(uintCV(123456), stringAsciiCV('hello')),
|
||||||
|
abi: JSON.stringify(contractJsonAbi),
|
||||||
|
};
|
||||||
|
|
||||||
const dataStoreTxs = txs.map(dbTx => {
|
const dataStoreTxs = txs.map(dbTx => {
|
||||||
return {
|
return {
|
||||||
tx: dbTx,
|
tx: dbTx,
|
||||||
@@ -4117,6 +4203,30 @@ describe('api tests', () => {
|
|||||||
stxEvents: events,
|
stxEvents: events,
|
||||||
ftEvents: ftEvents,
|
ftEvents: ftEvents,
|
||||||
nftEvents: nftEvents.flat(),
|
nftEvents: nftEvents.flat(),
|
||||||
|
contractLogEvents: [contractLogEvent1],
|
||||||
|
smartContracts: [smartContract1],
|
||||||
|
names: [],
|
||||||
|
namespaces: [],
|
||||||
|
});
|
||||||
|
dataStoreTxs.push({
|
||||||
|
tx: contractCall,
|
||||||
|
stxLockEvents: [],
|
||||||
|
stxEvents: [
|
||||||
|
{
|
||||||
|
canonical: true,
|
||||||
|
event_type: DbEventTypeId.StxAsset,
|
||||||
|
asset_event_type_id: DbAssetEventTypeId.Transfer,
|
||||||
|
event_index: 0,
|
||||||
|
tx_id: contractCall.tx_id,
|
||||||
|
tx_index: contractCall.tx_index,
|
||||||
|
block_height: contractCall.block_height,
|
||||||
|
amount: 4321n,
|
||||||
|
sender: testAddr5,
|
||||||
|
recipient: testAddr6,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ftEvents: [],
|
||||||
|
nftEvents: [],
|
||||||
contractLogEvents: [],
|
contractLogEvents: [],
|
||||||
smartContracts: [],
|
smartContracts: [],
|
||||||
names: [],
|
names: [],
|
||||||
@@ -4186,10 +4296,10 @@ describe('api tests', () => {
|
|||||||
expect(fetchAddrBalance2.type).toBe('application/json');
|
expect(fetchAddrBalance2.type).toBe('application/json');
|
||||||
const expectedResp2 = {
|
const expectedResp2 = {
|
||||||
stx: {
|
stx: {
|
||||||
balance: '101',
|
balance: '91',
|
||||||
total_sent: '15',
|
total_sent: '15',
|
||||||
total_received: '1350',
|
total_received: '1350',
|
||||||
total_fees_sent: '1234',
|
total_fees_sent: '1244',
|
||||||
total_miner_rewards_received: '0',
|
total_miner_rewards_received: '0',
|
||||||
burnchain_lock_height: 0,
|
burnchain_lock_height: 0,
|
||||||
burnchain_unlock_height: 0,
|
burnchain_unlock_height: 0,
|
||||||
@@ -4221,10 +4331,10 @@ describe('api tests', () => {
|
|||||||
expect(fetchAddrStxBalance1.status).toBe(200);
|
expect(fetchAddrStxBalance1.status).toBe(200);
|
||||||
expect(fetchAddrStxBalance1.type).toBe('application/json');
|
expect(fetchAddrStxBalance1.type).toBe('application/json');
|
||||||
const expectedStxResp1 = {
|
const expectedStxResp1 = {
|
||||||
balance: '101',
|
balance: '91',
|
||||||
total_sent: '15',
|
total_sent: '15',
|
||||||
total_received: '1350',
|
total_received: '1350',
|
||||||
total_fees_sent: '1234',
|
total_fees_sent: '1244',
|
||||||
total_miner_rewards_received: '0',
|
total_miner_rewards_received: '0',
|
||||||
burnchain_lock_height: 0,
|
burnchain_lock_height: 0,
|
||||||
burnchain_unlock_height: 0,
|
burnchain_unlock_height: 0,
|
||||||
@@ -4361,7 +4471,7 @@ describe('api tests', () => {
|
|||||||
const expectedResp4 = {
|
const expectedResp4 = {
|
||||||
limit: 20,
|
limit: 20,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
total: 3,
|
total: 4,
|
||||||
results: [
|
results: [
|
||||||
{
|
{
|
||||||
tx_id: '0x12340005',
|
tx_id: '0x12340005',
|
||||||
@@ -4403,6 +4513,62 @@ describe('api tests', () => {
|
|||||||
execution_cost_write_count: 0,
|
execution_cost_write_count: 0,
|
||||||
execution_cost_write_length: 0,
|
execution_cost_write_length: 0,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
tx_id: '0x1232',
|
||||||
|
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,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
tx_id: '0x12340003',
|
tx_id: '0x12340003',
|
||||||
tx_status: 'success',
|
tx_status: 'success',
|
||||||
@@ -4486,6 +4652,76 @@ describe('api tests', () => {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
expect(JSON.parse(fetchAddrTx1.text)).toEqual(expectedResp4);
|
expect(JSON.parse(fetchAddrTx1.text)).toEqual(expectedResp4);
|
||||||
|
|
||||||
|
const fetchAddrTx2 = await supertest(api.server).get(
|
||||||
|
`/extended/v1/address/${testAddr5}/transactions`
|
||||||
|
);
|
||||||
|
expect(fetchAddrTx2.status).toBe(200);
|
||||||
|
expect(fetchAddrTx2.type).toBe('application/json');
|
||||||
|
const expectedResp5 = {
|
||||||
|
limit: 20,
|
||||||
|
offset: 0,
|
||||||
|
total: 1,
|
||||||
|
results: [
|
||||||
|
{
|
||||||
|
tx_id: '0x1232',
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
expect(JSON.parse(fetchAddrTx2.text)).toEqual(expectedResp5);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('list contract log events', async () => {
|
test('list contract log events', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user