Skip to content

store and allow retrieval of transaction results #129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,6 @@ src/schemas

# Webstorm editor files
.idea

# OS specific
.DS_Store
13 changes: 13 additions & 0 deletions docs/entities/transactions/abstract-transaction.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@
"tx_status": {
"$ref": "./transaction-status.schema.json"
},
"tx_result": {
"type": "object",
"required": ["hex", "repr"],
"additionalProperties": false,
"properties": {
"hex": {
"type": "string"
},
"repr": {
"type": "string"
}
}
},
"fee_rate": {
"type": "string",
"description": "Integer string (64-bit unsigned integer)."
Expand Down
20 changes: 20 additions & 0 deletions docs/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ export interface TokenTransferTransaction {
tx_id: string;
tx_index?: number;
tx_status: TransactionStatus;
tx_result?: {
hex: string;
repr: string;
};
/**
* Integer string (64-bit unsigned integer).
*/
Expand Down Expand Up @@ -244,6 +248,10 @@ export interface SmartContractTransaction {
tx_id: string;
tx_index?: number;
tx_status: TransactionStatus;
tx_result?: {
hex: string;
repr: string;
};
/**
* Integer string (64-bit unsigned integer).
*/
Expand Down Expand Up @@ -280,6 +288,10 @@ export interface ContractCallTransaction {
tx_id: string;
tx_index?: number;
tx_status: TransactionStatus;
tx_result?: {
hex: string;
repr: string;
};
/**
* Integer string (64-bit unsigned integer).
*/
Expand Down Expand Up @@ -323,6 +335,10 @@ export interface PoisonMicroblockTransaction {
tx_id: string;
tx_index?: number;
tx_status: TransactionStatus;
tx_result?: {
hex: string;
repr: string;
};
/**
* Integer string (64-bit unsigned integer).
*/
Expand Down Expand Up @@ -360,6 +376,10 @@ export interface CoinbaseTransaction {
tx_id: string;
tx_index?: number;
tx_status: TransactionStatus;
tx_result?: {
hex: string;
repr: string;
};
/**
* Integer string (64-bit unsigned integer).
*/
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"lint:eslint": "eslint . --ext .js,.jsx,.ts,.tsx -f codeframe",
"lint:prettier": "prettier --check src/**/*.{ts,json}",
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx -f codeframe --fix",
"migrate": "node-pg-migrate -m src/migrations",
"devenv:build": "docker-compose -f docker-compose.dev.postgres.yml -f docker-compose.dev.stacks-blockchain.yml -f docker-compose.dev.bitcoind.yml build --no-cache",
"devenv:deploy": "docker-compose -f docker-compose.dev.postgres.yml -f docker-compose.dev.stacks-blockchain.yml -f docker-compose.dev.bitcoind.yml up",
"devenv:stop": "docker-compose -f docker-compose.dev.postgres.yml -f docker-compose.dev.stacks-blockchain.yml -f docker-compose.dev.bitcoind.yml down -v -t 0",
Expand Down Expand Up @@ -56,7 +57,7 @@
"node-fetch": "^2.6.0",
"node-pg-migrate": "^4.2.3",
"p-queue": "^6.3.0",
"pg": "^7.18.2",
"pg": "^8.2.1",
"rpc-bitcoin": "^2.0.0",
"smart-buffer": "^4.1.0",
"strict-event-emitter-types": "^2.0.0",
Expand Down
10 changes: 10 additions & 0 deletions src/api/controllers/db-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,19 @@ export async function getTxFromDataStore(
dbTxEvents = eventsQuery.results;
}

let tx_result;
if ((dbTx as DbTx).raw_result !== undefined && (dbTx as DbTx).raw_result !== null) {
const valueHex = (dbTx as DbTx).raw_result;
tx_result = {
hex: valueHex,
repr: cvToString(deserializeCV(Buffer.from(valueHex.substring(2), 'hex'))),
};
}

const apiTx: Partial<Transaction> = {
tx_id: dbTx.tx_id,
tx_status: getTxStatusString(dbTx.status),
tx_result,
tx_type: getTxTypeString(dbTx.type_id),

fee_rate: dbTx.fee_rate.toString(10),
Expand Down
3 changes: 3 additions & 0 deletions src/datastore/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ export interface DbTx {
type_id: DbTxTypeId;

status: DbTxStatus;
raw_result: string;

/** Set to `true` if entry corresponds to the canonical chain tip */
canonical: boolean;
post_conditions: Buffer;
Expand Down Expand Up @@ -401,6 +403,7 @@ export function createDbTxFromCoreMsg(msg: CoreNodeParsedTxMessage): DbTx {
burn_block_time: msg.burn_block_time,
type_id: parseEnum(DbTxTypeId, rawTx.payload.typeId as number),
status: getTxDbStatus(coreTx.status),
raw_result: coreTx.raw_result,
fee_rate: rawTx.auth.originCondition.feeRate,
sender_address: msg.sender_address,
origin_hash_mode: rawTx.auth.originCondition.hashMode as number,
Expand Down
59 changes: 33 additions & 26 deletions src/datastore/postgres-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export async function cycleMigrations(): Promise<void> {

const TX_COLUMNS = `
-- required columns
tx_id, tx_index, index_block_hash, block_hash, block_height, burn_block_time, type_id, status,
tx_id, tx_index, index_block_hash, block_hash, block_height, burn_block_time, type_id, status,
canonical, post_conditions, fee_rate, sponsored, sender_address, origin_hash_mode,

-- token-transfer tx columns
Expand All @@ -114,12 +114,15 @@ const TX_COLUMNS = `
poison_microblock_header_1, poison_microblock_header_2,

-- coinbase tx columns
coinbase_payload
coinbase_payload,

-- tx result
raw_result
`;

const MEMPOOL_TX_COLUMNS = `
-- required columns
tx_id, type_id, status,
tx_id, type_id, status,
post_conditions, fee_rate, sponsored, sender_address, origin_hash_mode,

-- token-transfer tx columns
Expand Down Expand Up @@ -158,6 +161,7 @@ interface MempoolTxQueryResult {

type_id: number;
status: number;
raw_result: Buffer;
canonical: boolean;
post_conditions: Buffer;
fee_rate: string;
Expand Down Expand Up @@ -196,6 +200,7 @@ interface TxQueryResult {
burn_block_time: number;
type_id: number;
status: number;
raw_result: Buffer;
canonical: boolean;
post_conditions: Buffer;
fee_rate: string;
Expand Down Expand Up @@ -533,9 +538,9 @@ export class PgDataStore extends (EventEmitter as { new (): DataStoreEventEmitte
-- check if the parent block is also orphaned
SELECT index_block_hash
FROM blocks
WHERE
block_height = $1 AND
index_block_hash = $2 AND
WHERE
block_height = $1 AND
index_block_hash = $2 AND
canonical = false
`,
[blockResult.rows[0].block_height - 1, blockResult.rows[0].parent_index_block_hash]
Expand Down Expand Up @@ -806,7 +811,7 @@ export class PgDataStore extends (EventEmitter as { new (): DataStoreEventEmitte
`
INSERT INTO txs(
${TX_COLUMNS}
) values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25)
) values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26)
ON CONFLICT ON CONSTRAINT unique_tx_id_index_block_hash
DO NOTHING
`,
Expand Down Expand Up @@ -836,6 +841,7 @@ export class PgDataStore extends (EventEmitter as { new (): DataStoreEventEmitte
tx.poison_microblock_header_1,
tx.poison_microblock_header_2,
tx.coinbase_payload,
hexToBuffer(tx.raw_result),
]
);
return result.rowCount;
Expand Down Expand Up @@ -924,6 +930,7 @@ export class PgDataStore extends (EventEmitter as { new (): DataStoreEventEmitte
burn_block_time: result.burn_block_time,
type_id: result.type_id as DbTxTypeId,
status: result.status,
raw_result: result.raw_result ? bufferToHexPrefixString(result.raw_result) : '',
canonical: result.canonical,
post_conditions: result.post_conditions,
fee_rate: BigInt(result.fee_rate),
Expand Down Expand Up @@ -1075,9 +1082,9 @@ export class PgDataStore extends (EventEmitter as { new (): DataStoreEventEmitte
amount: string;
}>(
`
SELECT
event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, amount
FROM stx_events
SELECT
event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, amount
FROM stx_events
WHERE tx_id = $1 AND index_block_hash = $2
`,
[txIdBuffer, blockHashBuffer]
Expand All @@ -1095,9 +1102,9 @@ export class PgDataStore extends (EventEmitter as { new (): DataStoreEventEmitte
amount: string;
}>(
`
SELECT
event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, asset_identifier, amount
FROM ft_events
SELECT
event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, asset_identifier, amount
FROM ft_events
WHERE tx_id = $1 AND index_block_hash = $2
`,
[txIdBuffer, blockHashBuffer]
Expand All @@ -1115,9 +1122,9 @@ export class PgDataStore extends (EventEmitter as { new (): DataStoreEventEmitte
value: Buffer;
}>(
`
SELECT
event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, asset_identifier, value
FROM nft_events
SELECT
event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, asset_identifier, value
FROM nft_events
WHERE tx_id = $1 AND index_block_hash = $2
`,
[txIdBuffer, blockHashBuffer]
Expand All @@ -1133,9 +1140,9 @@ export class PgDataStore extends (EventEmitter as { new (): DataStoreEventEmitte
value: Buffer;
}>(
`
SELECT
event_index, tx_id, tx_index, block_height, canonical, contract_identifier, topic, value
FROM contract_logs
SELECT
event_index, tx_id, tx_index, block_height, canonical, contract_identifier, topic, value
FROM contract_logs
WHERE tx_id = $1 AND index_block_hash = $2
`,
[txIdBuffer, blockHashBuffer]
Expand Down Expand Up @@ -1414,19 +1421,19 @@ export class PgDataStore extends (EventEmitter as { new (): DataStoreEventEmitte
}>(
`
SELECT * FROM (
SELECT
SELECT
'stx' as asset_type, event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, '<stx>' as asset_identifier, amount::numeric(78, 0), null::bytea as value
FROM stx_events
FROM stx_events
WHERE canonical = true AND (sender = $1 OR recipient = $1)
UNION ALL
SELECT
SELECT
'ft' as asset_type, event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, asset_identifier, amount, null::bytea as value
FROM ft_events
FROM ft_events
WHERE canonical = true AND (sender = $1 OR recipient = $1)
UNION ALL
SELECT
'nft' as asset_type, event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, asset_identifier, null::numeric(78, 0) as amount, value
FROM nft_events
SELECT
'nft' as asset_type, event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, asset_identifier, null::numeric(78, 0) as amount, value
FROM nft_events
WHERE canonical = true AND (sender = $1 OR recipient = $1)
) asset_events
ORDER BY block_height DESC, tx_index DESC, event_index DESC
Expand Down
1 change: 1 addition & 0 deletions src/event-stream/core-node-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export interface CoreNodeTxMessage {
raw_tx: string;
result: NonStandardClarityValue;
status: CoreNodeTxStatus;
raw_result: string;
txid: string;
tx_index: number;
contract_abi: ClarityAbi | null;
Expand Down
17 changes: 17 additions & 0 deletions src/migrations/1593415759720_add-txs-raw-result.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* 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.addColumns('txs', {
raw_result: {
type: 'bytea',
notNull: false, // to avoid migration issues for previous txs not including
},
});
}

export async function down(pgm: MigrationBuilder): Promise<void> {
pgm.dropColumns('txs', ['raw_result']);
}
Loading