From 9b57d6ba3029301110cc45eadc312c104ea59bc1 Mon Sep 17 00:00:00 2001 From: Rafael Cardenas Date: Thu, 3 Jul 2025 09:59:07 -0600 Subject: [PATCH 1/7] fix: pre nakamoto block time --- src/event-stream/core-node-message.ts | 2 +- src/event-stream/event-server.ts | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/event-stream/core-node-message.ts b/src/event-stream/core-node-message.ts index 8250fc265..066e0ffe6 100644 --- a/src/event-stream/core-node-message.ts +++ b/src/event-stream/core-node-message.ts @@ -326,7 +326,7 @@ export interface CoreNodeBlockMessage { missed_reward_slots: []; }; }; - block_time: number; + block_time: number | null; signer_bitvec?: string | null; signer_signature?: string[]; } diff --git a/src/event-stream/event-server.ts b/src/event-stream/event-server.ts index 6d36ff7da..78b52450f 100644 --- a/src/event-stream/event-server.ts +++ b/src/event-stream/event-server.ts @@ -1000,17 +1000,16 @@ export function parseNewBlockMessage( const parsedTxs: CoreNodeParsedTxMessage[] = []; const blockData: CoreNodeMsgBlockData = { ...msg, + // If received block_time is empty, and the block is not a Nakamoto block or we're running in + // IBD mode, we use the parent burn block timestamp as the receipt date. Otherwise, use the + // current timestamp. This is to ensure that the block time is always set, and that it is + // consistent with the block time in the block header. + block_time: + msg.block_time ?? (!msg.signer_bitvec || isEventReplay) + ? msg.burn_block_time + : Math.round(Date.now() / 1000), }; - if (!blockData.block_time) { - // If running in IBD mode, we use the parent burn block timestamp as the receipt date, - // otherwise, use the current timestamp. - const stacksBlockReceiptDate = isEventReplay - ? msg.burn_block_time - : Math.round(Date.now() / 1000); - blockData.block_time = stacksBlockReceiptDate; - } - msg.transactions.forEach(item => { const parsedTx = parseMessageTransaction(chainId, item, blockData, msg.events); if (parsedTx) { From fd5f543bedde16ef3d12a01fdf2aa6c993714db0 Mon Sep 17 00:00:00 2001 From: Rafael Cardenas Date: Thu, 3 Jul 2025 10:47:11 -0600 Subject: [PATCH 2/7] fix: always use block time --- src/event-stream/core-node-message.ts | 2 +- src/event-stream/event-server.ts | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/event-stream/core-node-message.ts b/src/event-stream/core-node-message.ts index 066e0ffe6..8250fc265 100644 --- a/src/event-stream/core-node-message.ts +++ b/src/event-stream/core-node-message.ts @@ -326,7 +326,7 @@ export interface CoreNodeBlockMessage { missed_reward_slots: []; }; }; - block_time: number | null; + block_time: number; signer_bitvec?: string | null; signer_signature?: string[]; } diff --git a/src/event-stream/event-server.ts b/src/event-stream/event-server.ts index 78b52450f..0b57715b7 100644 --- a/src/event-stream/event-server.ts +++ b/src/event-stream/event-server.ts @@ -1000,14 +1000,9 @@ export function parseNewBlockMessage( const parsedTxs: CoreNodeParsedTxMessage[] = []; const blockData: CoreNodeMsgBlockData = { ...msg, - // If received block_time is empty, and the block is not a Nakamoto block or we're running in - // IBD mode, we use the parent burn block timestamp as the receipt date. Otherwise, use the - // current timestamp. This is to ensure that the block time is always set, and that it is - // consistent with the block time in the block header. - block_time: - msg.block_time ?? (!msg.signer_bitvec || isEventReplay) - ? msg.burn_block_time - : Math.round(Date.now() / 1000), + // Nakamoto blocks now include their own `block_time`, but this will be empty for pre-Nakamoto + // blocks. We'll use the parent burn block timestamp as the receipt date for those. + block_time: msg.block_time ?? msg.burn_block_time ?? Math.round(Date.now() / 1000), }; msg.transactions.forEach(item => { From b9c94ca9a46f4d3bf429139bba9380286ff5fd47 Mon Sep 17 00:00:00 2001 From: Rafael Cardenas Date: Thu, 3 Jul 2025 11:22:29 -0600 Subject: [PATCH 3/7] test: behavior --- tests/api/synthetic-stx-txs.test.ts | 2 ++ ...49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/api/synthetic-stx-txs.test.ts b/tests/api/synthetic-stx-txs.test.ts index 6d961f1da..6d1aa6d62 100644 --- a/tests/api/synthetic-stx-txs.test.ts +++ b/tests/api/synthetic-stx-txs.test.ts @@ -62,6 +62,7 @@ describe('synthetic stx txs', () => { }; expect(parsed.parsed_tx).toEqual(expect.objectContaining(expected)); + expect(parsed.block_time).toEqual(1610742541); // Takes burn_block_time from block header }); test('test synthetic tx token transfer 2', () => { @@ -117,6 +118,7 @@ describe('synthetic stx txs', () => { }; expect(parsed.parsed_tx).toEqual(expect.objectContaining(expected)); + expect(parsed.block_time).toEqual(1846858171); // Takes block_time from block header }); test('test synthetic tx stx lock 1', () => { diff --git a/tests/api/synthetic-tx-payloads/token_transfer-51655-0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6.json b/tests/api/synthetic-tx-payloads/token_transfer-51655-0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6.json index 7b670278f..bc0a3d797 100644 --- a/tests/api/synthetic-tx-payloads/token_transfer-51655-0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6.json +++ b/tests/api/synthetic-tx-payloads/token_transfer-51655-0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6.json @@ -1 +1 @@ -{"events":[{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":9,"stx_transfer_event":{"amount":"3636363","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SPNWZ5V2TPWGQGVDR6T7B6RQ4XMGZ4PXTEE0VQ0S"}},{"txid":"0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6","type":"stx_transfer_event","committed":true,"event_index":0,"stx_transfer_event":{"amount":"8333333333","sender":"SM1J78KG0XBCYXS2NP1ZYJ06AGH5T5SKND701Q4CA","recipient":"SMSJ4YQNTPHWE1KH325MHVHXDRZY7ZA21W989BPW"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"nft_transfer_event","committed":true,"event_index":10,"nft_transfer_event":{"value":{"UInt":4622},"sender":"SP3ZMEFW7VH796ZQAH1JMAJT4WC4VPEZZFB6W5CAD","raw_value":"0x010000000000000000000000000000120e","recipient":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","asset_identifier":"SP3QSAJQ4EA8WXEDSRRKMZZ29NH91VZ6C5X88FGZQ.crashpunks-v2::crashpunks-v2"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":7,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP1P89TEC03E29V5MYJBSCC8KWR1A243ZG2R8DYB1"}},{"txid":"0xc68191241d3023c5ef487e0597092e05ee5072e11683315d559f042d30a38257","type":"stx_transfer_event","committed":true,"event_index":11,"stx_transfer_event":{"amount":"3042590353","sender":"SP35JCE77FTPWVEW1VFA0TFP9F863J70QRRJQ5MS","recipient":"SP3HXJJMJQ06GNAZ8XWDN1QM48JEDC6PP6W3YZPZJ"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":3,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SPGAKH27HF1T170QET72C727873H911BKNMPF8YB"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":1,"stx_transfer_event":{"amount":"181818182","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP3ZMEFW7VH796ZQAH1JMAJT4WC4VPEZZFB6W5CAD"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":2,"stx_transfer_event":{"amount":"10909090","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP2CBFWG9AT8W4WSCSSJE1R42SDECK7K7W9VSEKD0"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":8,"stx_transfer_event":{"amount":"363636","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP2S6MCR2K3TYAC02RSYQ74RE9RJ3Q0EV3FYFGKGB"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":6,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP162D87CY84QVVCMJKNKGHC7GGXFGA0TAR9D0XJW"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":5,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP2FTZQX1V9FPPNH485Z49JE914YNQYGT4XVGNR4S"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":4,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SPZRAE52H2NC2MDBEV8W99RFVPK8Q9BW8H88XV9N"}}],"block_hash":"0xd51cd57ccbed84d08a0158f6b44dfee1a0896ed2ddd6e9e0f37ef6528cd692de","miner_txid":"0xa874abae6787c8c5339107fc669bde7e388dc3f6c60cdf429c0db5e69cf8074e","block_height":51655,"transactions":[{"txid":"0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6","raw_tx":"0x00","status":"success","tx_index":0,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null},{"txid":"0xa60e1d365bae6153b82efdf8031cd0b8c389ec083a2a31fc1869f2899c9ca049","raw_tx":"0x0000000001040029cc0b8ad8636eadd807a786dc000146553bd59a000000000000028100000000000000000001f6342b223c478581f46244704d83990b71b1611156f734f12dff3742d30b9dbe612813eaf550ae0021fef642643a8e79de7fd489ef7502de0578ea43dcbff112010200000000040000000000000000000000000000000000000000000000000000000000000000","status":"success","tx_index":1,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","raw_tx":"0x000000000104006e04ab02c42586aa7c33d6d6c0d513171f3f7c6e0000000000000000000000000003ffef0000cc7bee3e952b4a4166d996aeba1257d65e764ccdc4a217851f5b4ee0f2faf41331b1169e5380e1ea94083465778d0933640197c816daf283680914c17a6012780302000000020002166e04ab02c42586aa7c33d6d6c0d513171f3f7c6e05000000000bebc200020216ff473f87dc4e937eea8865454b44e309bb3bff7a16ef954ae47291ceb9b9c6274ffc49ac521dfccc2f0d637261736870756e6b732d76320d637261736870756e6b732d7632010000000000000000000000000000120e100216ef954ae47291ceb9b9c6274ffc49ac521dfccc2f0d637261736870756e6b732d76320b6275792d696e2d7573747800000002010000000000000000000000000000120e06162bcf9762d5b90bc36dc1b4759b1727690f92ddd31f637261736870756e6b732d76322d7374786e66742d636f6d6d697373696f6e","status":"success","tx_index":2,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":64762,"read_count":19,"read_length":13236,"write_count":11,"write_length":29},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null},{"txid":"0xc68191241d3023c5ef487e0597092e05ee5072e11683315d559f042d30a38257","raw_tx":"0x00000000010400065931c73bf56e6ddc0edea069f64bd061c8e0be000000000000060a00000000000000b40001c926e708059056a55813591f7b6cbbdfd001c07d99643f4f710e62a38e5b2de841a3ad50c3c84d535758c41a9c78c7befe7170d4f04954c6c7eb1c99836d4b40030200000000000516e3d94a92b80d0aabe8ef1b50de84449cd61ad63700000000b55a3e9131313838343700000000000000000000000000000000000000000000000000000000","status":"success","tx_index":3,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null}],"anchored_cost":{"runtime":64762,"read_count":19,"read_length":13236,"write_count":11,"write_length":29},"burn_block_hash":"0x0000000000000000000984f90550aead762d7b828a7bf4414a33cf90d015b98a","burn_block_time":1646858171,"index_block_hash":"0xacbcd86508292a25eb6fbb528d4dc3914a22f4dae03ebca4eae80b3f9f161760","burn_block_height":726601,"parent_block_hash":"0xb1f3116c0c698fc05d7e6e49ce8478e1e79d134efda77834675c98519fc6dc11","parent_microblock":"0x0000000000000000000000000000000000000000000000000000000000000000","matured_miner_rewards":[{"recipient":"SP1Q7NC4FFRMCE59HS7BVF3CGHK6RRT8WD1M0WWSF","coinbase_amount":"1000000000","tx_fees_anchored":"2352739","from_stacks_block_hash":"0x718382e6f8ac7e7a855f0044ca8a68dc07bfd3808013f73b80c70def40dbe5df","from_index_consensus_hash":"0xcd9c9435556d5f00781192d39f1f845732d58f7dba970ce48d553f83095818b3","tx_fees_streamed_produced":"0","tx_fees_streamed_confirmed":"794668"},{"recipient":"SPMWR2WAV1HPXBER0YKRDQ000535AEYNK91MVCZF","coinbase_amount":"0","tx_fees_anchored":"0","from_stacks_block_hash":"0x718382e6f8ac7e7a855f0044ca8a68dc07bfd3808013f73b80c70def40dbe5df","from_index_consensus_hash":"0xcd9c9435556d5f00781192d39f1f845732d58f7dba970ce48d553f83095818b3","tx_fees_streamed_produced":"1580000","tx_fees_streamed_confirmed":"0"}],"parent_burn_block_hash":"0x00000000000000000006027b9de2e4a9e09cda9646edb391bd434f97f063dc1b","parent_index_block_hash":"0xfcdee58979922da016ca65db9b54be09db97d88bb6aa0c9cd66a9e2b7fa4b0a2","parent_burn_block_height":726600,"confirmed_microblocks_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"parent_microblock_sequence":0,"parent_burn_block_timestamp":1646857773} \ No newline at end of file +{"events":[{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":9,"stx_transfer_event":{"amount":"3636363","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SPNWZ5V2TPWGQGVDR6T7B6RQ4XMGZ4PXTEE0VQ0S"}},{"txid":"0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6","type":"stx_transfer_event","committed":true,"event_index":0,"stx_transfer_event":{"amount":"8333333333","sender":"SM1J78KG0XBCYXS2NP1ZYJ06AGH5T5SKND701Q4CA","recipient":"SMSJ4YQNTPHWE1KH325MHVHXDRZY7ZA21W989BPW"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"nft_transfer_event","committed":true,"event_index":10,"nft_transfer_event":{"value":{"UInt":4622},"sender":"SP3ZMEFW7VH796ZQAH1JMAJT4WC4VPEZZFB6W5CAD","raw_value":"0x010000000000000000000000000000120e","recipient":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","asset_identifier":"SP3QSAJQ4EA8WXEDSRRKMZZ29NH91VZ6C5X88FGZQ.crashpunks-v2::crashpunks-v2"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":7,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP1P89TEC03E29V5MYJBSCC8KWR1A243ZG2R8DYB1"}},{"txid":"0xc68191241d3023c5ef487e0597092e05ee5072e11683315d559f042d30a38257","type":"stx_transfer_event","committed":true,"event_index":11,"stx_transfer_event":{"amount":"3042590353","sender":"SP35JCE77FTPWVEW1VFA0TFP9F863J70QRRJQ5MS","recipient":"SP3HXJJMJQ06GNAZ8XWDN1QM48JEDC6PP6W3YZPZJ"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":3,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SPGAKH27HF1T170QET72C727873H911BKNMPF8YB"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":1,"stx_transfer_event":{"amount":"181818182","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP3ZMEFW7VH796ZQAH1JMAJT4WC4VPEZZFB6W5CAD"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":2,"stx_transfer_event":{"amount":"10909090","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP2CBFWG9AT8W4WSCSSJE1R42SDECK7K7W9VSEKD0"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":8,"stx_transfer_event":{"amount":"363636","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP2S6MCR2K3TYAC02RSYQ74RE9RJ3Q0EV3FYFGKGB"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":6,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP162D87CY84QVVCMJKNKGHC7GGXFGA0TAR9D0XJW"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":5,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP2FTZQX1V9FPPNH485Z49JE914YNQYGT4XVGNR4S"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":4,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SPZRAE52H2NC2MDBEV8W99RFVPK8Q9BW8H88XV9N"}}],"block_hash":"0xd51cd57ccbed84d08a0158f6b44dfee1a0896ed2ddd6e9e0f37ef6528cd692de","miner_txid":"0xa874abae6787c8c5339107fc669bde7e388dc3f6c60cdf429c0db5e69cf8074e","block_height":51655,"transactions":[{"txid":"0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6","raw_tx":"0x00","status":"success","tx_index":0,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null},{"txid":"0xa60e1d365bae6153b82efdf8031cd0b8c389ec083a2a31fc1869f2899c9ca049","raw_tx":"0x0000000001040029cc0b8ad8636eadd807a786dc000146553bd59a000000000000028100000000000000000001f6342b223c478581f46244704d83990b71b1611156f734f12dff3742d30b9dbe612813eaf550ae0021fef642643a8e79de7fd489ef7502de0578ea43dcbff112010200000000040000000000000000000000000000000000000000000000000000000000000000","status":"success","tx_index":1,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","raw_tx":"0x000000000104006e04ab02c42586aa7c33d6d6c0d513171f3f7c6e0000000000000000000000000003ffef0000cc7bee3e952b4a4166d996aeba1257d65e764ccdc4a217851f5b4ee0f2faf41331b1169e5380e1ea94083465778d0933640197c816daf283680914c17a6012780302000000020002166e04ab02c42586aa7c33d6d6c0d513171f3f7c6e05000000000bebc200020216ff473f87dc4e937eea8865454b44e309bb3bff7a16ef954ae47291ceb9b9c6274ffc49ac521dfccc2f0d637261736870756e6b732d76320d637261736870756e6b732d7632010000000000000000000000000000120e100216ef954ae47291ceb9b9c6274ffc49ac521dfccc2f0d637261736870756e6b732d76320b6275792d696e2d7573747800000002010000000000000000000000000000120e06162bcf9762d5b90bc36dc1b4759b1727690f92ddd31f637261736870756e6b732d76322d7374786e66742d636f6d6d697373696f6e","status":"success","tx_index":2,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":64762,"read_count":19,"read_length":13236,"write_count":11,"write_length":29},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null},{"txid":"0xc68191241d3023c5ef487e0597092e05ee5072e11683315d559f042d30a38257","raw_tx":"0x00000000010400065931c73bf56e6ddc0edea069f64bd061c8e0be000000000000060a00000000000000b40001c926e708059056a55813591f7b6cbbdfd001c07d99643f4f710e62a38e5b2de841a3ad50c3c84d535758c41a9c78c7befe7170d4f04954c6c7eb1c99836d4b40030200000000000516e3d94a92b80d0aabe8ef1b50de84449cd61ad63700000000b55a3e9131313838343700000000000000000000000000000000000000000000000000000000","status":"success","tx_index":3,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null}],"anchored_cost":{"runtime":64762,"read_count":19,"read_length":13236,"write_count":11,"write_length":29},"burn_block_hash":"0x0000000000000000000984f90550aead762d7b828a7bf4414a33cf90d015b98a","burn_block_time":1646858171,"index_block_hash":"0xacbcd86508292a25eb6fbb528d4dc3914a22f4dae03ebca4eae80b3f9f161760","burn_block_height":726601,"parent_block_hash":"0xb1f3116c0c698fc05d7e6e49ce8478e1e79d134efda77834675c98519fc6dc11","parent_microblock":"0x0000000000000000000000000000000000000000000000000000000000000000","matured_miner_rewards":[{"recipient":"SP1Q7NC4FFRMCE59HS7BVF3CGHK6RRT8WD1M0WWSF","coinbase_amount":"1000000000","tx_fees_anchored":"2352739","from_stacks_block_hash":"0x718382e6f8ac7e7a855f0044ca8a68dc07bfd3808013f73b80c70def40dbe5df","from_index_consensus_hash":"0xcd9c9435556d5f00781192d39f1f845732d58f7dba970ce48d553f83095818b3","tx_fees_streamed_produced":"0","tx_fees_streamed_confirmed":"794668"},{"recipient":"SPMWR2WAV1HPXBER0YKRDQ000535AEYNK91MVCZF","coinbase_amount":"0","tx_fees_anchored":"0","from_stacks_block_hash":"0x718382e6f8ac7e7a855f0044ca8a68dc07bfd3808013f73b80c70def40dbe5df","from_index_consensus_hash":"0xcd9c9435556d5f00781192d39f1f845732d58f7dba970ce48d553f83095818b3","tx_fees_streamed_produced":"1580000","tx_fees_streamed_confirmed":"0"}],"parent_burn_block_hash":"0x00000000000000000006027b9de2e4a9e09cda9646edb391bd434f97f063dc1b","parent_index_block_hash":"0xfcdee58979922da016ca65db9b54be09db97d88bb6aa0c9cd66a9e2b7fa4b0a2","parent_burn_block_height":726600,"confirmed_microblocks_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"parent_microblock_sequence":0,"parent_burn_block_timestamp":1646857773,"block_time": 1846858171} \ No newline at end of file From 5eec64dfc54e3300d22594f7466edfd84adfc170 Mon Sep 17 00:00:00 2001 From: Rafael Cardenas Date: Thu, 3 Jul 2025 12:01:14 -0600 Subject: [PATCH 4/7] test: new suite --- src/event-stream/core-node-message.ts | 2 +- tests/api/block-time.test.ts | 55 +++++++++++++++++++ tests/api/synthetic-stx-txs.test.ts | 34 +++++++++--- ...c8f15945965a51976ac6697641003533986f6.json | 2 +- 4 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 tests/api/block-time.test.ts diff --git a/src/event-stream/core-node-message.ts b/src/event-stream/core-node-message.ts index 8250fc265..066e0ffe6 100644 --- a/src/event-stream/core-node-message.ts +++ b/src/event-stream/core-node-message.ts @@ -326,7 +326,7 @@ export interface CoreNodeBlockMessage { missed_reward_slots: []; }; }; - block_time: number; + block_time: number | null; signer_bitvec?: string | null; signer_signature?: string[]; } diff --git a/tests/api/block-time.test.ts b/tests/api/block-time.test.ts new file mode 100644 index 000000000..8571b573d --- /dev/null +++ b/tests/api/block-time.test.ts @@ -0,0 +1,55 @@ +import { ChainID } from '@stacks/transactions'; +import { CoreNodeBlockMessage } from '../../src/event-stream/core-node-message'; +import { parseNewBlockMessage } from '../../src/event-stream/event-server'; + +describe('block time tests', () => { + test('takes block_time from block header', () => { + const block: CoreNodeBlockMessage = { + block_time: 1716238792, + block_height: 1, + block_hash: '0x1234', + index_block_hash: '0x5678', + parent_index_block_hash: '0x9abc', + parent_block_hash: '0x1234', + parent_microblock: '0x1234', + parent_microblock_sequence: 0, + parent_burn_block_hash: '0x1234', + parent_burn_block_height: 0, + parent_burn_block_timestamp: 0, + burn_block_time: 1234567890, + burn_block_hash: '0x1234', + burn_block_height: 1, + miner_txid: '0x1234', + events: [], + transactions: [], + matured_miner_rewards: [], + }; + const { dbData: parsed } = parseNewBlockMessage(ChainID.Mainnet, block, false); + expect(parsed.block.block_time).toEqual(1716238792); // Takes block_time from block header + }); + + test('takes burn_block_time from block header when block_time is not present', () => { + const block: CoreNodeBlockMessage = { + block_time: null, + block_height: 1, + block_hash: '0x1234', + index_block_hash: '0x5678', + parent_index_block_hash: '0x9abc', + parent_block_hash: '0x1234', + parent_microblock: '0x1234', + parent_microblock_sequence: 0, + parent_burn_block_hash: '0x1234', + parent_burn_block_height: 0, + parent_burn_block_timestamp: 0, + burn_block_time: 1234567890, + burn_block_hash: '0x1234', + burn_block_height: 1, + miner_txid: '0x1234', + events: [], + transactions: [], + matured_miner_rewards: [], + }; + const { dbData: parsed } = parseNewBlockMessage(ChainID.Mainnet, block, false); + expect(parsed.block.block_time).toEqual(1234567890); // Takes burn_block_time from block header + }); +}); diff --git a/tests/api/synthetic-stx-txs.test.ts b/tests/api/synthetic-stx-txs.test.ts index 6d1aa6d62..92776cb2f 100644 --- a/tests/api/synthetic-stx-txs.test.ts +++ b/tests/api/synthetic-stx-txs.test.ts @@ -3,7 +3,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { DecodedTxResult, TxPayloadTypeID } from 'stacks-encoding-native-js'; import { CoreNodeBlockMessage } from '../../src/event-stream/core-node-message'; -import { parseMessageTransaction } from '../../src/event-stream/reader'; +import { CoreNodeMsgBlockData, parseMessageTransaction } from '../../src/event-stream/reader'; import { parseNewBlockMessage } from '../../src/event-stream/event-server'; // Test processing of the psuedo-Stacks transactions, i.e. the ones that @@ -20,7 +20,12 @@ describe('synthetic stx txs', () => { if (!txMsg) { throw new Error(`Cound not find tx ${txid}`); } - const parsed = parseMessageTransaction(ChainID.Mainnet, txMsg, blockMsg, blockMsg.events); + const parsed = parseMessageTransaction( + ChainID.Mainnet, + txMsg, + blockMsg as unknown as CoreNodeMsgBlockData, + blockMsg.events + ); if (!parsed) { throw new Error(`Failed to parse ${txid}`); } @@ -62,7 +67,6 @@ describe('synthetic stx txs', () => { }; expect(parsed.parsed_tx).toEqual(expect.objectContaining(expected)); - expect(parsed.block_time).toEqual(1610742541); // Takes burn_block_time from block header }); test('test synthetic tx token transfer 2', () => { @@ -76,7 +80,12 @@ describe('synthetic stx txs', () => { if (!txMsg) { throw new Error(`Cound not find tx ${txid}`); } - const parsed = parseMessageTransaction(ChainID.Mainnet, txMsg, blockMsg, blockMsg.events); + const parsed = parseMessageTransaction( + ChainID.Mainnet, + txMsg, + blockMsg as unknown as CoreNodeMsgBlockData, + blockMsg.events + ); if (!parsed) { throw new Error(`Failed to parse ${txid}`); } @@ -132,7 +141,12 @@ describe('synthetic stx txs', () => { if (!txMsg) { throw new Error(`Cound not find tx ${txid}`); } - const parsed = parseMessageTransaction(ChainID.Mainnet, txMsg, blockMsg, blockMsg.events); + const parsed = parseMessageTransaction( + ChainID.Mainnet, + txMsg, + blockMsg as unknown as CoreNodeMsgBlockData, + blockMsg.events + ); if (!parsed) { throw new Error(`Failed to parse ${txid}`); } @@ -223,6 +237,7 @@ describe('synthetic stx txs', () => { for (const poxEvent of parsed.txs[0].pox4Events) { expect(poxEvent.event_index).toBeLessThan(events.length); } + expect(parsed.block.block_time).toEqual(1716238792); // Takes burn_block_time from block header }); test('test synthetic tx stx lock 2', () => { @@ -236,7 +251,12 @@ describe('synthetic stx txs', () => { if (!txMsg) { throw new Error(`Cound not find tx ${txid}`); } - const parsed = parseMessageTransaction(ChainID.Mainnet, txMsg, blockMsg, blockMsg.events); + const parsed = parseMessageTransaction( + ChainID.Mainnet, + txMsg, + blockMsg as unknown as CoreNodeMsgBlockData, + blockMsg.events + ); if (!parsed) { throw new Error(`Failed to parse ${txid}`); } @@ -335,7 +355,7 @@ describe('synthetic stx txs', () => { const parsed = parseMessageTransaction( ChainID.Mainnet, payload.txMsg, - payload.blockMsg, + payload.blockMsg as unknown as CoreNodeMsgBlockData, payload.blockMsg.events ); let txType: 'contract_call' | 'token_transfer' | null; diff --git a/tests/api/synthetic-tx-payloads/token_transfer-51655-0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6.json b/tests/api/synthetic-tx-payloads/token_transfer-51655-0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6.json index bc0a3d797..7b670278f 100644 --- a/tests/api/synthetic-tx-payloads/token_transfer-51655-0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6.json +++ b/tests/api/synthetic-tx-payloads/token_transfer-51655-0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6.json @@ -1 +1 @@ -{"events":[{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":9,"stx_transfer_event":{"amount":"3636363","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SPNWZ5V2TPWGQGVDR6T7B6RQ4XMGZ4PXTEE0VQ0S"}},{"txid":"0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6","type":"stx_transfer_event","committed":true,"event_index":0,"stx_transfer_event":{"amount":"8333333333","sender":"SM1J78KG0XBCYXS2NP1ZYJ06AGH5T5SKND701Q4CA","recipient":"SMSJ4YQNTPHWE1KH325MHVHXDRZY7ZA21W989BPW"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"nft_transfer_event","committed":true,"event_index":10,"nft_transfer_event":{"value":{"UInt":4622},"sender":"SP3ZMEFW7VH796ZQAH1JMAJT4WC4VPEZZFB6W5CAD","raw_value":"0x010000000000000000000000000000120e","recipient":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","asset_identifier":"SP3QSAJQ4EA8WXEDSRRKMZZ29NH91VZ6C5X88FGZQ.crashpunks-v2::crashpunks-v2"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":7,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP1P89TEC03E29V5MYJBSCC8KWR1A243ZG2R8DYB1"}},{"txid":"0xc68191241d3023c5ef487e0597092e05ee5072e11683315d559f042d30a38257","type":"stx_transfer_event","committed":true,"event_index":11,"stx_transfer_event":{"amount":"3042590353","sender":"SP35JCE77FTPWVEW1VFA0TFP9F863J70QRRJQ5MS","recipient":"SP3HXJJMJQ06GNAZ8XWDN1QM48JEDC6PP6W3YZPZJ"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":3,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SPGAKH27HF1T170QET72C727873H911BKNMPF8YB"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":1,"stx_transfer_event":{"amount":"181818182","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP3ZMEFW7VH796ZQAH1JMAJT4WC4VPEZZFB6W5CAD"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":2,"stx_transfer_event":{"amount":"10909090","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP2CBFWG9AT8W4WSCSSJE1R42SDECK7K7W9VSEKD0"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":8,"stx_transfer_event":{"amount":"363636","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP2S6MCR2K3TYAC02RSYQ74RE9RJ3Q0EV3FYFGKGB"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":6,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP162D87CY84QVVCMJKNKGHC7GGXFGA0TAR9D0XJW"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":5,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP2FTZQX1V9FPPNH485Z49JE914YNQYGT4XVGNR4S"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":4,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SPZRAE52H2NC2MDBEV8W99RFVPK8Q9BW8H88XV9N"}}],"block_hash":"0xd51cd57ccbed84d08a0158f6b44dfee1a0896ed2ddd6e9e0f37ef6528cd692de","miner_txid":"0xa874abae6787c8c5339107fc669bde7e388dc3f6c60cdf429c0db5e69cf8074e","block_height":51655,"transactions":[{"txid":"0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6","raw_tx":"0x00","status":"success","tx_index":0,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null},{"txid":"0xa60e1d365bae6153b82efdf8031cd0b8c389ec083a2a31fc1869f2899c9ca049","raw_tx":"0x0000000001040029cc0b8ad8636eadd807a786dc000146553bd59a000000000000028100000000000000000001f6342b223c478581f46244704d83990b71b1611156f734f12dff3742d30b9dbe612813eaf550ae0021fef642643a8e79de7fd489ef7502de0578ea43dcbff112010200000000040000000000000000000000000000000000000000000000000000000000000000","status":"success","tx_index":1,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","raw_tx":"0x000000000104006e04ab02c42586aa7c33d6d6c0d513171f3f7c6e0000000000000000000000000003ffef0000cc7bee3e952b4a4166d996aeba1257d65e764ccdc4a217851f5b4ee0f2faf41331b1169e5380e1ea94083465778d0933640197c816daf283680914c17a6012780302000000020002166e04ab02c42586aa7c33d6d6c0d513171f3f7c6e05000000000bebc200020216ff473f87dc4e937eea8865454b44e309bb3bff7a16ef954ae47291ceb9b9c6274ffc49ac521dfccc2f0d637261736870756e6b732d76320d637261736870756e6b732d7632010000000000000000000000000000120e100216ef954ae47291ceb9b9c6274ffc49ac521dfccc2f0d637261736870756e6b732d76320b6275792d696e2d7573747800000002010000000000000000000000000000120e06162bcf9762d5b90bc36dc1b4759b1727690f92ddd31f637261736870756e6b732d76322d7374786e66742d636f6d6d697373696f6e","status":"success","tx_index":2,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":64762,"read_count":19,"read_length":13236,"write_count":11,"write_length":29},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null},{"txid":"0xc68191241d3023c5ef487e0597092e05ee5072e11683315d559f042d30a38257","raw_tx":"0x00000000010400065931c73bf56e6ddc0edea069f64bd061c8e0be000000000000060a00000000000000b40001c926e708059056a55813591f7b6cbbdfd001c07d99643f4f710e62a38e5b2de841a3ad50c3c84d535758c41a9c78c7befe7170d4f04954c6c7eb1c99836d4b40030200000000000516e3d94a92b80d0aabe8ef1b50de84449cd61ad63700000000b55a3e9131313838343700000000000000000000000000000000000000000000000000000000","status":"success","tx_index":3,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null}],"anchored_cost":{"runtime":64762,"read_count":19,"read_length":13236,"write_count":11,"write_length":29},"burn_block_hash":"0x0000000000000000000984f90550aead762d7b828a7bf4414a33cf90d015b98a","burn_block_time":1646858171,"index_block_hash":"0xacbcd86508292a25eb6fbb528d4dc3914a22f4dae03ebca4eae80b3f9f161760","burn_block_height":726601,"parent_block_hash":"0xb1f3116c0c698fc05d7e6e49ce8478e1e79d134efda77834675c98519fc6dc11","parent_microblock":"0x0000000000000000000000000000000000000000000000000000000000000000","matured_miner_rewards":[{"recipient":"SP1Q7NC4FFRMCE59HS7BVF3CGHK6RRT8WD1M0WWSF","coinbase_amount":"1000000000","tx_fees_anchored":"2352739","from_stacks_block_hash":"0x718382e6f8ac7e7a855f0044ca8a68dc07bfd3808013f73b80c70def40dbe5df","from_index_consensus_hash":"0xcd9c9435556d5f00781192d39f1f845732d58f7dba970ce48d553f83095818b3","tx_fees_streamed_produced":"0","tx_fees_streamed_confirmed":"794668"},{"recipient":"SPMWR2WAV1HPXBER0YKRDQ000535AEYNK91MVCZF","coinbase_amount":"0","tx_fees_anchored":"0","from_stacks_block_hash":"0x718382e6f8ac7e7a855f0044ca8a68dc07bfd3808013f73b80c70def40dbe5df","from_index_consensus_hash":"0xcd9c9435556d5f00781192d39f1f845732d58f7dba970ce48d553f83095818b3","tx_fees_streamed_produced":"1580000","tx_fees_streamed_confirmed":"0"}],"parent_burn_block_hash":"0x00000000000000000006027b9de2e4a9e09cda9646edb391bd434f97f063dc1b","parent_index_block_hash":"0xfcdee58979922da016ca65db9b54be09db97d88bb6aa0c9cd66a9e2b7fa4b0a2","parent_burn_block_height":726600,"confirmed_microblocks_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"parent_microblock_sequence":0,"parent_burn_block_timestamp":1646857773,"block_time": 1846858171} \ No newline at end of file +{"events":[{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":9,"stx_transfer_event":{"amount":"3636363","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SPNWZ5V2TPWGQGVDR6T7B6RQ4XMGZ4PXTEE0VQ0S"}},{"txid":"0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6","type":"stx_transfer_event","committed":true,"event_index":0,"stx_transfer_event":{"amount":"8333333333","sender":"SM1J78KG0XBCYXS2NP1ZYJ06AGH5T5SKND701Q4CA","recipient":"SMSJ4YQNTPHWE1KH325MHVHXDRZY7ZA21W989BPW"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"nft_transfer_event","committed":true,"event_index":10,"nft_transfer_event":{"value":{"UInt":4622},"sender":"SP3ZMEFW7VH796ZQAH1JMAJT4WC4VPEZZFB6W5CAD","raw_value":"0x010000000000000000000000000000120e","recipient":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","asset_identifier":"SP3QSAJQ4EA8WXEDSRRKMZZ29NH91VZ6C5X88FGZQ.crashpunks-v2::crashpunks-v2"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":7,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP1P89TEC03E29V5MYJBSCC8KWR1A243ZG2R8DYB1"}},{"txid":"0xc68191241d3023c5ef487e0597092e05ee5072e11683315d559f042d30a38257","type":"stx_transfer_event","committed":true,"event_index":11,"stx_transfer_event":{"amount":"3042590353","sender":"SP35JCE77FTPWVEW1VFA0TFP9F863J70QRRJQ5MS","recipient":"SP3HXJJMJQ06GNAZ8XWDN1QM48JEDC6PP6W3YZPZJ"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":3,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SPGAKH27HF1T170QET72C727873H911BKNMPF8YB"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":1,"stx_transfer_event":{"amount":"181818182","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP3ZMEFW7VH796ZQAH1JMAJT4WC4VPEZZFB6W5CAD"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":2,"stx_transfer_event":{"amount":"10909090","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP2CBFWG9AT8W4WSCSSJE1R42SDECK7K7W9VSEKD0"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":8,"stx_transfer_event":{"amount":"363636","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP2S6MCR2K3TYAC02RSYQ74RE9RJ3Q0EV3FYFGKGB"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":6,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP162D87CY84QVVCMJKNKGHC7GGXFGA0TAR9D0XJW"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":5,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SP2FTZQX1V9FPPNH485Z49JE914YNQYGT4XVGNR4S"}},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","type":"stx_transfer_event","committed":true,"event_index":4,"stx_transfer_event":{"amount":"654545","sender":"SP1Q09AR2RGJRDAKW6FBDDG6N2CBHYFVWDT7SVGCJ","recipient":"SPZRAE52H2NC2MDBEV8W99RFVPK8Q9BW8H88XV9N"}}],"block_hash":"0xd51cd57ccbed84d08a0158f6b44dfee1a0896ed2ddd6e9e0f37ef6528cd692de","miner_txid":"0xa874abae6787c8c5339107fc669bde7e388dc3f6c60cdf429c0db5e69cf8074e","block_height":51655,"transactions":[{"txid":"0x2553c7c5b49eab5a0569e5d0f14c8f15945965a51976ac6697641003533986f6","raw_tx":"0x00","status":"success","tx_index":0,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null},{"txid":"0xa60e1d365bae6153b82efdf8031cd0b8c389ec083a2a31fc1869f2899c9ca049","raw_tx":"0x0000000001040029cc0b8ad8636eadd807a786dc000146553bd59a000000000000028100000000000000000001f6342b223c478581f46244704d83990b71b1611156f734f12dff3742d30b9dbe612813eaf550ae0021fef642643a8e79de7fd489ef7502de0578ea43dcbff112010200000000040000000000000000000000000000000000000000000000000000000000000000","status":"success","tx_index":1,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null},{"txid":"0x62cf75b37193353f9e7b7d0f1fc55314430ded8d8f98e260cbe5a5cf3fc5820a","raw_tx":"0x000000000104006e04ab02c42586aa7c33d6d6c0d513171f3f7c6e0000000000000000000000000003ffef0000cc7bee3e952b4a4166d996aeba1257d65e764ccdc4a217851f5b4ee0f2faf41331b1169e5380e1ea94083465778d0933640197c816daf283680914c17a6012780302000000020002166e04ab02c42586aa7c33d6d6c0d513171f3f7c6e05000000000bebc200020216ff473f87dc4e937eea8865454b44e309bb3bff7a16ef954ae47291ceb9b9c6274ffc49ac521dfccc2f0d637261736870756e6b732d76320d637261736870756e6b732d7632010000000000000000000000000000120e100216ef954ae47291ceb9b9c6274ffc49ac521dfccc2f0d637261736870756e6b732d76320b6275792d696e2d7573747800000002010000000000000000000000000000120e06162bcf9762d5b90bc36dc1b4759b1727690f92ddd31f637261736870756e6b732d76322d7374786e66742d636f6d6d697373696f6e","status":"success","tx_index":2,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":64762,"read_count":19,"read_length":13236,"write_count":11,"write_length":29},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null},{"txid":"0xc68191241d3023c5ef487e0597092e05ee5072e11683315d559f042d30a38257","raw_tx":"0x00000000010400065931c73bf56e6ddc0edea069f64bd061c8e0be000000000000060a00000000000000b40001c926e708059056a55813591f7b6cbbdfd001c07d99643f4f710e62a38e5b2de841a3ad50c3c84d535758c41a9c78c7befe7170d4f04954c6c7eb1c99836d4b40030200000000000516e3d94a92b80d0aabe8ef1b50de84449cd61ad63700000000b55a3e9131313838343700000000000000000000000000000000000000000000000000000000","status":"success","tx_index":3,"raw_result":"0x0703","contract_abi":null,"execution_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"microblock_hash":null,"microblock_sequence":null,"microblock_parent_hash":null}],"anchored_cost":{"runtime":64762,"read_count":19,"read_length":13236,"write_count":11,"write_length":29},"burn_block_hash":"0x0000000000000000000984f90550aead762d7b828a7bf4414a33cf90d015b98a","burn_block_time":1646858171,"index_block_hash":"0xacbcd86508292a25eb6fbb528d4dc3914a22f4dae03ebca4eae80b3f9f161760","burn_block_height":726601,"parent_block_hash":"0xb1f3116c0c698fc05d7e6e49ce8478e1e79d134efda77834675c98519fc6dc11","parent_microblock":"0x0000000000000000000000000000000000000000000000000000000000000000","matured_miner_rewards":[{"recipient":"SP1Q7NC4FFRMCE59HS7BVF3CGHK6RRT8WD1M0WWSF","coinbase_amount":"1000000000","tx_fees_anchored":"2352739","from_stacks_block_hash":"0x718382e6f8ac7e7a855f0044ca8a68dc07bfd3808013f73b80c70def40dbe5df","from_index_consensus_hash":"0xcd9c9435556d5f00781192d39f1f845732d58f7dba970ce48d553f83095818b3","tx_fees_streamed_produced":"0","tx_fees_streamed_confirmed":"794668"},{"recipient":"SPMWR2WAV1HPXBER0YKRDQ000535AEYNK91MVCZF","coinbase_amount":"0","tx_fees_anchored":"0","from_stacks_block_hash":"0x718382e6f8ac7e7a855f0044ca8a68dc07bfd3808013f73b80c70def40dbe5df","from_index_consensus_hash":"0xcd9c9435556d5f00781192d39f1f845732d58f7dba970ce48d553f83095818b3","tx_fees_streamed_produced":"1580000","tx_fees_streamed_confirmed":"0"}],"parent_burn_block_hash":"0x00000000000000000006027b9de2e4a9e09cda9646edb391bd434f97f063dc1b","parent_index_block_hash":"0xfcdee58979922da016ca65db9b54be09db97d88bb6aa0c9cd66a9e2b7fa4b0a2","parent_burn_block_height":726600,"confirmed_microblocks_cost":{"runtime":0,"read_count":0,"read_length":0,"write_count":0,"write_length":0},"parent_microblock_sequence":0,"parent_burn_block_timestamp":1646857773} \ No newline at end of file From 2495537e6088d9038aa380e9c2d1342f43dbcda4 Mon Sep 17 00:00:00 2001 From: Rafael Cardenas Date: Thu, 3 Jul 2025 12:15:33 -0600 Subject: [PATCH 5/7] fix: remove old tests --- tests/api/synthetic-stx-txs.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/api/synthetic-stx-txs.test.ts b/tests/api/synthetic-stx-txs.test.ts index 92776cb2f..b19769c30 100644 --- a/tests/api/synthetic-stx-txs.test.ts +++ b/tests/api/synthetic-stx-txs.test.ts @@ -127,7 +127,6 @@ describe('synthetic stx txs', () => { }; expect(parsed.parsed_tx).toEqual(expect.objectContaining(expected)); - expect(parsed.block_time).toEqual(1846858171); // Takes block_time from block header }); test('test synthetic tx stx lock 1', () => { @@ -237,7 +236,6 @@ describe('synthetic stx txs', () => { for (const poxEvent of parsed.txs[0].pox4Events) { expect(poxEvent.event_index).toBeLessThan(events.length); } - expect(parsed.block.block_time).toEqual(1716238792); // Takes burn_block_time from block header }); test('test synthetic tx stx lock 2', () => { From 1ba41fa7d999364bdb446740dab3ee11579dd661 Mon Sep 17 00:00:00 2001 From: Rafael Cardenas Date: Mon, 7 Jul 2025 12:00:54 -0600 Subject: [PATCH 6/7] fix: throw when no time is present --- src/event-stream/event-server.ts | 12 +++++++++--- tests/api/block-time.test.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/event-stream/event-server.ts b/src/event-stream/event-server.ts index 0b57715b7..572704515 100644 --- a/src/event-stream/event-server.ts +++ b/src/event-stream/event-server.ts @@ -997,12 +997,18 @@ export function parseNewBlockMessage( ) { const counts = newCoreNoreBlockEventCounts(); + // Nakamoto blocks now include their own `block_time`, but this will be empty for pre-Nakamoto + // blocks. We'll use the parent burn block timestamp as the receipt date for those. If both are + // blank, there's something wrong with Stacks core. + const block_time = msg.block_time ?? msg.burn_block_time; + if (!block_time) { + throw new Error('Block message has no block_time or burn_block_time'); + } + const parsedTxs: CoreNodeParsedTxMessage[] = []; const blockData: CoreNodeMsgBlockData = { ...msg, - // Nakamoto blocks now include their own `block_time`, but this will be empty for pre-Nakamoto - // blocks. We'll use the parent burn block timestamp as the receipt date for those. - block_time: msg.block_time ?? msg.burn_block_time ?? Math.round(Date.now() / 1000), + block_time, }; msg.transactions.forEach(item => { diff --git a/tests/api/block-time.test.ts b/tests/api/block-time.test.ts index 8571b573d..b4607b9a6 100644 --- a/tests/api/block-time.test.ts +++ b/tests/api/block-time.test.ts @@ -52,4 +52,31 @@ describe('block time tests', () => { const { dbData: parsed } = parseNewBlockMessage(ChainID.Mainnet, block, false); expect(parsed.block.block_time).toEqual(1234567890); // Takes burn_block_time from block header }); + + test('throws error if block_time and burn_block_time are not present', () => { + // Use `any` to avoid type errors when setting `block_time` and `burn_block_time` to `null`. + const block: any = { + block_time: null, + burn_block_time: null, + block_height: 1, + block_hash: '0x1234', + index_block_hash: '0x5678', + parent_index_block_hash: '0x9abc', + parent_block_hash: '0x1234', + parent_microblock: '0x1234', + parent_microblock_sequence: 0, + parent_burn_block_hash: '0x1234', + parent_burn_block_height: 0, + parent_burn_block_timestamp: 0, + burn_block_hash: '0x1234', + burn_block_height: 1, + miner_txid: '0x1234', + events: [], + transactions: [], + matured_miner_rewards: [], + }; + expect(() => parseNewBlockMessage(ChainID.Mainnet, block, false)).toThrow( + 'Block message has no block_time or burn_block_time' + ); + }); }); From 1388279b2952f859df7a811155d4a8e93068cfd8 Mon Sep 17 00:00:00 2001 From: Rafael Cardenas Date: Mon, 7 Jul 2025 12:10:02 -0600 Subject: [PATCH 7/7] fix: block time falsy check --- src/event-stream/event-server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/event-stream/event-server.ts b/src/event-stream/event-server.ts index 572704515..00b541eba 100644 --- a/src/event-stream/event-server.ts +++ b/src/event-stream/event-server.ts @@ -1001,7 +1001,7 @@ export function parseNewBlockMessage( // blocks. We'll use the parent burn block timestamp as the receipt date for those. If both are // blank, there's something wrong with Stacks core. const block_time = msg.block_time ?? msg.burn_block_time; - if (!block_time) { + if (block_time === undefined || block_time === null) { throw new Error('Block message has no block_time or burn_block_time'); }