• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stacks-network / stacks-core / 25903914664-1

15 May 2026 06:28AM UTC coverage: 47.122% (-38.8%) from 85.959%
25903914664-1

Pull #7199

github

94e391
web-flow
Merge 109f2828c into 1c7b8e6ac
Pull Request #7199: Feat: L1 and L2 early unlocks, updating signer

103343 of 219309 relevant lines covered (47.12%)

12880462.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.1
/stackslib/src/core/test_util.rs
1
// Copyright (C) 2025-2026 Stacks Open Internet Foundation
2
//
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, either version 3 of the License, or
6
// (at your option) any later version.
7
//
8
// This program is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
// GNU General Public License for more details.
12
//
13
// You should have received a copy of the GNU General Public License
14
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
15

16
use std::io::Cursor;
17

18
use chrono::Utc;
19
use clarity::codec::StacksMessageCodec;
20
use clarity::types::chainstate::{
21
    BlockHeaderHash, ConsensusHash, StacksAddress, StacksPrivateKey, StacksPublicKey,
22
};
23
use clarity::vm::costs::ExecutionCost;
24
use clarity::vm::tests::BurnStateDB;
25
use clarity::vm::types::PrincipalData;
26
use clarity::vm::{ClarityName, ClarityVersion, ContractName, Value};
27

28
use crate::chainstate::stacks::db::StacksChainState;
29
use crate::chainstate::stacks::miner::{BlockBuilderSettings, StacksMicroblockBuilder};
30
use crate::chainstate::stacks::{
31
    CoinbasePayload, StacksBlock, StacksMicroblock, StacksMicroblockHeader, StacksTransaction,
32
    StacksTransactionSigner, TenureChangePayload, TokenTransferMemo, TransactionAnchorMode,
33
    TransactionAuth, TransactionContractCall, TransactionPayload, TransactionPostConditionMode,
34
    TransactionSmartContract, TransactionSpendingCondition, TransactionVersion,
35
};
36
use crate::util_lib::strings::StacksString;
37

38
#[allow(clippy::too_many_arguments)]
39
pub fn sign_sponsored_sig_tx_anchor_mode_version(
×
40
    payload: TransactionPayload,
×
41
    sender: &StacksPrivateKey,
×
42
    payer: &StacksPrivateKey,
×
43
    sender_nonce: u64,
×
44
    payer_nonce: u64,
×
45
    tx_fee: u64,
×
46
    chain_id: u32,
×
47
    anchor_mode: TransactionAnchorMode,
×
48
    version: TransactionVersion,
×
49
) -> StacksTransaction {
×
50
    sign_tx_anchor_mode_version(
×
51
        payload,
×
52
        sender,
×
53
        Some(payer),
×
54
        sender_nonce,
×
55
        Some(payer_nonce),
×
56
        tx_fee,
×
57
        chain_id,
×
58
        anchor_mode,
×
59
        version,
×
60
    )
61
}
×
62

63
pub fn sign_standard_single_sig_tx(
12,686,284✔
64
    payload: TransactionPayload,
12,686,284✔
65
    sender: &StacksPrivateKey,
12,686,284✔
66
    nonce: u64,
12,686,284✔
67
    tx_fee: u64,
12,686,284✔
68
    chain_id: u32,
12,686,284✔
69
) -> StacksTransaction {
12,686,284✔
70
    sign_standard_single_sig_tx_anchor_mode(
12,686,284✔
71
        payload,
12,686,284✔
72
        sender,
12,686,284✔
73
        nonce,
12,686,284✔
74
        tx_fee,
12,686,284✔
75
        chain_id,
12,686,284✔
76
        TransactionAnchorMode::OnChainOnly,
12,686,284✔
77
    )
78
}
12,686,284✔
79

80
pub fn sign_standard_single_sig_tx_anchor_mode(
12,686,356✔
81
    payload: TransactionPayload,
12,686,356✔
82
    sender: &StacksPrivateKey,
12,686,356✔
83
    nonce: u64,
12,686,356✔
84
    tx_fee: u64,
12,686,356✔
85
    chain_id: u32,
12,686,356✔
86
    anchor_mode: TransactionAnchorMode,
12,686,356✔
87
) -> StacksTransaction {
12,686,356✔
88
    sign_standard_single_sig_tx_anchor_mode_version(
12,686,356✔
89
        payload,
12,686,356✔
90
        sender,
12,686,356✔
91
        nonce,
12,686,356✔
92
        tx_fee,
12,686,356✔
93
        chain_id,
12,686,356✔
94
        anchor_mode,
12,686,356✔
95
        TransactionVersion::Testnet,
12,686,356✔
96
    )
97
}
12,686,356✔
98

