feat: ingestion for TenureChange and NakamotoCoinbase tx types (#1753)

* feat: ingestion for TenureChange and NakamotoCoinbase tx types

* fix: add new tx fields to batch tx insert query

* chore: bump stacks-encoding-native-js

* test: fix flaky socket-io timeout test
This commit is contained in:
Matthew Little
2023-12-08 12:39:52 +01:00
committed by GitHub
parent f33d4da43e
commit 7c45f53622
24 changed files with 468 additions and 12 deletions

20
.vscode/launch.json vendored
View File

@@ -48,6 +48,26 @@
},
"killBehavior": "polite",
},
{
"type": "node",
"request": "launch",
"name": "Launch: w/ postgres",
"skipFiles": [
"<node_internals>/**"
],
"runtimeArgs": ["-r", "ts-node/register/transpile-only", "-r", "tsconfig-paths/register"],
"args": ["${workspaceFolder}/src/index.ts"],
"outputCapture": "std",
"internalConsoleOptions": "openOnSessionStart",
"preLaunchTask": "deploy:pg",
"postDebugTask": "stop:pg",
"env": {
"STACKS_CHAIN_ID": "0x80000000",
"NODE_ENV": "development",
"TS_NODE_SKIP_IGNORE": "true"
},
"killBehavior": "polite",
},
{
"type": "node",
"request": "launch",

23
.vscode/tasks.json vendored
View File

@@ -44,6 +44,29 @@
},
"presentation": { "echo": true, "reveal": "always", "focus": false, "panel": "dedicated", "clear": false }
},
{
"label": "deploy:pg",
"type": "shell",
"command": "docker compose -f docker/docker-compose.dev.postgres.yml up --force-recreate -V",
"isBackground": true,
"problemMatcher": [{
"pattern": [{ "regexp": ".", "file": 1, "location": 2, "message": 3 }],
"background": { "activeOnStart": true, "beginsPattern": ".", "endsPattern": "." }
}],
"presentation": { "echo": true, "reveal": "always", "focus": false, "panel": "dedicated", "clear": false }
},
{
"label": "stop:pg",
"type": "shell",
"command": "docker compose -f docker/docker-compose.dev.postgres.yml down -v -t 0",
"presentation": {
"echo": true,
"reveal": "silent",
"focus": false,
"panel": "shared",
"clear": false
}
},
{
"label": "deploy:subnets",
"type": "shell",

View File

@@ -0,0 +1,13 @@
{
"type": "object",
"title": "MempoolTenureChangeTransaction",
"description": "Describes representation of a Type 7 Stacks transaction: Tenure Change",
"allOf": [
{
"$ref": "./abstract-transaction.schema.json"
},
{
"$ref": "../transactions/transaction-7-tenure-change-metadata.schema.json"
}
]
}

View File

@@ -17,6 +17,9 @@
},
{
"$ref": "./transaction-4-coinbase.schema.json"
},
{
"$ref": "./transaction-7-tenure-change.schema.json"
}
]
}

View File

@@ -22,6 +22,11 @@
"type": "string",
"nullable": true,
"description": "A principal that will receive the miner rewards for this coinbase transaction. Can be either a standard principal or contract principal. Only specified for `coinbase-to-alt-recipient` transaction types, otherwise null."
},
"vrf_proof": {
"type": "string",
"nullable": true,
"description": "Hex encoded 80-byte VRF proof"
}
}
}

View File

@@ -0,0 +1,45 @@
{
"type": "object",
"title": "TenureChangeTransactionMetadata",
"description": "Describes representation of a Type 7 Stacks transaction: Tenure Change",
"required": ["tx_type"],
"additionalProperties": false,
"properties": {
"tx_type": {
"type": "string",
"enum": ["tenure_change"]
},
"tenure_change_payload": {
"type": "object",
"additionalProperties": false,
"required": ["previous_tenure_end", "previous_tenure_blocks", "cause", "pubkey_hash", "signature", "signers"],
"properties": {
"previous_tenure_end": {
"type": "string",
"description": "(Hex string) Stacks Block hash"
},
"previous_tenure_blocks": {
"type": "number",
"description": "The number of blocks produced in the previous tenure."
},
"cause": {
"type": "string",
"enum": ["block_found", "no_block_found", "null_miner"],
"description": "Cause of change in mining tenure. Depending on cause, tenure can be ended or extended."
},
"pubkey_hash": {
"type": "string",
"description": "(Hex string) The ECDSA public key hash of the current tenure."
},
"signature": {
"type": "string",
"description": "(Hex string) A Schnorr signature from the Stackers."
},
"signers": {
"type": "string",
"description": "(Hex string) A bitmap of which Stackers signed."
}
}
}
}
}

