@@ -25,6 +25,7 @@ use common::{
25
25
chain:: {
26
26
output_value:: OutputValue ,
27
27
signature:: inputsig:: { standard_signature:: StandardInputSignature , InputWitness } ,
28
+ timelock:: OutputTimeLock ,
28
29
tokens:: {
29
30
make_token_id, TokenId , TokenIssuance , TokenIssuanceV1 , TokenIssuanceVersion ,
30
31
TokenTotalSupply ,
@@ -3138,3 +3139,117 @@ fn check_signature_on_lock_supply(#[case] seed: Seed) {
3138
3139
tf. make_block_builder ( ) . add_transaction ( tx) . build_and_process ( ) . unwrap ( ) ;
3139
3140
} ) ;
3140
3141
}
3142
+
3143
+ // Issue a token and mint some with locked outputs for 2 blocks.
3144
+ // Try transfer tokens in the next block and check it's the timelock error.
3145
+ // Produce a block.
3146
+ // Transfer tokens and check that now it's ok.
3147
+ #[ rstest]
3148
+ #[ trace]
3149
+ #[ case( Seed :: from_entropy( ) ) ]
3150
+ fn mint_with_timelock ( #[ case] seed : Seed ) {
3151
+ utils:: concurrency:: model ( move || {
3152
+ let mut rng = make_seedable_rng ( seed) ;
3153
+ let mut tf = make_test_framework_with_v1 ( & mut rng) ;
3154
+
3155
+ let token_min_supply_change_fee =
3156
+ tf. chainstate . get_chain_config ( ) . token_min_supply_change_fee ( ) ;
3157
+
3158
+ let amount_to_mint =
3159
+ Amount :: from_atoms ( rng. gen_range ( 2 ..SignedAmount :: MAX . into_atoms ( ) as u128 ) ) ;
3160
+ let ( token_id, _, utxo_with_change) =
3161
+ issue_token_from_genesis ( & mut rng, & mut tf, TokenTotalSupply :: Lockable ) ;
3162
+
3163
+ // Mint with locked output
3164
+ let mint_tx = TransactionBuilder :: new ( )
3165
+ . add_input (
3166
+ TxInput :: from_account (
3167
+ AccountNonce :: new ( 0 ) ,
3168
+ AccountOp :: MintTokens ( token_id, amount_to_mint) ,
3169
+ ) ,
3170
+ InputWitness :: NoSignature ( None ) ,
3171
+ )
3172
+ . add_input (
3173
+ utxo_with_change. clone ( ) . into ( ) ,
3174
+ InputWitness :: NoSignature ( None ) ,
3175
+ )
3176
+ . add_output ( TxOutput :: LockThenTransfer (
3177
+ OutputValue :: TokenV1 ( token_id, amount_to_mint) ,
3178
+ Destination :: AnyoneCanSpend ,
3179
+ OutputTimeLock :: ForBlockCount ( 2 ) ,
3180
+ ) )
3181
+ . add_output ( TxOutput :: Burn ( OutputValue :: Coin (
3182
+ token_min_supply_change_fee,
3183
+ ) ) )
3184
+ . add_output ( TxOutput :: Transfer (
3185
+ OutputValue :: Coin ( token_min_supply_change_fee) ,
3186
+ Destination :: AnyoneCanSpend ,
3187
+ ) )
3188
+ . build ( ) ;
3189
+ let mint_tx_id = mint_tx. transaction ( ) . get_id ( ) ;
3190
+ tf. make_block_builder ( ) . add_transaction ( mint_tx) . build_and_process ( ) . unwrap ( ) ;
3191
+
3192
+ let actual_supply =
3193
+ TokensAccountingStorageRead :: get_circulating_supply ( & tf. storage , & token_id) . unwrap ( ) ;
3194
+ assert_eq ! ( actual_supply, Some ( amount_to_mint) ) ;
3195
+
3196
+ // Try spend tokens at once
3197
+ let token_mint_outpoint = UtxoOutPoint :: new ( mint_tx_id. into ( ) , 0 ) ;
3198
+ let result = tf
3199
+ . make_block_builder ( )
3200
+ . add_transaction (
3201
+ TransactionBuilder :: new ( )
3202
+ . add_input (
3203
+ TxInput :: Utxo ( token_mint_outpoint. clone ( ) ) ,
3204
+ InputWitness :: NoSignature ( None ) ,
3205
+ )
3206
+ . add_output ( TxOutput :: Transfer (
3207
+ OutputValue :: TokenV1 ( token_id, amount_to_mint) ,
3208
+ Destination :: AnyoneCanSpend ,
3209
+ ) )
3210
+ . build ( ) ,
3211
+ )
3212
+ . build_and_process ( ) ;
3213
+
3214
+ assert_eq ! (
3215
+ result. unwrap_err( ) ,
3216
+ ChainstateError :: ProcessBlockError ( BlockError :: StateUpdateFailed (
3217
+ ConnectTransactionError :: TimeLockViolation ( token_mint_outpoint. clone( ) ) ,
3218
+ ) )
3219
+ ) ;
3220
+
3221
+ // Produce 1 more block to get past timelock
3222
+ tf. make_block_builder ( )
3223
+ . add_transaction (
3224
+ TransactionBuilder :: new ( )
3225
+ . add_input (
3226
+ TxInput :: from_utxo ( mint_tx_id. into ( ) , 2 ) ,
3227
+ InputWitness :: NoSignature ( None ) ,
3228
+ )
3229
+ . add_output ( TxOutput :: Transfer (
3230
+ OutputValue :: Coin ( token_min_supply_change_fee) ,
3231
+ Destination :: AnyoneCanSpend ,
3232
+ ) )
3233
+ . build ( ) ,
3234
+ )
3235
+ . build_and_process ( )
3236
+ . unwrap ( ) ;
3237
+
3238
+ // Spend again, now timelock should pass
3239
+ tf. make_block_builder ( )
3240
+ . add_transaction (
3241
+ TransactionBuilder :: new ( )
3242
+ . add_input (
3243
+ TxInput :: Utxo ( token_mint_outpoint. clone ( ) ) ,
3244
+ InputWitness :: NoSignature ( None ) ,
3245
+ )
3246
+ . add_output ( TxOutput :: Transfer (
3247
+ OutputValue :: TokenV1 ( token_id, amount_to_mint) ,
3248
+ Destination :: AnyoneCanSpend ,
3249
+ ) )
3250
+ . build ( ) ,
3251
+ )
3252
+ . build_and_process ( )
3253
+ . unwrap ( ) ;
3254
+ } ) ;
3255
+ }
0 commit comments