99
pub fn sign_standard_single_sig_tx_anchor_mode_version(
12,686,356✔
100
    payload: TransactionPayload,
12,686,356✔
101
    sender: &StacksPrivateKey,
12,686,356✔
102
    nonce: u64,
12,686,356✔
103
    tx_fee: u64,
12,686,356✔
104
    chain_id: u32,
12,686,356✔
105
    anchor_mode: TransactionAnchorMode,
12,686,356✔
106
    version: TransactionVersion,
12,686,356✔
107
) -> StacksTransaction {
12,686,356✔
108
    sign_tx_anchor_mode_version(
12,686,356✔
109
        payload,
12,686,356✔
110
        sender,
12,686,356✔
111
        None,
12,686,356✔
112
        nonce,
12,686,356✔
113
        None,
12,686,356✔
114
        tx_fee,
12,686,356✔
115
        chain_id,
12,686,356✔
116
        anchor_mode,
12,686,356✔
117
        version,
12,686,356✔
118
    )
119
}
12,686,356✔
120

121
#[allow(clippy::too_many_arguments)]
122
pub fn make_unsigned_tx(
12,686,356✔
123
    payload: TransactionPayload,
12,686,356✔
124
    sender: &StacksPrivateKey,
12,686,356✔
125
    payer: Option<&StacksPrivateKey>,
12,686,356✔
126
    sender_nonce: u64,
12,686,356✔
127
    payer_nonce: Option<u64>,
12,686,356✔
128
    tx_fee: u64,
12,686,356✔
129
    chain_id: u32,
12,686,356✔
130
    anchor_mode: TransactionAnchorMode,
12,686,356✔
131
    version: TransactionVersion,
12,686,356✔
132
) -> StacksTransaction {
12,686,356✔
133
    let mut sender_spending_condition =
12,686,356✔
134
        TransactionSpendingCondition::new_singlesig_p2pkh(StacksPublicKey::from_private(sender))
12,686,356✔
135
            .expect("Failed to create p2pkh spending condition from public key.");
12,686,356✔
136
    sender_spending_condition.set_nonce(sender_nonce);
12,686,356✔
137

138
    let auth = match (payer, payer_nonce) {
12,686,356✔
139
        (Some(payer), Some(payer_nonce)) => {
×
140
            let mut payer_spending_condition = TransactionSpendingCondition::new_singlesig_p2pkh(
×
141
                StacksPublicKey::from_private(payer),
×
142
            )
143
            .expect("Failed to create p2pkh spending condition from public key.");
×
144
            payer_spending_condition.set_nonce(payer_nonce);
×
145
            payer_spending_condition.set_tx_fee(tx_fee);
×
146
            TransactionAuth::Sponsored(sender_spending_condition, payer_spending_condition)
×
147
        }
148
        _ => {
149
            sender_spending_condition.set_tx_fee(tx_fee);
12,686,356✔
150
            TransactionAuth::Standard(sender_spending_condition)
12,686,356✔
151
        }
152
    };
153
    let mut unsigned_tx = StacksTransaction::new(version, auth, payload);
12,686,356✔
154
    unsigned_tx.anchor_mode = anchor_mode;
12,686,356✔
155
    unsigned_tx.post_condition_mode = TransactionPostConditionMode::Allow;
12,686,356✔
156
    unsigned_tx.chain_id = chain_id;
12,686,356✔
157
    unsigned_tx
12,686,356✔
158
}
12,686,356✔
159

