@@ -298,33 +298,53 @@ fn create_wallet(chain_config: Arc<ChainConfig>) -> DefaultWallet {
298298}
299299
300300#[ track_caller]
301- fn create_block < B , P > (
301+ fn create_block_with_reward_address < B , P > (
302302 chain_config : & Arc < ChainConfig > ,
303303 wallet : & mut Wallet < B , P > ,
304304 transactions : Vec < SignedTransaction > ,
305305 reward : Amount ,
306306 block_height : u64 ,
307- ) -> ( Address < Destination > , Block )
307+ address : Destination ,
308+ ) -> Block
308309where
309310 B : storage:: Backend + ' static ,
310311 P : SignerProvider ,
311312{
312- let address = wallet. get_new_address ( DEFAULT_ACCOUNT_INDEX ) . unwrap ( ) . 1 ;
313-
314313 let block1 = Block :: new (
315314 transactions,
316315 chain_config. genesis_block_id ( ) ,
317316 chain_config. genesis_block ( ) . timestamp ( ) ,
318317 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) ] ) ,
323319 )
324320 . unwrap ( ) ;
325321
326322 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)
328348}
329349
330350#[ track_caller]
@@ -1251,6 +1271,146 @@ fn locked_wallet_cant_sign_transaction(#[case] seed: Seed) {
12511271 . unwrap ( ) ;
12521272 }
12531273}
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+
12541414#[ rstest]
12551415#[ trace]
12561416#[ case( Seed :: from_entropy( ) ) ]
@@ -5320,59 +5480,6 @@ fn test_not_exhaustion_of_keys(#[case] seed: Seed) {
53205480 }
53215481}
53225482
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-
53765483#[ rstest]
53775484#[ trace]
53785485#[ case( Seed :: from_entropy( ) ) ]
0 commit comments