@@ -1726,6 +1726,226 @@ describe('mempool tests', () => {
1726
1726
expect ( txResult2 . body . tx_status ) . toBe ( 'success' ) ;
1727
1727
} ) ;
1728
1728
1729
+ test ( 'Revive dropped and rebroadcasted mempool tx' , async ( ) => {
1730
+ const senderAddress = 'SP25YGP221F01S9SSCGN114MKDAK9VRK8P3KXGEMB' ;
1731
+ const txId = '0x521234' ;
1732
+ const dbBlock1 : DbBlock = {
1733
+ block_hash : '0x0123' ,
1734
+ index_block_hash : '0x1234' ,
1735
+ parent_index_block_hash : '0x5678' ,
1736
+ parent_block_hash : '0x5678' ,
1737
+ parent_microblock_hash : '0x00' ,
1738
+ parent_microblock_sequence : 0 ,
1739
+ block_height : 1 ,
1740
+ burn_block_time : 39486 ,
1741
+ burn_block_hash : '0x1234' ,
1742
+ burn_block_height : 123 ,
1743
+ miner_txid : '0x4321' ,
1744
+ canonical : true ,
1745
+ execution_cost_read_count : 0 ,
1746
+ execution_cost_read_length : 0 ,
1747
+ execution_cost_runtime : 0 ,
1748
+ execution_cost_write_count : 0 ,
1749
+ execution_cost_write_length : 0 ,
1750
+ tx_count : 1 ,
1751
+ } ;
1752
+ const dbBlock1b : DbBlock = {
1753
+ block_hash : '0x0123bb' ,
1754
+ index_block_hash : '0x1234bb' ,
1755
+ parent_index_block_hash : '0x5678bb' ,
1756
+ parent_block_hash : '0x5678bb' ,
1757
+ parent_microblock_hash : '0x00' ,
1758
+ parent_microblock_sequence : 0 ,
1759
+ block_height : 1 ,
1760
+ burn_block_time : 39486 ,
1761
+ burn_block_hash : '0x1234bb' ,
1762
+ burn_block_height : 123 ,
1763
+ miner_txid : '0x4321bb' ,
1764
+ canonical : true ,
1765
+ execution_cost_read_count : 0 ,
1766
+ execution_cost_read_length : 0 ,
1767
+ execution_cost_runtime : 0 ,
1768
+ execution_cost_write_count : 0 ,
1769
+ execution_cost_write_length : 0 ,
1770
+ tx_count : 1 ,
1771
+ } ;
1772
+ const dbBlock2b : DbBlock = {
1773
+ block_hash : '0x2123' ,
1774
+ index_block_hash : '0x2234' ,
1775
+ parent_index_block_hash : dbBlock1b . index_block_hash ,
1776
+ parent_block_hash : dbBlock1b . block_hash ,
1777
+ parent_microblock_hash : '0x00' ,
1778
+ parent_microblock_sequence : 0 ,
1779
+ block_height : 2 ,
1780
+ burn_block_time : 39486 ,
1781
+ burn_block_hash : '0x1234' ,
1782
+ burn_block_height : 123 ,
1783
+ miner_txid : '0x4321' ,
1784
+ canonical : true ,
1785
+ execution_cost_read_count : 0 ,
1786
+ execution_cost_read_length : 0 ,
1787
+ execution_cost_runtime : 0 ,
1788
+ execution_cost_write_count : 0 ,
1789
+ execution_cost_write_length : 0 ,
1790
+ tx_count : 1 ,
1791
+ } ;
1792
+ const mempoolTx : DbMempoolTxRaw = {
1793
+ tx_id : txId ,
1794
+ anchor_mode : 3 ,
1795
+ nonce : 0 ,
1796
+ raw_tx : bufferToHex ( Buffer . from ( 'test-raw-mempool-tx' ) ) ,
1797
+ type_id : DbTxTypeId . Coinbase ,
1798
+ status : 1 ,
1799
+ post_conditions : '0x01f5' ,
1800
+ fee_rate : 1234n ,
1801
+ sponsored : false ,
1802
+ sponsor_address : undefined ,
1803
+ sender_address : senderAddress ,
1804
+ origin_hash_mode : 1 ,
1805
+ coinbase_payload : bufferToHex ( Buffer . from ( 'hi' ) ) ,
1806
+ pruned : false ,
1807
+ receipt_time : 1616063078 ,
1808
+ } ;
1809
+ const dbTx1 : DbTxRaw = {
1810
+ ...mempoolTx ,
1811
+ ...dbBlock1 ,
1812
+ parent_burn_block_time : 1626122935 ,
1813
+ tx_index : 4 ,
1814
+ status : DbTxStatus . Success ,
1815
+ raw_result : '0x0100000000000000000000000000000001' , // u1
1816
+ canonical : true ,
1817
+ microblock_canonical : true ,
1818
+ microblock_sequence : I32_MAX ,
1819
+ microblock_hash : '' ,
1820
+ parent_index_block_hash : '' ,
1821
+ event_count : 0 ,
1822
+ execution_cost_read_count : 0 ,
1823
+ execution_cost_read_length : 0 ,
1824
+ execution_cost_runtime : 0 ,
1825
+ execution_cost_write_count : 0 ,
1826
+ execution_cost_write_length : 0 ,
1827
+ } ;
1828
+
1829
+ await db . updateMempoolTxs ( { mempoolTxs : [ mempoolTx ] } ) ;
1830
+
1831
+ let chainTip = await db . getChainTip ( ) ;
1832
+ expect ( chainTip . mempool_tx_count ) . toBe ( 1 ) ;
1833
+
1834
+ // Verify tx shows up in mempool (non-pruned)
1835
+ const mempoolResult1 = await supertest ( api . server ) . get (
1836
+ `/extended/v1/address/${ mempoolTx . sender_address } /mempool`
1837
+ ) ;
1838
+ expect ( mempoolResult1 . body . results [ 0 ] . tx_id ) . toBe ( txId ) ;
1839
+ const mempoolCount1 = await supertest ( api . server ) . get ( `/extended/v1/tx/mempool` ) ;
1840
+ expect ( mempoolCount1 . body . total ) . toBe ( 1 ) ;
1841
+
1842
+ // Drop mempool tx
1843
+ await db . dropMempoolTxs ( {
1844
+ status : DbTxStatus . DroppedStaleGarbageCollect ,
1845
+ txIds : [ mempoolTx . tx_id ] ,
1846
+ } ) ;
1847
+
1848
+ // Verify tx is pruned from mempool
1849
+ const mempoolResult2 = await supertest ( api . server ) . get (
1850
+ `/extended/v1/address/${ mempoolTx . sender_address } /mempool`
1851
+ ) ;
1852
+ expect ( mempoolResult2 . body . results ) . toHaveLength ( 0 ) ;
1853
+ const mempoolCount2 = await supertest ( api . server ) . get ( `/extended/v1/tx/mempool` ) ;
1854
+ expect ( mempoolCount2 . body . total ) . toBe ( 0 ) ;
1855
+ chainTip = await db . getChainTip ( ) ;
1856
+ expect ( chainTip . mempool_tx_count ) . toBe ( 0 ) ;
1857
+
1858
+ // Re-broadcast mempool tx
1859
+ await db . updateMempoolTxs ( { mempoolTxs : [ mempoolTx ] } ) ;
1860
+
1861
+ // Verify tx shows up in mempool again (revived)
1862
+ const mempoolResult3 = await supertest ( api . server ) . get (
1863
+ `/extended/v1/address/${ mempoolTx . sender_address } /mempool`
1864
+ ) ;
1865
+ expect ( mempoolResult3 . body . results [ 0 ] . tx_id ) . toBe ( txId ) ;
1866
+ const mempoolCount3 = await supertest ( api . server ) . get ( `/extended/v1/tx/mempool` ) ;
1867
+ expect ( mempoolCount3 . body . total ) . toBe ( 1 ) ;
1868
+ chainTip = await db . getChainTip ( ) ;
1869
+ expect ( chainTip . mempool_tx_count ) . toBe ( 1 ) ;
1870
+
1871
+ // Mine tx in block to prune from mempool
1872
+ await db . update ( {
1873
+ block : dbBlock1 ,
1874
+ microblocks : [ ] ,
1875
+ minerRewards : [ ] ,
1876
+ txs : [
1877
+ {
1878
+ tx : dbTx1 ,
1879
+ stxEvents : [ ] ,
1880
+ stxLockEvents : [ ] ,
1881
+ ftEvents : [ ] ,
1882
+ nftEvents : [ ] ,
1883
+ contractLogEvents : [ ] ,
1884
+ smartContracts : [ ] ,
1885
+ names : [ ] ,
1886
+ namespaces : [ ] ,
1887
+ pox2Events : [ ] ,
1888
+ pox3Events : [ ] ,
1889
+ pox4Events : [ ] ,
1890
+ } ,
1891
+ ] ,
1892
+ } ) ;
1893
+
1894
+ // Verify tx is pruned from mempool
1895
+ const mempoolResult4 = await supertest ( api . server ) . get (
1896
+ `/extended/v1/address/${ mempoolTx . sender_address } /mempool`
1897
+ ) ;
1898
+ expect ( mempoolResult4 . body . results ) . toHaveLength ( 0 ) ;
1899
+ const mempoolCount4 = await supertest ( api . server ) . get ( `/extended/v1/tx/mempool` ) ;
1900
+ expect ( mempoolCount4 . body . total ) . toBe ( 0 ) ;
1901
+ chainTip = await db . getChainTip ( ) ;
1902
+ expect ( chainTip . mempool_tx_count ) . toBe ( 0 ) ;
1903
+
1904
+ // Verify tx is mined
1905
+ const txResult1 = await supertest ( api . server ) . get ( `/extended/v1/tx/${ txId } ` ) ;
1906
+ expect ( txResult1 . body . tx_status ) . toBe ( 'success' ) ;
1907
+ expect ( txResult1 . body . canonical ) . toBe ( true ) ;
1908
+
1909
+ // Orphan the block to get the tx orphaned and placed back in the pool
1910
+ await db . update ( {
1911
+ block : dbBlock1b ,
1912
+ microblocks : [ ] ,
1913
+ minerRewards : [ ] ,
1914
+ txs : [ ] ,
1915
+ } ) ;
1916
+ await db . update ( {
1917
+ block : dbBlock2b ,
1918
+ microblocks : [ ] ,
1919
+ minerRewards : [ ] ,
1920
+ txs : [ ] ,
1921
+ } ) ;
1922
+
1923
+ // Verify tx is orphaned and back in mempool
1924
+ const txResult2 = await supertest ( api . server ) . get ( `/extended/v1/tx/${ txId } ` ) ;
1925
+ expect ( txResult2 . body . canonical ) . toBeFalsy ( ) ;
1926
+
1927
+ // Verify tx has been revived and is back in the mempool
1928
+ const mempoolResult5 = await supertest ( api . server ) . get (
1929
+ `/extended/v1/address/${ mempoolTx . sender_address } /mempool`
1930
+ ) ;
1931
+ expect ( mempoolResult5 . body . results [ 0 ] . tx_id ) . toBe ( txId ) ;
1932
+ const mempoolCount5 = await supertest ( api . server ) . get ( `/extended/v1/tx/mempool` ) ;
1933
+ expect ( mempoolCount5 . body . total ) . toBe ( 1 ) ;
1934
+ chainTip = await db . getChainTip ( ) ;
1935
+ expect ( chainTip . mempool_tx_count ) . toBe ( 1 ) ;
1936
+
1937
+ // Re-broadcast mempool tx
1938
+ await db . updateMempoolTxs ( { mempoolTxs : [ mempoolTx ] } ) ;
1939
+
1940
+ // Verify tx has been revived and is back in the mempool
1941
+ const mempoolResult6 = await supertest ( api . server ) . get (
1942
+ `/extended/v1/address/${ mempoolTx . sender_address } /mempool`
1943
+ ) ;
1944
+ expect ( mempoolResult6 . body . results [ 0 ] . tx_id ) . toBe ( txId ) ;
1945
+ const mempoolCount6 = await supertest ( api . server ) . get ( `/extended/v1/tx/mempool` ) ;
1946
+ expect ( mempoolCount6 . body . total ) . toBe ( 1 ) ;
1947
+ } ) ;
1948
+
1729
1949
test ( 'returns fee priorities for mempool transactions' , async ( ) => {
1730
1950
const mempoolTxs : DbMempoolTxRaw [ ] = [ ] ;
1731
1951
for ( let i = 0 ; i < 10 ; i ++ ) {
0 commit comments