160
#[allow(clippy::too_many_arguments)]
161
pub fn sign_tx_anchor_mode_version(
12,686,356✔
162
    payload: TransactionPayload,
12,686,356✔
163
    sender: &StacksPrivateKey,
12,686,356✔
164
    payer: Option<&StacksPrivateKey>,
12,686,356✔
165
    sender_nonce: u64,
12,686,356✔
166
    payer_nonce: Option<u64>,
12,686,356✔
167
    tx_fee: u64,
12,686,356✔
168
    chain_id: u32,
12,686,356✔
169
    anchor_mode: TransactionAnchorMode,
12,686,356✔
170
    version: TransactionVersion,
12,686,356✔
171
) -> StacksTransaction {
12,686,356✔
172
    let unsigned_tx = make_unsigned_tx(
12,686,356✔
173
        payload,
12,686,356✔
174
        sender,
12,686,356✔
175
        payer,
12,686,356✔
176
        sender_nonce,
12,686,356✔
177
        payer_nonce,
12,686,356✔
178
        tx_fee,
12,686,356✔
179
        chain_id,
12,686,356✔
180
        anchor_mode,
12,686,356✔
181
        version,
12,686,356✔
182
    );
183

184
    let mut tx_signer = StacksTransactionSigner::new(&unsigned_tx);
12,686,356✔
185
    tx_signer.sign_origin(sender).unwrap();
12,686,356✔
186
    if let (Some(payer), Some(_)) = (payer, payer_nonce) {
12,686,356✔
187
        tx_signer.sign_sponsor(payer).unwrap();
×
188
    }
12,686,356✔
189

190
    tx_signer.get_tx().unwrap()
12,686,356✔
191
}
12,686,356✔
192

193
#[allow(clippy::too_many_arguments)]
194
pub fn serialize_sign_tx_anchor_mode_version(
×
195
    payload: TransactionPayload,
×
196
    sender: &StacksPrivateKey,
×
197
    payer: Option<&StacksPrivateKey>,
×
198
    sender_nonce: u64,
×
199
    payer_nonce: Option<u64>,
×
200
    tx_fee: u64,
×
201
    chain_id: u32,
×
202
    anchor_mode: TransactionAnchorMode,
×
203
    version: TransactionVersion,
×
204
) -> Vec<u8> {
×
205
    let tx = sign_tx_anchor_mode_version(
×
206
        payload,
×
207
        sender,
×
208
        payer,
×
209
        sender_nonce,
×
210
        payer_nonce,
×
211
        tx_fee,
×
212
        chain_id,
×
213
        anchor_mode,
×
214
        version,
×
215
    );
216

217
    let mut buf = vec![];
×
218
    tx.consensus_serialize(&mut buf).unwrap();
×
219
    buf
×
220
}
×
221

222
pub fn make_contract_publish_tx(
963✔
223
    sender: &StacksPrivateKey,
963✔
224
    nonce: u64,
963✔
225
    tx_fee: u64,
963✔
226
    chain_id: u32,
963✔
227
    contract_name: &str,
963✔
228
    contract_content: &str,
963✔
229
    version: Option<ClarityVersion>,
963✔
230
) -> StacksTransaction {
963✔
231
    let name = ContractName::try_from(contract_name).expect("invalid contract name");
963✔
232
    let code_body = StacksString::from_string(&contract_content.to_string()).unwrap();
963✔
233

234
    let payload =
963✔
235
        TransactionPayload::SmartContract(TransactionSmartContract { name, code_body }, version);
963✔
236

237
    sign_standard_single_sig_tx(payload, sender, nonce, tx_fee, chain_id)
963✔
238
}
963✔
239

240
pub fn make_contract_publish_versioned(
963✔
241
    sender: &StacksPrivateKey,
963✔
242
    nonce: u64,
963✔
243
    tx_fee: u64,
963✔
244
    chain_id: u32,
963✔
245
    contract_name: &str,
963✔
246
    contract_content: &str,
963✔
247
    version: Option<ClarityVersion>,
963✔
248
) -> Vec<u8> {
963✔
249
    make_contract_publish_tx(
963✔
250
        sender,
963✔
251
        nonce,
963✔
252
        tx_fee,
963✔
253
        chain_id,
963✔
254
        contract_name,
963✔
255
        contract_content,
963✔
256
        version,
963✔
257
    )
963✔
258
    .serialize_to_vec()
963✔
259
}
963✔
260

