Skip to content

Commit 9cce325

Browse files
authored
Merge pull request #5156 from stacks-network/test/tx-no-fees
Adds Test - Non standard transaction, but not invalid being anchored
2 parents 1c53156 + 9aacd5e commit 9cce325

File tree

1 file changed

+219
-0
lines changed

1 file changed

+219
-0
lines changed

stackslib/src/chainstate/stacks/tests/block_construction.rs

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,6 +1536,225 @@ fn test_build_anchored_blocks_skip_too_expensive() {
15361536
}
15371537
}
15381538

1539+
#[test]
1540+
fn test_build_anchored_blocks_mempool_fee_transaction_too_low() {
1541+
let privk = StacksPrivateKey::from_hex(
1542+
"42faca653724860da7a41bfcef7e6ba78db55146f6900de8cb2a9f760ffac70c01",
1543+
)
1544+
.unwrap();
1545+
let addr = StacksAddress::from_public_keys(
1546+
C32_ADDRESS_VERSION_TESTNET_SINGLESIG,
1547+
&AddressHashMode::SerializeP2PKH,
1548+
1,
1549+
&vec![StacksPublicKey::from_private(&privk)],
1550+
)
1551+
.unwrap();
1552+
1553+
let mut peer_config = TestPeerConfig::new(function_name!(), 2032, 2033);
1554+
peer_config.initial_balances = vec![(addr.to_account_principal(), 1000000000)];
1555+
let burnchain = peer_config.burnchain.clone();
1556+
1557+
let mut peer = TestPeer::new(peer_config);
1558+
1559+
let chainstate_path = peer.chainstate_path.clone();
1560+
1561+
let recipient_addr_str = "ST1RFD5Q2QPK3E0F08HG9XDX7SSC7CNRS0QR0SGEV";
1562+
let recipient = StacksAddress::from_string(recipient_addr_str).unwrap();
1563+
1564+
let tip =
1565+
SortitionDB::get_canonical_burn_chain_tip(&peer.sortdb.as_ref().unwrap().conn()).unwrap();
1566+
1567+
let (burn_ops, stacks_block, microblocks) = peer.make_tenure(
1568+
|ref mut miner,
1569+
ref mut sortdb,
1570+
ref mut chainstate,
1571+
vrf_proof,
1572+
ref parent_opt,
1573+
ref parent_microblock_header_opt| {
1574+
let parent_tip = match parent_opt {
1575+
None => StacksChainState::get_genesis_header_info(chainstate.db()).unwrap(),
1576+
Some(block) => {
1577+
let ic = sortdb.index_conn();
1578+
let snapshot = SortitionDB::get_block_snapshot_for_winning_stacks_block(
1579+
&ic,
1580+
&tip.sortition_id,
1581+
&block.block_hash(),
1582+
)
1583+
.unwrap()
1584+
.unwrap();
1585+
StacksChainState::get_anchored_block_header_info(
1586+
chainstate.db(),
1587+
&snapshot.consensus_hash,
1588+
&snapshot.winning_stacks_block_hash,
1589+
)
1590+
.unwrap()
1591+
.unwrap()
1592+
}
1593+
};
1594+
1595+
let parent_header_hash = parent_tip.anchored_header.block_hash();
1596+
let parent_consensus_hash = parent_tip.consensus_hash.clone();
1597+
1598+
let mut mempool = MemPoolDB::open_test(false, 0x80000000, &chainstate_path).unwrap();
1599+
1600+
let coinbase_tx = make_coinbase(miner, 0);
1601+
1602+
// Create a zero-fee transaction
1603+
let zero_fee_tx = make_user_stacks_transfer(
1604+
&privk,
1605+
0,
1606+
0, // Set fee to 0
1607+
&recipient.to_account_principal(),
1608+
1000,
1609+
);
1610+
1611+
let result = mempool.submit(
1612+
chainstate,
1613+
sortdb,
1614+
&parent_consensus_hash,
1615+
&parent_header_hash,
1616+
&zero_fee_tx,
1617+
None,
1618+
&ExecutionCost::max_value(),
1619+
&StacksEpochId::Epoch20,
1620+
);
1621+
1622+
match result {
1623+
Ok(_) => panic!("Expected FeeTooLow error but transaction was accepted"),
1624+
Err(e) => match e {
1625+
MemPoolRejection::FeeTooLow(actual, required) => {
1626+
assert_eq!(actual, 0);
1627+
assert_eq!(required, 180);
1628+
}
1629+
_ => panic!("Unexpected error: {:?}", e),
1630+
},
1631+
};
1632+
1633+
let anchored_block = StacksBlockBuilder::build_anchored_block(
1634+
chainstate,
1635+
&sortdb.index_handle_at_tip(),
1636+
&mut mempool,
1637+
&parent_tip,
1638+
tip.total_burn,
1639+
vrf_proof,
1640+
Hash160([0 as u8; 20]),
1641+
&coinbase_tx,
1642+
BlockBuilderSettings::max_value(),
1643+
None,
1644+
&burnchain,
1645+
)
1646+
.unwrap();
1647+
1648+
(anchored_block.0, vec![])
1649+
},
1650+
);
1651+
1652+
peer.next_burnchain_block(burn_ops.clone());
1653+
peer.process_stacks_epoch_at_tip(&stacks_block, &microblocks);
1654+
1655+
// Check that the block contains only coinbase transactions (coinbase)
1656+
assert_eq!(stacks_block.txs.len(), 1);
1657+
}
1658+
1659+
#[test]
1660+
fn test_build_anchored_blocks_zero_fee_transaction() {
1661+
let privk = StacksPrivateKey::from_hex(
1662+
"42faca653724860da7a41bfcef7e6ba78db55146f6900de8cb2a9f760ffac70c01",
1663+
)
1664+
.unwrap();
1665+
let addr = StacksAddress::from_public_keys(
1666+
C32_ADDRESS_VERSION_TESTNET_SINGLESIG,
1667+
&AddressHashMode::SerializeP2PKH,
1668+
1,
1669+
&vec![StacksPublicKey::from_private(&privk)],
1670+
)
1671+
.unwrap();
1672+
1673+
let mut peer_config = TestPeerConfig::new(function_name!(), 2032, 2033);
1674+
peer_config.initial_balances = vec![(addr.to_account_principal(), 1000000000)];
1675+
let burnchain = peer_config.burnchain.clone();
1676+
1677+
let mut peer = TestPeer::new(peer_config);
1678+
1679+
let chainstate_path = peer.chainstate_path.clone();
1680+
1681+
let recipient_addr_str = "ST1RFD5Q2QPK3E0F08HG9XDX7SSC7CNRS0QR0SGEV";
1682+
let recipient = StacksAddress::from_string(recipient_addr_str).unwrap();
1683+
1684+
let tip =
1685+
SortitionDB::get_canonical_burn_chain_tip(&peer.sortdb.as_ref().unwrap().conn()).unwrap();
1686+
1687+
let (burn_ops, stacks_block, microblocks) = peer.make_tenure(
1688+
|ref mut miner,
1689+
ref mut sortdb,
1690+
ref mut chainstate,
1691+
vrf_proof,
1692+
ref parent_opt,
1693+
ref parent_microblock_header_opt| {
1694+
let parent_tip = match parent_opt {
1695+
None => StacksChainState::get_genesis_header_info(chainstate.db()).unwrap(),
1696+
Some(block) => {
1697+
let ic = sortdb.index_conn();
1698+
let snapshot = SortitionDB::get_block_snapshot_for_winning_stacks_block(
1699+
&ic,
1700+
&tip.sortition_id,
1701+
&block.block_hash(),
1702+
)
1703+
.unwrap()
1704+
.unwrap();
1705+
StacksChainState::get_anchored_block_header_info(
1706+
chainstate.db(),
1707+
&snapshot.consensus_hash,
1708+
&snapshot.winning_stacks_block_hash,
1709+
)
1710+
.unwrap()
1711+
.unwrap()
1712+
}
1713+
};
1714+
1715+
let coinbase_tx = make_coinbase(miner, 0);
1716+
1717+
// Create a zero-fee transaction
1718+
let zero_fee_tx = make_user_stacks_transfer(
1719+
&privk,
1720+
0,
1721+
0, // Set fee to 0
1722+
&recipient.to_account_principal(),
1723+
1000,
1724+
);
1725+
1726+
let block_builder = StacksBlockBuilder::make_regtest_block_builder(
1727+
&burnchain,
1728+
&parent_tip,
1729+
vrf_proof,
1730+
tip.total_burn,
1731+
Hash160([0 as u8; 20]),
1732+
)
1733+
.unwrap();
1734+
1735+
let anchored_block = StacksBlockBuilder::make_anchored_block_from_txs(
1736+
block_builder,
1737+
chainstate,
1738+
&sortdb.index_handle_at_tip(),
1739+
vec![coinbase_tx, zero_fee_tx],
1740+
)
1741+
.unwrap();
1742+
1743+
(anchored_block.0, vec![])
1744+
},
1745+
);
1746+
1747+
peer.next_burnchain_block(burn_ops.clone());
1748+
peer.process_stacks_epoch_at_tip(&stacks_block, &microblocks);
1749+
1750+
// Check that the block contains 2 transactions (coinbase + zero-fee transaction)
1751+
assert_eq!(stacks_block.txs.len(), 2);
1752+
1753+
// Verify that the zero-fee transaction is in the block
1754+
let zero_fee_tx = &stacks_block.txs[1];
1755+
assert_eq!(zero_fee_tx.get_tx_fee(), 0);
1756+
}
1757+
15391758
#[test]
15401759
fn test_build_anchored_blocks_multiple_chaintips() {
15411760
let mut privks = vec![];

0 commit comments

Comments
 (0)