@@ -1350,9 +1350,9 @@ fn mint_unlimited_supply(#[case] seed: Seed) {
13501350 } ) ;
13511351}
13521352
1353- // Issue and mint maximum possible tokens for Unlimited supply.
1354- // Try to mint 1 more and check an error.
1355- // Try to mint random number and check an error.
1353+ // Issue and mint maximum possible tokens (i128::MAX) for Unlimited supply.
1354+ // Try to mint 1 more and expect an error.
1355+ // Try to mint random number and expect an error.
13561356#[ rstest]
13571357#[ trace]
13581358#[ case( Seed :: from_entropy( ) ) ]
@@ -1373,8 +1373,8 @@ fn mint_unlimited_supply_max(#[case] seed: Seed) {
13731373 IsTokenFreezable :: No ,
13741374 ) ;
13751375
1376- // Mint tokens i128::MAX
1377- let mint_tx = TransactionBuilder :: new ( )
1376+ // Mint i128::MAX atoms
1377+ let initial_mint_tx = TransactionBuilder :: new ( )
13781378 . add_input (
13791379 TxInput :: from_command (
13801380 AccountNonce :: new ( 0 ) ,
@@ -1395,9 +1395,9 @@ fn mint_unlimited_supply_max(#[case] seed: Seed) {
13951395 Destination :: AnyoneCanSpend ,
13961396 ) )
13971397 . build ( ) ;
1398- let mint_tx_id = mint_tx . transaction ( ) . get_id ( ) ;
1398+ let initial_mint_tx_id = initial_mint_tx . transaction ( ) . get_id ( ) ;
13991399 tf. make_block_builder ( )
1400- . add_transaction ( mint_tx )
1400+ . add_transaction ( initial_mint_tx )
14011401 . build_and_process ( & mut rng)
14021402 . unwrap ( ) ;
14031403
@@ -1416,25 +1416,29 @@ fn mint_unlimited_supply_max(#[case] seed: Seed) {
14161416 true ,
14171417 ) ;
14181418
1419- {
1420- // Try mint one more over i128::MAX
1421- let mint_tx = TransactionBuilder :: new ( )
1419+ let make_mint_tx = |amount| {
1420+ TransactionBuilder :: new ( )
14221421 . add_input (
14231422 TxInput :: from_command (
14241423 AccountNonce :: new ( 1 ) ,
1425- AccountCommand :: MintTokens ( token_id, Amount :: from_atoms ( 1 ) ) ,
1424+ AccountCommand :: MintTokens ( token_id, amount ) ,
14261425 ) ,
14271426 InputWitness :: NoSignature ( None ) ,
14281427 )
14291428 . add_input (
1430- TxInput :: from_utxo ( mint_tx_id . into ( ) , 0 ) ,
1429+ TxInput :: from_utxo ( initial_mint_tx_id . into ( ) , 0 ) ,
14311430 InputWitness :: NoSignature ( None ) ,
14321431 )
14331432 . add_output ( TxOutput :: Transfer (
1434- OutputValue :: TokenV1 ( token_id, Amount :: from_atoms ( 1 ) ) ,
1433+ OutputValue :: TokenV1 ( token_id, amount ) ,
14351434 Destination :: AnyoneCanSpend ,
14361435 ) )
1437- . build ( ) ;
1436+ . build ( )
1437+ } ;
1438+
1439+ {
1440+ // Try minting one more atom.
1441+ let mint_tx = make_mint_tx ( Amount :: from_atoms ( 1 ) ) ;
14381442 let mint_tx_id = mint_tx. transaction ( ) . get_id ( ) ;
14391443 let result =
14401444 tf. make_block_builder ( ) . add_transaction ( mint_tx) . build_and_process ( & mut rng) ;
@@ -1454,41 +1458,256 @@ fn mint_unlimited_supply_max(#[case] seed: Seed) {
14541458 ) ;
14551459 }
14561460
1457- // Try mint random number over i128::MAX
1458- let random_amount = Amount :: from_atoms ( rng. gen_range ( 0 ..i128:: MAX as u128 ) ) ;
1459- let mint_tx = TransactionBuilder :: new ( )
1461+ {
1462+ // Try minting a random number of atoms
1463+ let amount = Amount :: from_atoms ( rng. gen_range ( 1 ..=i128:: MAX as u128 ) ) ;
1464+ let mint_tx = make_mint_tx ( amount) ;
1465+ let mint_tx_id = mint_tx. transaction ( ) . get_id ( ) ;
1466+ let result =
1467+ tf. make_block_builder ( ) . add_transaction ( mint_tx) . build_and_process ( & mut rng) ;
1468+
1469+ assert_eq ! (
1470+ result. unwrap_err( ) ,
1471+ ChainstateError :: ProcessBlockError ( BlockError :: StateUpdateFailed (
1472+ ConnectTransactionError :: ConstrainedValueAccumulatorError (
1473+ constraints_value_accumulator:: Error :: TokensAccountingError (
1474+ tokens_accounting:: Error :: AccountingError (
1475+ accounting:: Error :: ArithmeticErrorDeltaAdditionFailed
1476+ )
1477+ ) ,
1478+ mint_tx_id. into( )
1479+ )
1480+ ) )
1481+ ) ;
1482+ }
1483+
1484+ {
1485+ // For completeness, try minting a random number of atoms bigger than i128::MAX.
1486+ // A different error will be generated.
1487+ let amount = Amount :: from_atoms ( rng. gen_range ( ( i128:: MAX as u128 ) + 1 ..=u128:: MAX ) ) ;
1488+ let mint_tx = make_mint_tx ( amount) ;
1489+ let mint_tx_id = mint_tx. transaction ( ) . get_id ( ) ;
1490+ let result =
1491+ tf. make_block_builder ( ) . add_transaction ( mint_tx) . build_and_process ( & mut rng) ;
1492+
1493+ assert_eq ! (
1494+ result. unwrap_err( ) ,
1495+ ChainstateError :: ProcessBlockError ( BlockError :: StateUpdateFailed (
1496+ ConnectTransactionError :: ConstrainedValueAccumulatorError (
1497+ constraints_value_accumulator:: Error :: TokensAccountingError (
1498+ tokens_accounting:: Error :: AccountingError (
1499+ accounting:: Error :: ArithmeticErrorToSignedFailed
1500+ )
1501+ ) ,
1502+ mint_tx_id. into( )
1503+ )
1504+ ) )
1505+ ) ;
1506+ }
1507+ } ) ;
1508+ }
1509+
1510+ // Same as mint_unlimited_supply_max, but use TokenTotalSupply::Fixed with an amount bigger than i128::MAX.
1511+ // 1) mint maximum possible tokens (i128::MAX);
1512+ // 2) try minting 1 more and expect an error;
1513+ // 3) try minting a random amount and expect an error.
1514+ #[ rstest]
1515+ #[ trace]
1516+ #[ case( Seed :: from_entropy( ) ) ]
1517+ fn mint_pseudo_unlimited_supply_max ( #[ case] seed : Seed ) {
1518+ utils:: concurrency:: model ( move || {
1519+ let mut rng = make_seedable_rng ( seed) ;
1520+ let mut tf = TestFramework :: builder ( & mut rng) . build ( ) ;
1521+
1522+ let token_supply_change_fee =
1523+ tf. chainstate . get_chain_config ( ) . token_supply_change_fee ( BlockHeight :: zero ( ) ) ;
1524+
1525+ let max_amount_to_mint = Amount :: from_atoms ( i128:: MAX as u128 ) ;
1526+ let total_supply_atoms = if rng. gen_bool ( 0.5 ) {
1527+ u128:: MAX
1528+ } else {
1529+ rng. gen_range ( ( i128:: MAX as u128 ) + 1 ..u128:: MAX )
1530+ } ;
1531+ let total_supply_atoms_above_i128_max = total_supply_atoms - i128:: MAX as u128 ;
1532+ assert ! ( total_supply_atoms_above_i128_max > 0 ) ;
1533+
1534+ let ( token_id, issuance_block_id, issuance_tx, issuance, utxo_with_change) =
1535+ issue_token_from_genesis (
1536+ & mut rng,
1537+ & mut tf,
1538+ TokenTotalSupply :: Fixed ( Amount :: from_atoms ( total_supply_atoms) ) ,
1539+ IsTokenFreezable :: No ,
1540+ ) ;
1541+
1542+ // Mint i128::MAX atoms
1543+ let initial_mint_tx = TransactionBuilder :: new ( )
14601544 . add_input (
14611545 TxInput :: from_command (
1462- AccountNonce :: new ( 1 ) ,
1463- AccountCommand :: MintTokens ( token_id, random_amount ) ,
1546+ AccountNonce :: new ( 0 ) ,
1547+ AccountCommand :: MintTokens ( token_id, max_amount_to_mint ) ,
14641548 ) ,
14651549 InputWitness :: NoSignature ( None ) ,
14661550 )
14671551 . add_input (
1468- TxInput :: from_utxo ( mint_tx_id . into ( ) , 0 ) ,
1552+ utxo_with_change . clone ( ) . into ( ) ,
14691553 InputWitness :: NoSignature ( None ) ,
14701554 )
14711555 . add_output ( TxOutput :: Transfer (
1472- OutputValue :: TokenV1 ( token_id, random_amount) ,
1556+ OutputValue :: Coin ( token_supply_change_fee) ,
1557+ Destination :: AnyoneCanSpend ,
1558+ ) )
1559+ . add_output ( TxOutput :: Transfer (
1560+ OutputValue :: TokenV1 ( token_id, max_amount_to_mint) ,
14731561 Destination :: AnyoneCanSpend ,
14741562 ) )
14751563 . build ( ) ;
1476- let mint_tx_id = mint_tx. transaction ( ) . get_id ( ) ;
1477- let result = tf. make_block_builder ( ) . add_transaction ( mint_tx) . build_and_process ( & mut rng) ;
1564+ let initial_mint_tx_id = initial_mint_tx. transaction ( ) . get_id ( ) ;
1565+ tf. make_block_builder ( )
1566+ . add_transaction ( initial_mint_tx)
1567+ . build_and_process ( & mut rng)
1568+ . unwrap ( ) ;
14781569
1479- assert_eq ! (
1480- result. unwrap_err( ) ,
1481- ChainstateError :: ProcessBlockError ( BlockError :: StateUpdateFailed (
1482- ConnectTransactionError :: ConstrainedValueAccumulatorError (
1483- constraints_value_accumulator:: Error :: TokensAccountingError (
1484- tokens_accounting:: Error :: AccountingError (
1485- accounting:: Error :: ArithmeticErrorDeltaAdditionFailed
1486- )
1570+ check_fungible_token (
1571+ & tf,
1572+ & mut rng,
1573+ & token_id,
1574+ & ExpectedFungibleTokenData {
1575+ issuance,
1576+ issuance_tx,
1577+ issuance_block_id,
1578+ circulating_supply : Some ( max_amount_to_mint) ,
1579+ is_locked : false ,
1580+ is_frozen : IsTokenFrozen :: No ( IsTokenFreezable :: No ) ,
1581+ } ,
1582+ true ,
1583+ ) ;
1584+
1585+ let make_mint_tx = |amount| {
1586+ TransactionBuilder :: new ( )
1587+ . add_input (
1588+ TxInput :: from_command (
1589+ AccountNonce :: new ( 1 ) ,
1590+ AccountCommand :: MintTokens ( token_id, amount) ,
14871591 ) ,
1488- mint_tx_id . into ( )
1592+ InputWitness :: NoSignature ( None ) ,
14891593 )
1490- ) )
1491- ) ;
1594+ . add_input (
1595+ TxInput :: from_utxo ( initial_mint_tx_id. into ( ) , 0 ) ,
1596+ InputWitness :: NoSignature ( None ) ,
1597+ )
1598+ . add_output ( TxOutput :: Transfer (
1599+ OutputValue :: TokenV1 ( token_id, amount) ,
1600+ Destination :: AnyoneCanSpend ,
1601+ ) )
1602+ . build ( )
1603+ } ;
1604+
1605+ {
1606+ // Try mint one more atom
1607+ let mint_tx = make_mint_tx ( Amount :: from_atoms ( 1 ) ) ;
1608+ let mint_tx_id = mint_tx. transaction ( ) . get_id ( ) ;
1609+ let result =
1610+ tf. make_block_builder ( ) . add_transaction ( mint_tx) . build_and_process ( & mut rng) ;
1611+
1612+ assert_eq ! (
1613+ result. unwrap_err( ) ,
1614+ ChainstateError :: ProcessBlockError ( BlockError :: StateUpdateFailed (
1615+ ConnectTransactionError :: ConstrainedValueAccumulatorError (
1616+ constraints_value_accumulator:: Error :: TokensAccountingError (
1617+ tokens_accounting:: Error :: AccountingError (
1618+ accounting:: Error :: ArithmeticErrorDeltaAdditionFailed
1619+ )
1620+ ) ,
1621+ mint_tx_id. into( )
1622+ )
1623+ ) )
1624+ ) ;
1625+ }
1626+
1627+ {
1628+ // Try minting a random number of atoms, so that the total is below the specified max supply.
1629+ let amount = Amount :: from_atoms ( rng. gen_range ( 1 ..=total_supply_atoms_above_i128_max) ) ;
1630+ let mint_tx = make_mint_tx ( amount) ;
1631+ let mint_tx_id = mint_tx. transaction ( ) . get_id ( ) ;
1632+ let result =
1633+ tf. make_block_builder ( ) . add_transaction ( mint_tx) . build_and_process ( & mut rng) ;
1634+
1635+ assert_eq ! (
1636+ result. unwrap_err( ) ,
1637+ ChainstateError :: ProcessBlockError ( BlockError :: StateUpdateFailed (
1638+ ConnectTransactionError :: ConstrainedValueAccumulatorError (
1639+ constraints_value_accumulator:: Error :: TokensAccountingError (
1640+ tokens_accounting:: Error :: AccountingError (
1641+ accounting:: Error :: ArithmeticErrorDeltaAdditionFailed
1642+ )
1643+ ) ,
1644+ mint_tx_id. into( )
1645+ )
1646+ ) )
1647+ ) ;
1648+ }
1649+
1650+ {
1651+ // For completeness, try minting a random number of atoms, so that the total is above
1652+ // the specified max supply. Different errors are expected in this case, depending
1653+ // on whether the total amount fits into u128.
1654+
1655+ let max_extra_amount_to_fit_into_u128 = u128:: MAX - total_supply_atoms;
1656+
1657+ if max_extra_amount_to_fit_into_u128 != 0 {
1658+ // The total amount fits into u128.
1659+
1660+ let amount = Amount :: from_atoms (
1661+ total_supply_atoms_above_i128_max
1662+ + rng. gen_range ( 1 ..=max_extra_amount_to_fit_into_u128) ,
1663+ ) ;
1664+ let mint_tx = make_mint_tx ( amount) ;
1665+ let mint_tx_id = mint_tx. transaction ( ) . get_id ( ) ;
1666+ let result =
1667+ tf. make_block_builder ( ) . add_transaction ( mint_tx) . build_and_process ( & mut rng) ;
1668+
1669+ assert_eq ! (
1670+ result. unwrap_err( ) ,
1671+ ChainstateError :: ProcessBlockError ( BlockError :: StateUpdateFailed (
1672+ ConnectTransactionError :: ConstrainedValueAccumulatorError (
1673+ constraints_value_accumulator:: Error :: TokensAccountingError (
1674+ tokens_accounting:: Error :: MintExceedsSupplyLimit (
1675+ amount,
1676+ Amount :: from_atoms( total_supply_atoms) ,
1677+ token_id
1678+ )
1679+ ) ,
1680+ mint_tx_id. into( )
1681+ )
1682+ ) )
1683+ ) ;
1684+ }
1685+
1686+ {
1687+ // The total amount doesn't fit into u128.
1688+
1689+ let amount = Amount :: from_atoms ( rng. gen_range (
1690+ total_supply_atoms_above_i128_max + max_extra_amount_to_fit_into_u128 + 1
1691+ ..=u128:: MAX ,
1692+ ) ) ;
1693+ let mint_tx = make_mint_tx ( amount) ;
1694+ let mint_tx_id = mint_tx. transaction ( ) . get_id ( ) ;
1695+ let result =
1696+ tf. make_block_builder ( ) . add_transaction ( mint_tx) . build_and_process ( & mut rng) ;
1697+
1698+ assert_eq ! (
1699+ result. unwrap_err( ) ,
1700+ ChainstateError :: ProcessBlockError ( BlockError :: StateUpdateFailed (
1701+ ConnectTransactionError :: ConstrainedValueAccumulatorError (
1702+ constraints_value_accumulator:: Error :: TokensAccountingError (
1703+ tokens_accounting:: Error :: AmountOverflow
1704+ ) ,
1705+ mint_tx_id. into( )
1706+ )
1707+ ) )
1708+ ) ;
1709+ }
1710+ }
14921711 } ) ;
14931712}
14941713
0 commit comments