261
pub fn make_contract_publish(
927✔
262
    sender: &StacksPrivateKey,
927✔
263
    nonce: u64,
927✔
264
    tx_fee: u64,
927✔
265
    chain_id: u32,
927✔
266
    contract_name: &str,
927✔
267
    contract_content: &str,
927✔
268
) -> Vec<u8> {
927✔
269
    make_contract_publish_versioned(
927✔
270
        sender,
927✔
271
        nonce,
927✔
272
        tx_fee,
927✔
273
        chain_id,
927✔
274
        contract_name,
927✔
275
        contract_content,
927✔
276
        None,
927✔
277
    )
278
}
927✔
279

280
pub fn make_contract_publish_microblock_only_versioned(
63✔
281
    sender: &StacksPrivateKey,
63✔
282
    nonce: u64,
63✔
283
    tx_fee: u64,
63✔
284
    chain_id: u32,
63✔
285
    contract_name: &str,
63✔
286
    contract_content: &str,
63✔
287
    version: Option<ClarityVersion>,
63✔
288
) -> Vec<u8> {
63✔
289
    let name = ContractName::try_from(contract_name).expect("invalid contract name");
63✔
290
    let code_body = StacksString::from_string(&contract_content.to_string()).unwrap();
63✔
291

292
    let payload =
63✔
293
        TransactionPayload::SmartContract(TransactionSmartContract { name, code_body }, version);
63✔
294

295
    let tx = sign_standard_single_sig_tx_anchor_mode(
63✔
296
        payload,
63✔
297
        sender,
63✔
298
        nonce,
63✔
299
        tx_fee,
63✔
300
        chain_id,
63✔
301
        TransactionAnchorMode::OffChainOnly,
63✔
302
    );
303
    let mut tx_bytes = vec![];
63✔
304
    tx.consensus_serialize(&mut tx_bytes).unwrap();
63✔
305
    tx_bytes
63✔
306
}
63✔
307

308
pub fn make_contract_publish_microblock_only(
63✔
309
    sender: &StacksPrivateKey,
63✔
310
    nonce: u64,
63✔
311
    tx_fee: u64,
63✔
312
    chain_id: u32,
63✔
313
    contract_name: &str,
63✔
314
    contract_content: &str,
63✔
315
) -> Vec<u8> {
63✔
316
    make_contract_publish_microblock_only_versioned(
63✔
317
        sender,
63✔
318
        nonce,
63✔
319
        tx_fee,
63✔
320
        chain_id,
63✔
321
        contract_name,
63✔
322
        contract_content,
63✔
323
        None,
63✔
324
    )
325
}
63✔
326

327
pub fn to_addr(sk: &StacksPrivateKey) -> StacksAddress {
13,192,965✔
328
    StacksAddress::p2pkh(false, &StacksPublicKey::from_private(sk))
13,192,965✔
329
}
13,192,965✔
330

331
pub fn make_stacks_transfer_tx(
12,670,444✔
332
    sender: &StacksPrivateKey,
12,670,444✔
333
    nonce: u64,
12,670,444✔
334
    tx_fee: u64,
12,670,444✔
335
    chain_id: u32,
12,670,444✔
336
    recipient: &PrincipalData,
12,670,444✔
337
    amount: u64,
12,670,444✔
338
) -> StacksTransaction {
12,670,444✔
339
    let payload =
12,670,444✔
340
        TransactionPayload::TokenTransfer(recipient.clone(), amount, TokenTransferMemo([0; 34]));
12,670,444✔
341
    sign_standard_single_sig_tx(payload, sender, nonce, tx_fee, chain_id)
12,670,444✔
342
}
12,670,444✔
343

344
/// Make a stacks transfer transaction, returning the serialized transaction bytes
345
pub fn make_stacks_transfer_serialized(
12,670,362✔
346
    sender: &StacksPrivateKey,
12,670,362✔
347
    nonce: u64,
12,670,362✔
348
    tx_fee: u64,
12,670,362✔
349
    chain_id: u32,
12,670,362✔
350
    recipient: &PrincipalData,
12,670,362✔
351
    amount: u64,
12,670,362✔
352
) -> Vec<u8> {
12,670,362✔
353
    let tx = make_stacks_transfer_tx(sender, nonce, tx_fee, chain_id, recipient, amount);
12,670,362✔
354
    let mut tx_bytes = vec![];
12,670,362✔
355
    tx.consensus_serialize(&mut tx_bytes).unwrap();
12,670,362✔
356
    tx_bytes
12,670,362✔
357
}
12,670,362✔
358

