@@ -34,6 +34,102 @@ fn blockchain__dump_tx_out_set__modelled() {
3434 assert ! ( dump. coins_written. to_sat( ) > 0 ) ;
3535}
3636
37+ #[ test]
38+ #[ cfg( not( feature = "v25_and_below" ) ) ]
39+ fn blockchain__load_tx_out_set__modelled ( ) {
40+ // Regtest `loadtxoutset` requires replicating Bitcoin Core's C++
41+ // TestChain100Setup to produce the exact chain whose height at `110`
42+ // assumeutxo snapshot hash is hardcoded in chainparams.
43+ //
44+ // The C++ test framework uses:
45+ // - SetMockTime(1598887952), incrementing by 1 after each block
46+ // - P2PK coinbase output to compressed pubkey of private key 0x01
47+ // - 110 coinbase-only blocks (no wallet transactions)
48+ //
49+ // Matching these exactly helps us arrive at the expected hash at snapshot
50+
51+ #[ cfg( feature = "v29_and_below" ) ]
52+ let expected_block_hash = "696e92821f65549c7ee134edceeeeaaa4105647a3c4fd9f298c0aec0ab50425c" ;
53+ #[ cfg( not( feature = "v29_and_below" ) ) ]
54+ let expected_block_hash = "6affe030b7965ab538f820a56ef56c8149b7dc1d1c144af57113be080db7c397" ;
55+
56+ let snapshot_height = 110 ;
57+
58+ // Compressed public key for private key 0x01
59+ let coinbase_descriptor =
60+ "pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)" ;
61+
62+ let exe = node:: exe_path ( ) . expect ( "failed to get bitcoind executable" ) ;
63+ let mut conf_a = node:: Conf :: default ( ) ;
64+ conf_a. p2p = node:: P2P :: Yes ;
65+ let node_a = Node :: with_conf ( & exe, & conf_a) . expect ( "failed to create miner node" ) ;
66+
67+ // TestChain100Setup mocktime matched to the exact
68+ const MOCK_TIME_START : u64 = 1598887952 ;
69+ for i in 0 ..snapshot_height {
70+ let mock_time = MOCK_TIME_START + i;
71+ let _: node:: serde_json:: Value = node_a
72+ . client
73+ . call ( "setmocktime" , & [ node:: serde_json:: json!( mock_time) ] )
74+ . expect ( "setmocktime" ) ;
75+ node_a. client . generate_to_descriptor ( 1 , coinbase_descriptor) . expect ( "generatetodescriptor" ) ;
76+ }
77+
78+ let hash_at_height = node_a
79+ . client
80+ . get_block_hash ( snapshot_height)
81+ . expect ( "getblockhash" )
82+ . block_hash ( )
83+ . expect ( "parse block hash" ) ;
84+ assert_eq ! (
85+ hash_at_height. to_string( ) ,
86+ expected_block_hash,
87+ "block hash at height {} does not match hardcoded assumeutxo entry" ,
88+ snapshot_height
89+ ) ;
90+
91+ let temp_path = integration_test:: random_tmp_file ( ) ;
92+ let dump_path = temp_path. to_str ( ) . expect ( "temp path should be valid UTF-8" ) ;
93+ #[ cfg( feature = "v28_and_below" ) ]
94+ {
95+ let _: DumpTxOutSet = node_a. client . dump_tx_out_set ( dump_path) . expect ( "dumptxoutset" ) ;
96+ }
97+ #[ cfg( not( feature = "v28_and_below" ) ) ]
98+ {
99+ let _: DumpTxOutSet =
100+ node_a. client . dump_tx_out_set ( dump_path, "latest" ) . expect ( "dumptxoutset" ) ;
101+ }
102+ let mut conf_b = node:: Conf :: default ( ) ;
103+ conf_b. wallet = None ;
104+ conf_b. p2p = node:: P2P :: No ;
105+ let node_b = Node :: with_conf ( & exe, & conf_b) . expect ( "failed to create loader node" ) ;
106+
107+ for h in 1 ..=snapshot_height {
108+ let bh = node_a
109+ . client
110+ . get_block_hash ( h)
111+ . expect ( "getblockhash" )
112+ . block_hash ( )
113+ . expect ( "parse block hash" ) ;
114+ let header = node_a
115+ . client
116+ . get_block_header ( & bh)
117+ . expect ( "getblockheader" )
118+ . block_header ( )
119+ . expect ( "parse block header" ) ;
120+ node_b. client . submit_header ( & header) . expect ( "submitheader" ) ;
121+ }
122+
123+ let json: LoadTxOutSet =
124+ node_b. client . load_tx_out_set ( dump_path) . expect ( "loadtxoutset should succeed" ) ;
125+ let model: Result < mtype:: LoadTxOutSet , LoadTxOutSetError > = json. into_model ( ) ;
126+ let model = model. unwrap ( ) ;
127+
128+ assert_eq ! ( model. base_height, snapshot_height as u32 ) ;
129+ assert_eq ! ( model. tip_hash, hash_at_height) ;
130+ assert_eq ! ( model. coins_loaded, bitcoin:: Amount :: from_btc( 110.0 ) . unwrap( ) ) ;
131+ }
132+
37133#[ test]
38134fn blockchain__get_best_block_hash__modelled ( ) {
39135 let node = Node :: with_wallet ( Wallet :: None , & [ ] ) ;
0 commit comments