View File

@@ -0,0 +1,25 @@
{
"tx_id": "0x5e9f3933e358df6a73fec0d47ce3e1062c20812c129f5294e6f37a8d27c051d9",
"tx_status": "success",
"tx_type": "coinbase",
"fee_rate": "0",
"sender_address": "ST3WCQ6S0DFT7YHF53M8JPKGDS1N1GSSR91677XF1",
"sponsored": false,
"post_condition_mode": "deny",
"is_unanchored": false,
"microblock_hash": "",
"microblock_sequence": 2147483647,
"microblock_canonical": true,
"block_hash": "0x58412b50266debd0c35b1a20348ad9c0f17e5525fb155a97033256c83c9e2491",
"block_height": 3231,
"burn_block_time": 1594230455,
"canonical": true,
"tx_index": 0,
"tx_result": {
"hex": "0x03",
"repr": "true"
},
"coinbase_payload": {
"data": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
}

View File

@@ -0,0 +1,13 @@
{
"type": "object",
"title": "TenureChangeTransaction",
"description": "Describes representation of a Type 7 Stacks transaction: Tenure Change",
"allOf": [
{
"$ref": "./abstract-transaction.schema.json"
},
{
"$ref": "./transaction-7-tenure-change-metadata.schema.json"
}
]
}

View File

@@ -16,6 +16,9 @@
},
{
"$ref": "./transaction-4-coinbase-metadata.schema.json"
},
{
"$ref": "./transaction-7-tenure-change-metadata.schema.json"
}
]
}

View File

@@ -2,5 +2,5 @@
"title": "TransactionType",
"description": "String literal of all Stacks 2.0 transaction types",
"type": "string",
"enum": ["token_transfer", "smart_contract", "contract_call", "poison_microblock", "coinbase"]
"enum": ["token_transfer", "smart_contract", "contract_call", "poison_microblock", "coinbase", "tenure_change"]
}

View File

@@ -17,6 +17,9 @@
},
{
"$ref": "./transaction-4-coinbase.schema.json"
},
{
"$ref": "./transaction-7-tenure-change.schema.json"
}
]
}

64
docs/generated.d.ts vendored
View File