359
#[allow(clippy::too_many_arguments)]
360
pub fn make_sponsored_stacks_transfer_on_testnet(
×
361
    sender: &StacksPrivateKey,
×
362
    payer: &StacksPrivateKey,
×
363
    sender_nonce: u64,
×
364
    payer_nonce: u64,
×
365
    tx_fee: u64,
×
366
    chain_id: u32,
×
367
    recipient: &PrincipalData,
×
368
    amount: u64,
×
369
) -> Vec<u8> {
×
370
    let payload =
×
371
        TransactionPayload::TokenTransfer(recipient.clone(), amount, TokenTransferMemo([0; 34]));
×
372
    let tx = sign_sponsored_sig_tx_anchor_mode_version(
×
373
        payload,
×
374
        sender,
×
375
        payer,
×
376
        sender_nonce,
×
377
        payer_nonce,
×
378
        tx_fee,
×
379
        chain_id,
×
380
        TransactionAnchorMode::OnChainOnly,
×
381
        TransactionVersion::Testnet,
×
382
    );
383
    let mut tx_bytes = vec![];
×
384
    tx.consensus_serialize(&mut tx_bytes).unwrap();
×
385
    tx_bytes
×
386
}
×
387

388
pub fn make_stacks_transfer_mblock_only(
9✔
389
    sender: &StacksPrivateKey,
9✔
390
    nonce: u64,
9✔
391
    tx_fee: u64,
9✔
392
    chain_id: u32,
9✔
393
    recipient: &PrincipalData,
9✔
394
    amount: u64,
9✔
395
) -> Vec<u8> {
9✔
396
    let payload =
9✔
397
        TransactionPayload::TokenTransfer(recipient.clone(), amount, TokenTransferMemo([0; 34]));
9✔
398
    let tx = sign_standard_single_sig_tx_anchor_mode(
9✔
399
        payload,
9✔
400
        sender,
9✔
401
        nonce,
9✔
402
        tx_fee,
9✔
403
        chain_id,
9✔
404
        TransactionAnchorMode::OffChainOnly,
9✔
405
    );
406
    let mut tx_bytes = vec![];
9✔
407
    tx.consensus_serialize(&mut tx_bytes).unwrap();
9✔
408
    tx_bytes
9✔
409
}
9✔
410

411
pub fn make_poison(
×
412
    sender: &StacksPrivateKey,
×
413
    nonce: u64,
×
414
    tx_fee: u64,
×
415
    chain_id: u32,
×
416
    header_1: StacksMicroblockHeader,
×
417
    header_2: StacksMicroblockHeader,
×
418
) -> Vec<u8> {
×
419
    let payload = TransactionPayload::PoisonMicroblock(header_1, header_2);
×
420
    let tx = sign_standard_single_sig_tx(payload, sender, nonce, tx_fee, chain_id);
×
421
    let mut tx_bytes = vec![];
×
422
    tx.consensus_serialize(&mut tx_bytes).unwrap();
×
423
    tx_bytes
×
424
}
×
425

426
pub fn make_coinbase_tx(
×
427
    sender: &StacksPrivateKey,
×
428
    nonce: u64,
×
429
    tx_fee: u64,
×
430
    chain_id: u32,
×
431
) -> StacksTransaction {
×
432
    let payload = TransactionPayload::Coinbase(CoinbasePayload([0; 32]), None, None);
×
433
    let tx = sign_standard_single_sig_tx(payload, sender, nonce, tx_fee, chain_id);
×
434
    tx
×
435
}
×
436

437
pub fn make_coinbase(sender: &StacksPrivateKey, nonce: u64, tx_fee: u64, chain_id: u32) -> Vec<u8> {
×
438
    let tx = make_coinbase_tx(sender, nonce, tx_fee, chain_id);
×
439
    tx.serialize_to_vec()
×
440
}
×
441

