@@ -298,33 +298,53 @@ fn create_wallet(chain_config: Arc<ChainConfig>) -> DefaultWallet {
298
298
}
299
299
300
300
#[ track_caller]
301
- fn create_block < B , P > (
301
+ fn create_block_with_reward_address < B , P > (
302
302
chain_config : & Arc < ChainConfig > ,
303
303
wallet : & mut Wallet < B , P > ,
304
304
transactions : Vec < SignedTransaction > ,
305
305
reward : Amount ,
306
306
block_height : u64 ,
307
- ) -> ( Address < Destination > , Block )
307
+ address : Destination ,
308
+ ) -> Block
308
309
where
309
310
B : storage:: Backend + ' static ,
310
311
P : SignerProvider ,
311
312
{
312
- let address = wallet. get_new_address ( DEFAULT_ACCOUNT_INDEX ) . unwrap ( ) . 1 ;
313
-
314
313
let block1 = Block :: new (
315
314
transactions,
316
315
chain_config. genesis_block_id ( ) ,
317
316
chain_config. genesis_block ( ) . timestamp ( ) ,
318
317
ConsensusData :: None ,
319
- BlockReward :: new ( vec ! [ make_address_output(
320
- address. clone( ) . into_object( ) ,
321
- reward,
322
- ) ] ) ,
318
+ BlockReward :: new ( vec ! [ make_address_output( address, reward) ] ) ,
323
319
)
324
320
. unwrap ( ) ;
325
321
326
322
scan_wallet ( wallet, BlockHeight :: new ( block_height) , vec ! [ block1. clone( ) ] ) ;
327
- ( address, block1)
323
+ block1
324
+ }
325
+
326
+ #[ track_caller]
327
+ fn create_block < B , P > (
328
+ chain_config : & Arc < ChainConfig > ,
329
+ wallet : & mut Wallet < B , P > ,
330
+ transactions : Vec < SignedTransaction > ,
331
+ reward : Amount ,
332
+ block_height : u64 ,
333
+ ) -> ( Address < Destination > , Block )
334
+ where
335
+ B : storage:: Backend + ' static ,
336
+ P : SignerProvider ,
337
+ {
338
+ let address = wallet. get_new_address ( DEFAULT_ACCOUNT_INDEX ) . unwrap ( ) . 1 ;
339
+ let block = create_block_with_reward_address (
340
+ chain_config,
341
+ wallet,
342
+ transactions,
343
+ reward,
344
+ block_height,
345
+ address. clone ( ) . into_object ( ) ,
346
+ ) ;
347
+ ( address, block)
328
348
}
329
349
330
350
#[ track_caller]
@@ -1251,6 +1271,146 @@ fn locked_wallet_cant_sign_transaction(#[case] seed: Seed) {
1251
1271
. unwrap ( ) ;
1252
1272
}
1253
1273
}
1274
+
1275
+ #[ rstest]
1276
+ #[ trace]
1277
+ #[ case( Seed :: from_entropy( ) ) ]
1278
+ fn locked_wallet_standalone_keys (
1279
+ #[ case] seed : Seed ,
1280
+ #[ values( true , false ) ] insert_before_encrypt : bool ,
1281
+ #[ values( true , false ) ] change_password : bool ,
1282
+ ) {
1283
+ let mut rng = make_seedable_rng ( seed) ;
1284
+ let chain_config = Arc :: new ( create_mainnet ( ) ) ;
1285
+
1286
+ let mut wallet = create_wallet ( chain_config. clone ( ) ) ;
1287
+
1288
+ let coin_balance = get_coin_balance ( & wallet) ;
1289
+ assert_eq ! ( coin_balance, Amount :: ZERO ) ;
1290
+
1291
+ let ( standalone_sk, standalone_pk) =
1292
+ PrivateKey :: new_from_rng ( & mut rng, KeyKind :: Secp256k1Schnorr ) ;
1293
+ let mut password = Some ( gen_random_password ( & mut rng) ) ;
1294
+
1295
+ if insert_before_encrypt {
1296
+ wallet
1297
+ . add_standalone_private_key ( DEFAULT_ACCOUNT_INDEX , standalone_sk, None )
1298
+ . unwrap ( ) ;
1299
+ wallet. encrypt_wallet ( & password) . unwrap ( ) ;
1300
+ } else {
1301
+ wallet. encrypt_wallet ( & password) . unwrap ( ) ;
1302
+ wallet
1303
+ . add_standalone_private_key ( DEFAULT_ACCOUNT_INDEX , standalone_sk, None )
1304
+ . unwrap ( ) ;
1305
+ }
1306
+
1307
+ if change_password {
1308
+ password = Some ( gen_random_password ( & mut rng) ) ;
1309
+ wallet. encrypt_wallet ( & password) . unwrap ( ) ;
1310
+ }
1311
+
1312
+ let block1_amount = Amount :: from_atoms ( rng. gen_range ( NETWORK_FEE + 1 ..NETWORK_FEE + 10000 ) ) ;
1313
+
1314
+ let standalone_destination = if rng. gen :: < bool > ( ) {
1315
+ Destination :: PublicKey ( standalone_pk)
1316
+ } else {
1317
+ Destination :: PublicKeyHash ( ( & standalone_pk) . into ( ) )
1318
+ } ;
1319
+
1320
+ if rng. gen :: < bool > ( ) {
1321
+ // test that wallet will recognise a destination belonging to a standalone key in a block
1322
+ // reward
1323
+ let _ = create_block_with_reward_address (
1324
+ & chain_config,
1325
+ & mut wallet,
1326
+ vec ! [ ] ,
1327
+ block1_amount,
1328
+ 0 ,
1329
+ standalone_destination,
1330
+ ) ;
1331
+ } else {
1332
+ // test that wallet will recognise a destination belonging to a standalone key in a
1333
+ // transaction
1334
+ let output = make_address_output ( standalone_destination, block1_amount) ;
1335
+
1336
+ let tx = SignedTransaction :: new ( Transaction :: new ( 0 , vec ! [ ] , vec ! [ output] ) . unwrap ( ) , vec ! [ ] )
1337
+ . unwrap ( ) ;
1338
+
1339
+ let block1 = Block :: new (
1340
+ vec ! [ tx. clone( ) ] ,
1341
+ chain_config. genesis_block_id ( ) ,
1342
+ chain_config. genesis_block ( ) . timestamp ( ) ,
1343
+ ConsensusData :: None ,
1344
+ BlockReward :: new ( vec ! [ ] ) ,
1345
+ )
1346
+ . unwrap ( ) ;
1347
+
1348
+ scan_wallet ( & mut wallet, BlockHeight :: new ( 0 ) , vec ! [ block1. clone( ) ] ) ;
1349
+
1350
+ // check the transaction has been added to the wallet
1351
+ let tx_data = wallet
1352
+ . get_transaction ( DEFAULT_ACCOUNT_INDEX , tx. transaction ( ) . get_id ( ) )
1353
+ . unwrap ( ) ;
1354
+
1355
+ assert_eq ! ( tx_data. get_transaction( ) , tx. transaction( ) ) ;
1356
+ }
1357
+
1358
+ wallet. lock_wallet ( ) . unwrap ( ) ;
1359
+
1360
+ // check balance is recognising spendable UTXOs belonging to the standalone private key
1361
+ let coin_balance = get_coin_balance ( & wallet) ;
1362
+ assert_eq ! ( coin_balance, block1_amount) ;
1363
+
1364
+ // also check utxos
1365
+ let utxos = wallet
1366
+ . get_utxos (
1367
+ DEFAULT_ACCOUNT_INDEX ,
1368
+ UtxoType :: Transfer | UtxoType :: LockThenTransfer | UtxoType :: IssueNft ,
1369
+ UtxoState :: Confirmed | UtxoState :: Inactive ,
1370
+ WithLocked :: Unlocked ,
1371
+ )
1372
+ . unwrap ( ) ;
1373
+ assert_eq ! ( utxos. len( ) , 1 ) ;
1374
+
1375
+ // try to spend the UTXO belonging to the standalone key
1376
+
1377
+ let new_output = TxOutput :: Transfer (
1378
+ OutputValue :: Coin ( Amount :: from_atoms (
1379
+ rng. gen_range ( 1 ..=block1_amount. into_atoms ( ) - NETWORK_FEE ) ,
1380
+ ) ) ,
1381
+ Destination :: AnyoneCanSpend ,
1382
+ ) ;
1383
+
1384
+ assert_eq ! (
1385
+ wallet. create_transaction_to_addresses(
1386
+ DEFAULT_ACCOUNT_INDEX ,
1387
+ [ new_output. clone( ) ] ,
1388
+ SelectedInputs :: Utxos ( vec![ ] ) ,
1389
+ BTreeMap :: new( ) ,
1390
+ FeeRate :: from_amount_per_kb( Amount :: ZERO ) ,
1391
+ FeeRate :: from_amount_per_kb( Amount :: ZERO ) ,
1392
+ TxAdditionalInfo :: new( ) ,
1393
+ ) ,
1394
+ Err ( WalletError :: DatabaseError (
1395
+ wallet_storage:: Error :: WalletLocked
1396
+ ) )
1397
+ ) ;
1398
+
1399
+ // success after unlock
1400
+ wallet. unlock_wallet ( & password. unwrap ( ) ) . unwrap ( ) ;
1401
+ wallet
1402
+ . create_transaction_to_addresses (
1403
+ DEFAULT_ACCOUNT_INDEX ,
1404
+ [ new_output] ,
1405
+ SelectedInputs :: Utxos ( vec ! [ ] ) ,
1406
+ BTreeMap :: new ( ) ,
1407
+ FeeRate :: from_amount_per_kb ( Amount :: ZERO ) ,
1408
+ FeeRate :: from_amount_per_kb ( Amount :: ZERO ) ,
1409
+ TxAdditionalInfo :: new ( ) ,
1410
+ )
1411
+ . unwrap ( ) ;
1412
+ }
1413
+
1254
1414
#[ rstest]
1255
1415
#[ trace]
1256
1416
#[ case( Seed :: from_entropy( ) ) ]
@@ -5320,59 +5480,6 @@ fn test_not_exhaustion_of_keys(#[case] seed: Seed) {
5320
5480
}
5321
5481
}
5322
5482
5323
- #[ rstest]
5324
- #[ trace]
5325
- #[ case( Seed :: from_entropy( ) ) ]
5326
- fn test_add_standalone_private_key ( #[ case] seed : Seed ) {
5327
- let mut rng = make_seedable_rng ( seed) ;
5328
- let chain_config = Arc :: new ( create_regtest ( ) ) ;
5329
-
5330
- let mut wallet = create_wallet ( chain_config. clone ( ) ) ;
5331
-
5332
- let coin_balance = get_coin_balance ( & wallet) ;
5333
- assert_eq ! ( coin_balance, Amount :: ZERO ) ;
5334
- // generate a random private key unrelated to the wallet and add it
5335
- let ( private_key, pub_key) =
5336
- crypto:: key:: PrivateKey :: new_from_rng ( & mut rng, KeyKind :: Secp256k1Schnorr ) ;
5337
-
5338
- wallet
5339
- . add_standalone_private_key ( DEFAULT_ACCOUNT_INDEX , private_key, None )
5340
- . unwrap ( ) ;
5341
-
5342
- // get the destination address from the new private key and send some coins to it
5343
- let address =
5344
- Address :: new ( & chain_config, Destination :: PublicKeyHash ( ( & pub_key) . into ( ) ) ) . unwrap ( ) ;
5345
-
5346
- // Generate a new block which sends reward to the new address
5347
- let block1_amount = Amount :: from_atoms ( rng. gen_range ( NETWORK_FEE + 100 ..NETWORK_FEE + 10000 ) ) ;
5348
- let output = make_address_output ( address. clone ( ) . into_object ( ) , block1_amount) ;
5349
-
5350
- let tx =
5351
- SignedTransaction :: new ( Transaction :: new ( 0 , vec ! [ ] , vec ! [ output] ) . unwrap ( ) , vec ! [ ] ) . unwrap ( ) ;
5352
-
5353
- let block1 = Block :: new (
5354
- vec ! [ tx. clone( ) ] ,
5355
- chain_config. genesis_block_id ( ) ,
5356
- chain_config. genesis_block ( ) . timestamp ( ) ,
5357
- ConsensusData :: None ,
5358
- BlockReward :: new ( vec ! [ ] ) ,
5359
- )
5360
- . unwrap ( ) ;
5361
-
5362
- scan_wallet ( & mut wallet, BlockHeight :: new ( 0 ) , vec ! [ block1. clone( ) ] ) ;
5363
-
5364
- // Check amount is still zero
5365
- let coin_balance = get_coin_balance ( & wallet) ;
5366
- assert_eq ! ( coin_balance, Amount :: ZERO ) ;
5367
-
5368
- // but the transaction has been added to the wallet
5369
- let tx_data = wallet
5370
- . get_transaction ( DEFAULT_ACCOUNT_INDEX , tx. transaction ( ) . get_id ( ) )
5371
- . unwrap ( ) ;
5372
-
5373
- assert_eq ! ( tx_data. get_transaction( ) , tx. transaction( ) ) ;
5374
- }
5375
-
5376
5483
#[ rstest]
5377
5484
#[ trace]
5378
5485
#[ case( Seed :: from_entropy( ) ) ]
0 commit comments