@@ -127,6 +127,7 @@ export type SchemaMergeRootStub =
| MempoolContractCallTransaction
| MempoolPoisonMicroblockTransaction
| MempoolCoinbaseTransaction
| MempoolTenureChangeTransaction
| MempoolTransactionStatus
| MempoolTransaction
| Microblock
@@ -209,6 +210,8 @@ export type SchemaMergeRootStub =
| PoisonMicroblockTransaction
| CoinbaseTransactionMetadata
| CoinbaseTransaction
| TenureChangeTransactionMetadata
| TenureChangeTransaction
| TransactionFound
| TransactionList
| TransactionMetadata
@@ -324,7 +327,8 @@ export type Transaction =
| SmartContractTransaction
| ContractCallTransaction
| PoisonMicroblockTransaction
| CoinbaseTransaction;
| CoinbaseTransaction
| TenureChangeTransaction;
/**
* Describes representation of a Type-0 Stacks 2.0 transaction. https://github.com/blockstack/stacks-blockchain/blob/master/sip/sip-005-blocks-and-transactions.md#type-0-transferring-an-asset
*/
@@ -526,6 +530,10 @@ export type PoisonMicroblockTransaction = AbstractTransaction & PoisonMicroblock
* Describes representation of a Type 3 Stacks 2.0 transaction: Poison Microblock
*/
export type CoinbaseTransaction = AbstractTransaction & CoinbaseTransactionMetadata;
/**
* Describes representation of a Type 7 Stacks transaction: Tenure Change
*/
export type TenureChangeTransaction = AbstractTransaction & TenureChangeTransactionMetadata;
/**
* Describes all transaction types on Stacks 2.0 blockchain
*/
@@ -534,7 +542,8 @@ export type MempoolTransaction =
| MempoolSmartContractTransaction
| MempoolContractCallTransaction
| MempoolPoisonMicroblockTransaction
| MempoolCoinbaseTransaction;
| MempoolCoinbaseTransaction
| MempoolTenureChangeTransaction;
/**
* Describes representation of a Type-0 Stacks 2.0 transaction. https://github.com/blockstack/stacks-blockchain/blob/master/sip/sip-005-blocks-and-transactions.md#type-0-transferring-an-asset
*/
@@ -578,6 +587,10 @@ export type MempoolPoisonMicroblockTransaction = AbstractMempoolTransaction & Po
* Describes representation of a Type 3 Stacks 2.0 transaction: Poison Microblock
*/
export type MempoolCoinbaseTransaction = AbstractMempoolTransaction & CoinbaseTransactionMetadata;
/**
* Describes representation of a Type 7 Stacks transaction: Tenure Change
*/
export type MempoolTenureChangeTransaction = AbstractMempoolTransaction & TenureChangeTransactionMetadata;
/**
* Fetch a user's raw zone file. This only works for RFC-compliant zone files. This method returns an error for names that have non-standard zone files.
*/
@@ -705,11 +718,18 @@ export type TransactionMetadata =
| SmartContractTransactionMetadata
| ContractCallTransactionMetadata
| PoisonMicroblockTransactionMetadata
| CoinbaseTransactionMetadata;
| CoinbaseTransactionMetadata
| TenureChangeTransactionMetadata;
/**
* String literal of all Stacks 2.0 transaction types
*/
export type TransactionType = "token_transfer" | "smart_contract" | "contract_call" | "poison_microblock" | "coinbase";
export type TransactionType =
| "token_transfer"
| "smart_contract"
| "contract_call"
| "poison_microblock"
| "coinbase"
| "tenure_change";
export type RpcAddressBalanceNotificationParams = {
address: string;
} & AddressStxBalanceResponse;
@@ -1098,6 +1118,42 @@ export interface CoinbaseTransactionMetadata {
* A principal that will receive the miner rewards for this coinbase transaction. Can be either a standard principal or contract principal. Only specified for `coinbase-to-alt-recipient` transaction types, otherwise null.
*/
alt_recipient?: string;
/**
* Hex encoded 80-byte VRF proof
*/
vrf_proof?: string;
};
}
/**
* Describes representation of a Type 7 Stacks transaction: Tenure Change
*/
export interface TenureChangeTransactionMetadata {
tx_type: "tenure_change";
tenure_change_payload?: {
/**
* (Hex string) Stacks Block hash
*/
previous_tenure_end: string;
/**
* The number of blocks produced in the previous tenure.
*/
previous_tenure_blocks: number;
/**
* Cause of change in mining tenure. Depending on cause, tenure can be ended or extended.
*/
cause: "block_found" | "no_block_found" | "null_miner";
/**
* (Hex string) The ECDSA public key hash of the current tenure.
*/
pubkey_hash: string;
/**
* (Hex string) A Schnorr signature from the Stackers.
*/
signature: string;
/**
* (Hex string) A bitmap of which Stackers signed.
*/
signers: string;
};
}
/**

View File

@@ -228,7 +228,7 @@ paths:
example: coinbase
items:
type: string
enum: [coinbase, token_transfer, smart_contract, contract_call, poison_microblock]
enum: [coinbase, token_transfer, smart_contract, contract_call, poison_microblock, tenure_change]
- name: unanchored
in: query
description: Include transaction data from unanchored (i.e. unconfirmed) microblocks

View File

@@ -0,0 +1,44 @@
/** @param { import("node-pg-migrate").MigrationBuilder } pgm */
exports.up = pgm => {
pgm.addColumns('txs', {
// `nakamoto-coinbase` tx types
coinbase_vrf_proof: 'bytea',
// `tenure-change` tx types
tenure_change_previous_tenure_end: 'bytea',
tenure_change_previous_tenure_blocks: 'integer',
tenure_change_cause: 'smallint',
tenure_change_pubkey_hash: 'bytea',
tenure_change_signature: 'bytea',
tenure_change_signers: 'bytea',
});
pgm.addColumns('mempool_txs', {
// `nakamoto-coinbase` tx types
coinbase_vrf_proof: 'bytea',
// `tenure-change` tx types
tenure_change_previous_tenure_end: 'bytea',
tenure_change_previous_tenure_blocks: 'integer',
tenure_change_cause: 'smallint',
tenure_change_pubkey_hash: 'bytea',
tenure_change_signature: 'bytea',
tenure_change_signers: 'bytea',
});
pgm.addConstraint('txs', 'valid_tenure-change', `CHECK (type_id != 7 OR (
NOT (tenure_change_previous_tenure_end, tenure_change_previous_tenure_blocks, tenure_change_cause, tenure_change_pubkey_hash, tenure_change_signature, tenure_change_signers) IS NULL
))`);
pgm.addConstraint('txs', 'valid_nakamoto-coinbase', `CHECK (type_id != 8 OR (
NOT (coinbase_payload, coinbase_vrf_proof) IS NULL
))`);
pgm.addConstraint('mempool_txs', 'valid_tenure-change', `CHECK (type_id != 7 OR (
NOT (tenure_change_previous_tenure_end, tenure_change_previous_tenure_blocks, tenure_change_cause, tenure_change_pubkey_hash, tenure_change_signature, tenure_change_signers) IS NULL
))`);
pgm.addConstraint('mempool_txs', 'valid_nakamoto-coinbase', `CHECK (type_id != 8 OR (
NOT (coinbase_payload, coinbase_vrf_proof) IS NULL
))`);
};

8
package-lock.json generated
View File

@@ -62,7 +62,7 @@
"socket.io": "4.6.1",
"source-map-support": "0.5.21",
"split2": "3.2.2",
"stacks-encoding-native-js": "1.0.0",
"stacks-encoding-native-js": "1.1.0-beta.3",
"strict-event-emitter-types": "2.0.0",
"tiny-secp256k1": "2.2.1",
"ts-unused-exports": "7.0.3",
@@ -12825,9 +12825,9 @@
"dev": true
},
"node_modules/stacks-encoding-native-js": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/stacks-encoding-native-js/-/stacks-encoding-native-js-1.0.0.tgz",
"integrity": "sha512-7lbcU98ozN+/XvMViXc1cZe72PB3Lz/Fcw5Lv4xcRbDfZDqdT4LqNzDfApb0TrrPWDf1moT2jtR5Lq0pSm1byQ==",
"version": "1.1.0-beta.3",
"resolved": "https://registry.npmjs.org/stacks-encoding-native-js/-/stacks-encoding-native-js-1.1.0-beta.3.tgz",
"integrity": "sha512-A9Fh/hAs0CK8XTv/F5fyLAcoH2ONTPuHoQO19qfwgvpgJcbsdVKrrdaf/N5604YWilA1SK80bXFV7va5+aBiFw==",
"dependencies": {
"@types/node": "^16.11.26",
"detect-libc": "^2.0.1"

View File

@@ -137,7 +137,7 @@
"socket.io": "4.6.1",
"source-map-support": "0.5.21",
"split2": "3.2.2",
"stacks-encoding-native-js": "1.0.0",
"stacks-encoding-native-js": "1.1.0-beta.3",
"strict-event-emitter-types": "2.0.0",
"tiny-secp256k1": "2.2.1",
"ts-unused-exports": "7.0.3",

View File

@@ -26,6 +26,7 @@ import {
RosettaParentBlockIdentifier,
RosettaTransaction,
SmartContractTransactionMetadata,
TenureChangeTransactionMetadata,
TokenTransferTransactionMetadata,
Transaction,
TransactionAnchorModeType,
@@ -115,6 +116,19 @@ function getTxAnchorModeString(anchorMode: number): TransactionAnchorModeType {
}
}
function getTxTenureChangeCauseString(cause: number) {
switch (cause) {
case 0:
return 'block_found';
case 1:
return 'no_block_found';
case 2:
return 'null_miner';
default:
throw new Error(`Unexpected tenure change cause value ${cause}`);
}
}
export function getTxTypeId(typeString: Transaction['tx_type']): DbTxTypeId[] {
switch (typeString) {
case 'token_transfer':
@@ -901,6 +915,48 @@ function parseDbTxTypeMetadata(dbTx: DbTx | DbMempoolTx): TransactionMetadata {
};
return metadata;
}
case DbTxTypeId.NakamotoCoinbase: {
const metadata: CoinbaseTransactionMetadata = {
tx_type: 'coinbase',
coinbase_payload: {
data: unwrapOptional(dbTx.coinbase_payload, () => 'Unexpected nullish coinbase_payload'),
alt_recipient: dbTx.coinbase_alt_recipient ?? (null as any),
vrf_proof: unwrapOptional(dbTx.coinbase_vrf_proof, () => 'Unexpected nullish vrf_proof'),
},
};
return metadata;
}
case DbTxTypeId.TenureChange: {
const metadata: TenureChangeTransactionMetadata = {
tx_type: 'tenure_change',
tenure_change_payload: {
previous_tenure_end: unwrapOptional(
dbTx.tenure_change_previous_tenure_end,
() => 'Unexpected nullish tenure_change_previous_tenure_end'
),
previous_tenure_blocks: unwrapOptional(
dbTx.tenure_change_previous_tenure_blocks,
() => 'Unexpected nullish tenure_change_previous_tenure_blocks'
),
cause: getTxTenureChangeCauseString(
unwrapOptional(dbTx.tenure_change_cause, () => 'Unexpected nullish tenure_change_cause')
),
pubkey_hash: unwrapOptional(
dbTx.tenure_change_pubkey_hash,
() => 'Unexpected nullish tenure_change_pubkey_hash'
),
signature: unwrapOptional(
dbTx.tenure_change_signature,
() => 'Unexpected nullish tenure_change_signature'
),
signers: unwrapOptional(
dbTx.tenure_change_signers,
() => 'Unexpected nullish tenure_change_signers'
),
},
};
return metadata;
}
default: {
throw new Error(`Unexpected DbTxTypeId: ${dbTx.type_id}`);
}

View File

@@ -89,6 +89,8 @@ export enum DbTxTypeId {
Coinbase = 0x04,
CoinbaseToAltRecipient = 0x05,
VersionedSmartContract = 0x06,
TenureChange = 0x07,
NakamotoCoinbase = 0x08,
}
export enum DbTxStatus {
@@ -138,6 +140,14 @@ export interface BaseTx {
/** Hex encoded Clarity values. Undefined if function defines no args. */
contract_call_function_args?: string;
abi?: string;
/** Only valid for `tenure-change` tx types. */
tenure_change_previous_tenure_end?: string;
tenure_change_previous_tenure_blocks?: number;
tenure_change_cause?: number;
tenure_change_pubkey_hash?: string;
tenure_change_signature?: string;
tenure_change_signers?: string;
}
export interface DbTx extends BaseTx {
@@ -185,6 +195,9 @@ export interface DbTx extends BaseTx {
/** Only valid for `coinbase-to-alt-recipient` tx types. Either a standard principal or contract principal. */
coinbase_alt_recipient?: string;
/** Only valid for `nakamoto-coinbase` tx types. Hex encoded 80-bytes. */
coinbase_vrf_proof?: string;
event_count: number;
execution_cost_read_count: number;
@@ -260,6 +273,9 @@ export interface DbMempoolTx extends BaseTx {
/** Only valid for `coinbase-to-alt-recipient` tx types. Either a standard principal or contract principal. */
coinbase_alt_recipient?: string;
/** Only valid for `nakamoto-coinbase` tx types. Hex encoded 80-bytes. */
coinbase_vrf_proof?: string;
}
export interface DbMempoolTxRaw extends DbMempoolTx {
@@ -828,6 +844,17 @@ export interface MempoolTxQueryResult {
/** Only valid for `coinbase-to-alt-recipient` tx types. Either a standard principal or contract principal. */
coinbase_alt_recipient?: string;
/** Only valid for `nakamoto-coinbase` tx types. Hex encoded 80-bytes. */
coinbase_vrf_proof?: string;
// `tenure-change` tx types
tenure_change_previous_tenure_end?: string;
tenure_change_previous_tenure_blocks?: number;
tenure_change_cause?: number;
tenure_change_pubkey_hash: string;
tenure_change_signature?: string;
tenure_change_signers?: string;
// sending abi in case tx is contract call
abi: unknown | null;
}
@@ -888,6 +915,17 @@ export interface TxQueryResult {
// `coinbase-to-alt-recipient` tx types
coinbase_alt_recipient?: string;
// `nakamoto-coinbase` tx types. Hex encoded 80-bytes.
coinbase_vrf_proof?: string;
// `tenure-change` tx types
tenure_change_previous_tenure_end?: string;
tenure_change_previous_tenure_blocks?: number;
tenure_change_cause?: number;
tenure_change_pubkey_hash: string;
tenure_change_signature?: string;
tenure_change_signers?: string;
// events count
event_count: number;
@@ -1010,6 +1048,13 @@ export interface TxInsertValues {
poison_microblock_header_2: PgBytea | null;
coinbase_payload: PgBytea | null;
coinbase_alt_recipient: string | null;
coinbase_vrf_proof: string | null;
tenure_change_previous_tenure_end: string | null;
tenure_change_previous_tenure_blocks: number | null;
tenure_change_cause: number | null;
tenure_change_pubkey_hash: string | null;
tenure_change_signature: string | null;
tenure_change_signers: string | null;
raw_result: PgBytea;
event_count: number;
execution_cost_read_count: number;
@@ -1049,6 +1094,13 @@ export interface MempoolTxInsertValues {
poison_microblock_header_2: PgBytea | null;
coinbase_payload: PgBytea | null;
coinbase_alt_recipient: string | null;
coinbase_vrf_proof: string | null;
tenure_change_previous_tenure_end: string | null;
tenure_change_previous_tenure_blocks: number | null;
tenure_change_cause: number | null;
tenure_change_pubkey_hash: string | null;
tenure_change_signature: string | null;
tenure_change_signers: string | null;
}
export interface BlockInsertValues {

View File

@@ -102,6 +102,13 @@ export const TX_COLUMNS = [
'poison_microblock_header_2',
'coinbase_payload',
'coinbase_alt_recipient',
'coinbase_vrf_proof',
'tenure_change_previous_tenure_end',
'tenure_change_previous_tenure_blocks',
'tenure_change_cause',
'tenure_change_pubkey_hash',
'tenure_change_signature',
'tenure_change_signers',
'raw_result',
'event_count',
'execution_cost_read_count',
@@ -140,6 +147,13 @@ export const MEMPOOL_TX_COLUMNS = [
'poison_microblock_header_2',
'coinbase_payload',
'coinbase_alt_recipient',
'coinbase_vrf_proof',
'tenure_change_previous_tenure_end',
'tenure_change_previous_tenure_blocks',
'tenure_change_cause',
'tenure_change_pubkey_hash',
'tenure_change_signature',
'tenure_change_signers',
];
export const BLOCK_COLUMNS = [
@@ -370,6 +384,19 @@ function parseTxTypeSpecificQueryResult(
} else if (target.type_id === DbTxTypeId.CoinbaseToAltRecipient) {
target.coinbase_payload = result.coinbase_payload;
target.coinbase_alt_recipient = result.coinbase_alt_recipient;
} else if (target.type_id === DbTxTypeId.NakamotoCoinbase) {
target.coinbase_payload = result.coinbase_payload;
if (result.coinbase_alt_recipient) {
target.coinbase_alt_recipient = result.coinbase_alt_recipient;
}
target.coinbase_vrf_proof = result.coinbase_vrf_proof;
} else if (target.type_id === DbTxTypeId.TenureChange) {
target.tenure_change_previous_tenure_end = result.tenure_change_previous_tenure_end;
target.tenure_change_previous_tenure_blocks = result.tenure_change_previous_tenure_blocks;
target.tenure_change_cause = result.tenure_change_cause;
target.tenure_change_pubkey_hash = result.tenure_change_pubkey_hash;
target.tenure_change_signature = result.tenure_change_signature;
target.tenure_change_signers = result.tenure_change_signers;
} else {
throw new Error(`Received unexpected tx type_id from db query: ${target.type_id}`);
}
@@ -994,6 +1021,25 @@ function extractTransactionPayload(txData: DecodedTxResult, dbTx: DbTx | DbMempo
}
break;
}
case TxPayloadTypeID.NakamotoCoinbase: {
dbTx.coinbase_payload = txData.payload.payload_buffer;
if (txData.payload.recipient?.type_id === PrincipalTypeID.Standard) {
dbTx.coinbase_alt_recipient = txData.payload.recipient.address;
} else if (txData.payload.recipient?.type_id === PrincipalTypeID.Contract) {
dbTx.coinbase_alt_recipient = `${txData.payload.recipient.address}.${txData.payload.recipient.contract_name}`;
}
dbTx.coinbase_vrf_proof = txData.payload.vrf_proof;
break;
}
case TxPayloadTypeID.TenureChange: {
dbTx.tenure_change_previous_tenure_end = txData.payload.previous_tenure_end;
dbTx.tenure_change_previous_tenure_blocks = txData.payload.previous_tenure_blocks;
dbTx.tenure_change_cause = txData.payload.cause;
dbTx.tenure_change_pubkey_hash = txData.payload.pubkey_hash;
dbTx.tenure_change_signature = txData.payload.signature;
dbTx.tenure_change_signers = txData.payload.signers;
break;
}
default:
throw new Error(`Unexpected transaction type ID: ${JSON.stringify(txData.payload)}`);
}

View File

@@ -1699,6 +1699,13 @@ export class PgWriteStore extends PgStore {
poison_microblock_header_2: tx.poison_microblock_header_2 ?? null,
coinbase_payload: tx.coinbase_payload ?? null,
coinbase_alt_recipient: tx.coinbase_alt_recipient ?? null,
coinbase_vrf_proof: tx.coinbase_vrf_proof ?? null,
tenure_change_previous_tenure_end: tx.tenure_change_previous_tenure_end ?? null,
tenure_change_previous_tenure_blocks: tx.tenure_change_previous_tenure_blocks ?? null,
tenure_change_cause: tx.tenure_change_cause ?? null,
tenure_change_pubkey_hash: tx.tenure_change_pubkey_hash ?? null,
tenure_change_signature: tx.tenure_change_signature ?? null,
tenure_change_signers: tx.tenure_change_signers ?? null,
raw_result: tx.raw_result,
event_count: tx.event_count,
execution_cost_read_count: tx.execution_cost_read_count,
@@ -1749,6 +1756,13 @@ export class PgWriteStore extends PgStore {
poison_microblock_header_2: tx.poison_microblock_header_2 ?? null,
coinbase_payload: tx.coinbase_payload ?? null,
coinbase_alt_recipient: tx.coinbase_alt_recipient ?? null,
coinbase_vrf_proof: tx.coinbase_vrf_proof ?? null,
tenure_change_previous_tenure_end: tx.tenure_change_previous_tenure_end ?? null,
tenure_change_previous_tenure_blocks: tx.tenure_change_previous_tenure_blocks ?? null,
tenure_change_cause: tx.tenure_change_cause ?? null,
tenure_change_pubkey_hash: tx.tenure_change_pubkey_hash ?? null,
tenure_change_signature: tx.tenure_change_signature ?? null,
tenure_change_signers: tx.tenure_change_signers ?? null,
};
const result = await sql`
INSERT INTO mempool_txs ${sql(values)}
@@ -3062,6 +3076,13 @@ export class PgWriteStore extends PgStore {
poison_microblock_header_2: tx.poison_microblock_header_2 ?? null,
coinbase_payload: tx.coinbase_payload ?? null,
coinbase_alt_recipient: tx.coinbase_alt_recipient ?? null,
coinbase_vrf_proof: tx.coinbase_vrf_proof ?? null,
tenure_change_previous_tenure_end: tx.tenure_change_previous_tenure_end ?? null,
tenure_change_previous_tenure_blocks: tx.tenure_change_previous_tenure_blocks ?? null,
tenure_change_cause: tx.tenure_change_cause ?? null,
tenure_change_pubkey_hash: tx.tenure_change_pubkey_hash ?? null,
tenure_change_signature: tx.tenure_change_signature ?? null,
tenure_change_signers: tx.tenure_change_signers ?? null,
raw_result: tx.raw_result,
event_count: tx.event_count,
execution_cost_read_count: tx.execution_cost_read_count,

View File

@@ -773,6 +773,20 @@ export function parseMessageTransaction(
}
break;
}
case TxPayloadTypeID.NakamotoCoinbase: {
if (payload.recipient?.type_id === PrincipalTypeID.Standard) {
logger.debug(
`NakamotoCoinbase to alt recipient, standard principal: ${payload.recipient.address}, vrf=${payload.vrf_proof}`
);
} else if (payload.recipient?.type_id === PrincipalTypeID.Contract) {
logger.debug(
`NakamotoCoinbase to alt recipient, contract principal: ${payload.recipient.address}.${payload.recipient.contract_name}, vrf=${payload.vrf_proof}`
);
} else {
logger.debug(`NakamotoCoinbase (no alt recipient), vrf=${payload.vrf_proof}`);
}
break;
}
case TxPayloadTypeID.SmartContract: {
logger.debug(
`Smart contract deployed: ${parsedTx.sender_address}.${payload.contract_name}`
@@ -807,6 +821,12 @@ export function parseMessageTransaction(
);
break;
}
case TxPayloadTypeID.TenureChange: {
logger.debug(
`Tenure change: cause=${payload.cause}, prev_tenure_blocks=${payload.previous_tenure_blocks}, prev_tenure_block=${payload.previous_tenure_end}, signers=${payload.signers},`
);
break;
}
default: {
throw new NotImplementedError(
`extracting data for tx type: ${getEnumDescription(

View File

@@ -1122,6 +1122,12 @@ export function rawTxToBaseTx(raw_tx: string): BaseTx {
case TxPayloadTypeID.PoisonMicroblock:
transactionType = DbTxTypeId.PoisonMicroblock;
break;
case TxPayloadTypeID.TenureChange:
transactionType = DbTxTypeId.TenureChange;
break;
case TxPayloadTypeID.NakamotoCoinbase:
transactionType = DbTxTypeId.NakamotoCoinbase;
break;
}
const dbTx: BaseTx = {
token_transfer_recipient_address: recipientAddr,

View File

@@ -159,6 +159,7 @@ export interface TestTxArgs {
canonical?: boolean;
microblock_canonical?: boolean;
coinbase_alt_recipient?: string;
coinbase_vrf_proof?: string;
contract_call_contract_id?: string;
contract_call_function_name?: string;
contract_call_function_args?: string;
@@ -213,6 +214,7 @@ function testTx(args?: TestTxArgs): DataStoreTxEventData {
origin_hash_mode: 1,
coinbase_payload: bufferToHex(Buffer.from('hi')),
coinbase_alt_recipient: args?.coinbase_alt_recipient,
coinbase_vrf_proof: args?.coinbase_vrf_proof,
event_count: 0,
parent_index_block_hash: args?.parent_index_block_hash ?? INDEX_BLOCK_HASH,
parent_block_hash: BLOCK_HASH,

View File

@@ -546,6 +546,6 @@ describe('socket-io', () => {
});
await disconnectWaiter;
expect(disconnectReason).toBe('ping timeout');
expect(['ping timeout', 'transport close']).toContain(disconnectReason);
});
});