442
#[allow(clippy::too_many_arguments)]
443
pub fn make_contract_call_tx(
14,832✔
444
    sender: &StacksPrivateKey,
14,832✔
445
    nonce: u64,
14,832✔
446
    tx_fee: u64,
14,832✔
447
    chain_id: u32,
14,832✔
448
    contract_addr: &StacksAddress,
14,832✔
449
    contract_name: ContractName,
14,832✔
450
    function_name: ClarityName,
14,832✔
451
    function_args: &[Value],
14,832✔
452
) -> StacksTransaction {
14,832✔
453
    let payload = TransactionContractCall {
14,832✔
454
        address: contract_addr.clone(),
14,832✔
455
        contract_name,
14,832✔
456
        function_name,
14,832✔
457
        function_args: function_args.to_vec(),
14,832✔
458
    };
14,832✔
459

460
    sign_standard_single_sig_tx(payload.into(), sender, nonce, tx_fee, chain_id)
14,832✔
461
}
14,832✔
462

463
#[allow(clippy::too_many_arguments)]
464
pub fn make_contract_call(
14,832✔
465
    sender: &StacksPrivateKey,
14,832✔
466
    nonce: u64,
14,832✔
467
    tx_fee: u64,
14,832✔
468
    chain_id: u32,
14,832✔
469
    contract_addr: &StacksAddress,
14,832✔
470
    contract_name: &str,
14,832✔
471
    function_name: &str,
14,832✔
472
    function_args: &[Value],
14,832✔
473
) -> Vec<u8> {
14,832✔
474
    make_contract_call_tx(
14,832✔
475
        sender,
14,832✔
476
        nonce,
14,832✔
477
        tx_fee,
14,832✔
478
        chain_id,
14,832✔
479
        contract_addr,
14,832✔
480
        contract_name.try_into().expect("invalid contract name"),
14,832✔
481
        function_name.try_into().expect("invalid function name"),
14,832✔
482
        function_args,
14,832✔
483
    )
14,832✔
484
    .serialize_to_vec()
14,832✔
485
}
14,832✔
486

487
#[allow(clippy::too_many_arguments)]
488
pub fn make_contract_call_mblock_only(
×
489
    sender: &StacksPrivateKey,
×
490
    nonce: u64,
×
491
    tx_fee: u64,
×
492
    chain_id: u32,
×
493
    contract_addr: &StacksAddress,
×
494
    contract_name: &'static str,
×
495
    function_name: &'static str,
×
496
    function_args: &[Value],
×
497
) -> Vec<u8> {
×
498
    let contract_name = ContractName::from_literal(contract_name);
×
499
    let function_name = ClarityName::from_literal(function_name);
×
500

501
    let payload = TransactionContractCall {
×
502
        address: contract_addr.clone(),
×
503
        contract_name,
×
504
        function_name,
×
505
        function_args: function_args.to_vec(),
×
506
    };
×
507

508
    let tx = sign_standard_single_sig_tx_anchor_mode(
×
509
        payload.into(),
×
510
        sender,
×
511
        nonce,
×
512
        tx_fee,
×
513
        chain_id,
×
514
        TransactionAnchorMode::OffChainOnly,
×
515
    );
516
    let mut tx_bytes = vec![];
×
517
    tx.consensus_serialize(&mut tx_bytes).unwrap();
×
518
    tx_bytes
×
519
}
×
520

521
pub fn make_microblock(
9✔
522
    privk: &StacksPrivateKey,
9✔
523
    chainstate: &mut StacksChainState,
9✔
524
    burn_dbconn: &dyn BurnStateDB,
9✔
525
    consensus_hash: ConsensusHash,
9✔
526
    block: StacksBlock,
9✔
527
    txs: Vec<StacksTransaction>,
9✔
528
) -> StacksMicroblock {
9✔
529
    let mut block_bytes = vec![];
9✔
530
    block.consensus_serialize(&mut block_bytes).unwrap();
9✔
531

532
    let mut microblock_builder = StacksMicroblockBuilder::new(
9✔
533
        block.block_hash(),
9✔
534
        consensus_hash,
9✔
535
        chainstate,
9✔
536
        burn_dbconn,
9✔
537
        BlockBuilderSettings::max_value(),
9✔
538
    )
539
    .unwrap();
9✔
540
    let mempool_txs: Vec<_> = txs
9✔
541
        .into_iter()
9✔
542
        .map(|tx| {
18✔
543
            // TODO: better fee estimation
544
            let mut tx_bytes = vec![];
18✔
545
            tx.consensus_serialize(&mut tx_bytes).unwrap();
18✔
546
            (tx, tx_bytes.len() as u64)
18✔
547
        })
18✔
548
        .collect();
9✔
549

550
    // NOTE: we intentionally do not check the block's microblock pubkey hash against the private
551
    // key, because we may need to test that microblocks get rejected due to bad signatures.
552
    microblock_builder
9✔
553
        .mine_next_microblock_from_txs(mempool_txs, privk)
9✔
554
        .unwrap()
9✔
555
}
9✔
556

