mirror of
https://github.com/alexgo-io/stacks-blockchain-api.git
synced 2026-01-12 16:53:19 +08:00
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:
20
.vscode/launch.json
vendored
20
.vscode/launch.json
vendored
@@ -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
23
.vscode/tasks.json
vendored
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -17,6 +17,9 @@
|
||||
},
|
||||
{
|
||||
"$ref": "./transaction-4-coinbase.schema.json"
|
||||
},
|
||||
{
|
||||
"$ref": "./transaction-7-tenure-change.schema.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -16,6 +16,9 @@
|
||||
},
|
||||
{
|
||||
"$ref": "./transaction-4-coinbase-metadata.schema.json"
|
||||
},
|
||||
{
|
||||
"$ref": "./transaction-7-tenure-change-metadata.schema.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
},
|
||||
{
|
||||
"$ref": "./transaction-4-coinbase.schema.json"
|
||||
},
|
||||
{
|
||||
"$ref": "./transaction-7-tenure-change.schema.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
64
docs/generated.d.ts
vendored
64
docs/generated.d.ts
vendored
@@ -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;
|
||||
};
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
44
migrations/1701368149776_nakamoto-txs.js
Normal file
44
migrations/1701368149776_nakamoto-txs.js
Normal 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
8
package-lock.json
generated
@@ -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"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)}`);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -546,6 +546,6 @@ describe('socket-io', () => {
|
||||
});
|
||||
|
||||
await disconnectWaiter;
|
||||
expect(disconnectReason).toBe('ping timeout');
|
||||
expect(['ping timeout', 'transport close']).toContain(disconnectReason);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user