557
pub fn insert_tx_in_mempool(
12,654,000✔
558
    db_tx: &rusqlite::Transaction,
12,654,000✔
559
    tx_hex: Vec<u8>,
12,654,000✔
560
    origin_addr: &StacksAddress,
12,654,000✔
561
    origin_nonce: u64,
12,654,000✔
562
    fee: u64,
12,654,000✔
563
    consensus_hash: &ConsensusHash,
12,654,000✔
564
    block_header_hash: &BlockHeaderHash,
12,654,000✔
565
    height: u64,
12,654,000✔
566
) {
12,654,000✔
567
    let sql = "INSERT OR REPLACE INTO mempool (
12,654,000✔
568
        txid,
12,654,000✔
569
        origin_address,
12,654,000✔
570
        origin_nonce,
12,654,000✔
571
        sponsor_address,
12,654,000✔
572
        sponsor_nonce,
12,654,000✔
573
        tx_fee,
12,654,000✔
574
        length,
12,654,000✔
575
        consensus_hash,
12,654,000✔
576
        block_header_hash,
12,654,000✔
577
        height,
12,654,000✔
578
        accept_time,
12,654,000✔
579
        tx,
12,654,000✔
580
        fee_rate)
12,654,000✔
581
        VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)";
12,654,000✔
582

583
    let origin_addr_str = origin_addr.to_string();
12,654,000✔
584
    let length = tx_hex.len() as u64;
12,654,000✔
585
    let fee_rate = fee / length * 30;
12,654,000✔
586

587
    let txid = {
12,654,000✔
588
        let mut cursor = Cursor::new(&tx_hex);
12,654,000✔
589
        StacksTransaction::consensus_deserialize(&mut cursor)
12,654,000✔
590
            .expect("Failed to deserialize transaction")
12,654,000✔
591
            .txid()
12,654,000✔
592
    };
593
    let args = rusqlite::params![
12,654,000✔
594
        txid,
595
        origin_addr_str,
596
        origin_nonce,
597
        origin_addr_str,
598
        origin_nonce,
599
        fee,
600
        length,
601
        consensus_hash,
602
        block_header_hash,
603
        height,
604
        Utc::now().timestamp(),
12,654,000✔
605
        tx_hex,
606
        fee_rate
607
    ];
608
    db_tx
12,654,000✔
609
        .execute(sql, args)
12,654,000✔
610
        .expect("Failed to insert transaction into mempool");
12,654,000✔
611
}
12,654,000✔
612

613
/// Generate source code for a contract that exposes a public function
614
/// `big-tx`. This function uses `proportion` of read_count when called
615
pub fn make_big_read_count_contract(limit: ExecutionCost, proportion: u64) -> String {
63✔
616
    let read_count = (limit.read_count * proportion) / 100;
63✔
617

618
    let read_lines = (0..read_count)
63✔
619
        .map(|_| format!("(var-get my-var)"))
918,000✔
620
        .collect::<Vec<_>>()
63✔
621
        .join("\n");
63✔
622

623
    format!(
63✔
624
        "
625
(define-data-var my-var uint u0)
626
(define-public (big-tx)
627
(begin
628
{}
629
(ok true)))
630
        ",
631
        read_lines
632
    )
633
}
63✔
634

635
/// Make a tenure change transaction
636
pub fn make_tenure_change_tx(
45✔
637
    sender: &StacksPrivateKey,
45✔
638
    nonce: u64,
45✔
639
    tx_fee: u64,
45✔
640
    chain_id: u32,
45✔
641
    tc_payload: TenureChangePayload,
45✔
642
) -> StacksTransaction {
45✔
643
    sign_standard_single_sig_tx(
45✔
644
        TransactionPayload::TenureChange(tc_payload),
45✔
645
        sender,
45✔
646
        nonce,
45✔
647
        tx_fee,
45✔
648
        chain_id,
45✔
649
    )
650
}
45✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc