diff --git a/.drone.yml b/.drone.yml index 94e1b40be..9b748b43e 100644 --- a/.drone.yml +++ b/.drone.yml @@ -39,6 +39,14 @@ steps: - cd chain-tx-enclave/tx-validation && make clean && SGX_TEST=1 make - cd bin && ./tx-validation-app +trigger: + branch: + - master + - staging + - trying + event: + - push + --- kind: pipeline @@ -80,6 +88,6 @@ trigger: - push --- kind: signature -hmac: 21e4a81d9785eeaa92154bda9daa8cc6cda13169e459849e919b473e0e2be725 +hmac: bdc2684e182cf00ebf7a8a2e7971884e5ff9ee193d16398aec745bcd1260cf6f ... diff --git a/client-core/src/types/wallet_kind.rs b/client-core/src/types/wallet_kind.rs index 32ff2a89d..c932b4173 100644 --- a/client-core/src/types/wallet_kind.rs +++ b/client-core/src/types/wallet_kind.rs @@ -1,11 +1,12 @@ use client_common::{Error, ErrorKind, Result}; +use serde::{Deserialize, Serialize}; use std::str::FromStr; use unicase::eq_ascii; /// Wallet kinds /// Basic: default wallet /// HD: HD wallet /// Hardware: hardware based wallets -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)] pub enum WalletKind { /// Basic Wallet Basic, diff --git a/client-rpc/src/rpc/wallet_rpc.rs b/client-rpc/src/rpc/wallet_rpc.rs index f5fb2c476..777f11008 100644 --- a/client-rpc/src/rpc/wallet_rpc.rs +++ b/client-rpc/src/rpc/wallet_rpc.rs @@ -13,17 +13,25 @@ use chain_core::tx::TxObfuscated; use chain_core::tx::{TxAux, TxEnclaveAux}; use client_common::{PublicKey, Result as CommonResult}; use client_core::types::TransactionChange; +use client_core::types::WalletKind; use client_core::{MultiSigWalletClient, WalletClient}; use crate::server::{rpc_error_from_string, to_rpc_error, WalletRequest}; - +use secstr::*; #[rpc] pub trait WalletRpc: Send + Sync { #[rpc(name = "wallet_balance")] fn balance(&self, request: WalletRequest) -> Result; #[rpc(name = "wallet_create")] - fn create(&self, request: WalletRequest) -> Result; + fn create(&self, request: WalletRequest, walletkind: WalletKind) -> Result; + + fn create_basic(&self, request: WalletRequest) -> Result; + + fn create_hd(&self, request: WalletRequest) -> Result; + + #[rpc(name = "wallet_restore")] + fn restore(&self, request: WalletRequest, mnemonics: SecUtf8) -> Result; #[rpc(name = "wallet_createStakingAddress")] fn create_staking_address(&self, request: WalletRequest) -> Result; @@ -87,7 +95,62 @@ where } } - fn create(&self, request: WalletRequest) -> Result { + fn create(&self, request: WalletRequest, kind: WalletKind) -> Result { + match kind { + WalletKind::Basic => self.create_basic(request), + WalletKind::HD => self.create_hd(request), + } + } + + fn create_basic(&self, request: WalletRequest) -> Result { + if let Err(err) = self.client.new_wallet(&request.name, &request.passphrase) { + return Err(to_rpc_error(err)); + } + + self.client + .new_staking_address(&request.name, &request.passphrase) + .map_err(to_rpc_error)?; + self.client + .new_transfer_address(&request.name, &request.passphrase) + .map_err(to_rpc_error)?; + Ok(request.name) + } + + fn create_hd(&self, request: WalletRequest) -> Result { + let mnemonics = self.client.new_mnemonics().map_err(to_rpc_error)?; + let mnemonics_phrase = SecUtf8::from(mnemonics.to_string()); + + // make seed for hd-wallet + if let Err(err) = + self.client + .new_hdwallet(&request.name, &request.passphrase, &mnemonics_phrase) + { + return Err(to_rpc_error(err)); + } + // make basic wallet + // only generation is different with basic wallet + if let Err(err) = self.client.new_wallet(&request.name, &request.passphrase) { + return Err(to_rpc_error(err)); + } + + self.client + .new_staking_address(&request.name, &request.passphrase) + .map_err(to_rpc_error)?; + self.client + .new_transfer_address(&request.name, &request.passphrase) + .map_err(to_rpc_error)?; + Ok(mnemonics.to_string()) + } + + fn restore(&self, request: WalletRequest, mnemonics: SecUtf8) -> Result { + if let Err(err) = self + .client + .new_hdwallet(&request.name, &request.passphrase, &mnemonics) + { + return Err(to_rpc_error(err)); + } + // make basic wallet + // only generation is different with basic wallet if let Err(err) = self.client.new_wallet(&request.name, &request.passphrase) { return Err(to_rpc_error(err)); } @@ -417,7 +480,10 @@ pub mod tests { let wallet_rpc = setup_wallet_rpc(); wallet_rpc - .create(create_wallet_request("Default", "123456")) + .create( + create_wallet_request("Default", "123456"), + WalletKind::Basic, + ) .unwrap(); assert_eq!( Coin::zero(), @@ -435,7 +501,10 @@ pub mod tests { let wallet_rpc = setup_wallet_rpc(); wallet_rpc - .create(create_wallet_request("Default", "123456")) + .create( + create_wallet_request("Default", "123456"), + WalletKind::Basic, + ) .unwrap(); assert_eq!( @@ -444,7 +513,10 @@ pub mod tests { "Wallet with name (Default) already exists" )), wallet_rpc - .create(create_wallet_request("Default", "123456")) + .create( + create_wallet_request("Default", "123456"), + WalletKind::Basic + ) .unwrap_err() ); } @@ -456,7 +528,10 @@ pub mod tests { assert_eq!( "Default".to_owned(), wallet_rpc - .create(create_wallet_request("Default", "123456")) + .create( + create_wallet_request("Default", "123456"), + WalletKind::Basic + ) .unwrap() ); @@ -468,7 +543,9 @@ pub mod tests { let wallet_rpc = setup_wallet_rpc(); let wallet_request = create_wallet_request("Default", "123456"); - wallet_rpc.create(wallet_request.clone()).unwrap(); + wallet_rpc + .create(wallet_request.clone(), WalletKind::Basic) + .unwrap(); assert_eq!( 1, @@ -492,7 +569,9 @@ pub mod tests { let wallet_rpc = setup_wallet_rpc(); let wallet_request = create_wallet_request("Default", "123456"); - wallet_rpc.create(wallet_request.clone()).unwrap(); + wallet_rpc + .create(wallet_request.clone(), WalletKind::Basic) + .unwrap(); assert_eq!( 1, wallet_rpc @@ -519,7 +598,9 @@ pub mod tests { let wallet_rpc = setup_wallet_rpc(); let wallet_request = create_wallet_request("Default", "123456"); - wallet_rpc.create(wallet_request.clone()).unwrap(); + wallet_rpc + .create(wallet_request.clone(), WalletKind::Basic) + .unwrap(); assert_eq!( 1, @@ -547,7 +628,9 @@ pub mod tests { let wallet_rpc = setup_wallet_rpc(); let wallet_request = create_wallet_request("Default", "123456"); - wallet_rpc.create(wallet_request.clone()).unwrap(); + wallet_rpc + .create(wallet_request.clone(), WalletKind::Basic) + .unwrap(); assert_eq!( wallet_rpc @@ -565,13 +648,19 @@ pub mod tests { assert_eq!(0, wallet_rpc.list().unwrap().len()); wallet_rpc - .create(create_wallet_request("Default", "123456")) + .create( + create_wallet_request("Default", "123456"), + WalletKind::Basic, + ) .unwrap(); assert_eq!(vec!["Default"], wallet_rpc.list().unwrap()); wallet_rpc - .create(create_wallet_request("Personal", "123456")) + .create( + create_wallet_request("Personal", "123456"), + WalletKind::Basic, + ) .unwrap(); let wallet_list = wallet_rpc.list().unwrap(); @@ -585,7 +674,9 @@ pub mod tests { let wallet_rpc = setup_wallet_rpc(); let wallet_request = create_wallet_request("Default", "123456"); - wallet_rpc.create(wallet_request.clone()).unwrap(); + wallet_rpc + .create(wallet_request.clone(), WalletKind::Basic) + .unwrap(); assert_eq!( 0, wallet_rpc @@ -620,4 +711,66 @@ pub mod tests { passphrase: SecUtf8::from(passphrase), } } + + #[test] + fn hdwallet_should_create_hd_wallet() { + let wallet_rpc = setup_wallet_rpc(); + + wallet_rpc + .create(create_wallet_request("Default", "123456"), WalletKind::HD) + .unwrap(); + } + + #[test] + fn hdwallet_should_recover_hd_wallet() { + let wallet_rpc = setup_wallet_rpc(); + + let result=wallet_rpc + .restore( + create_wallet_request("Default", "123456"), + SecUtf8::from("online hire print other clock like betray vote hollow bus insect meadow replace two tape worry quality disease cabin girl tree pudding issue radar") + ) + .unwrap(); + assert!("Default" == result); + } + + #[test] + fn wallet_can_send_amount_should_fail_with_insufficient_amount() { + let wallet_rpc = setup_wallet_rpc(); + + let result=wallet_rpc + .restore( + create_wallet_request("Default", "123456"), + SecUtf8::from("online hire print other clock like betray vote hollow bus insect meadow replace two tape worry quality disease cabin girl tree pudding issue radar") + ) + .unwrap(); + assert!("Default" == result); + + let wallet_request = create_wallet_request("Default", "123456"); + + let result = wallet_rpc + .create_transfer_address(wallet_request.clone()) + .unwrap(); + assert!( + "dcro1cxsz9ayc9a93j98l2dqjc8nxnr3hgjt2an9s79w2mpnusap353gqdswd75" == result.to_string() + ); + + let to_result = wallet_rpc + .create_transfer_address(wallet_request.clone()) + .unwrap(); + assert!( + "dcro1kgdm0vg9sfymdln44vmlteyly3v4gglusfkmjpr7j6vc33jcl9dsgjqmef" + == to_result.to_string() + ); + + let viewkey = wallet_rpc.get_view_key(wallet_request.clone()).unwrap(); + + let send_result = wallet_rpc.send_to_address( + wallet_request.clone(), + to_result, + Coin::from(1_0000u32), + vec![viewkey], + ); + assert!(send_result.is_err()); + } } diff --git a/integration-tests/client-rpc/test/network-ops.test.ts b/integration-tests/client-rpc/test/network-ops.test.ts index 53477073d..ab43d38e2 100644 --- a/integration-tests/client-rpc/test/network-ops.test.ts +++ b/integration-tests/client-rpc/test/network-ops.test.ts @@ -134,7 +134,7 @@ describe("Staking", () => { const walletName = generateWalletName(); const walletRequest = newWalletRequest(walletName, "123456"); - await rpcClient.request("wallet_create", [walletRequest]); + await rpcClient.request("wallet_create", [walletRequest, "Basic"]); const stakingAddress = await asyncMiddleman( rpcClient.request("wallet_createStakingAddress", [walletRequest]), "Error when creating staking address", diff --git a/integration-tests/client-rpc/test/wallet-auto-sync.test.ts b/integration-tests/client-rpc/test/wallet-auto-sync.test.ts index 42b1904cd..fbc8c6a11 100644 --- a/integration-tests/client-rpc/test/wallet-auto-sync.test.ts +++ b/integration-tests/client-rpc/test/wallet-auto-sync.test.ts @@ -46,7 +46,7 @@ describe("Wallet Auto-sync", () => { const transferAmount = "1000"; await asyncMiddleman( - zeroFeeRpcClient.request("wallet_create", [receiverWalletRequest]), + zeroFeeRpcClient.request("wallet_create", [receiverWalletRequest, "Basic"]), "Error when creating receiver wallet", ); diff --git a/integration-tests/client-rpc/test/wallet-management.test.ts b/integration-tests/client-rpc/test/wallet-management.test.ts index c1c2908af..fdd117f81 100644 --- a/integration-tests/client-rpc/test/wallet-management.test.ts +++ b/integration-tests/client-rpc/test/wallet-management.test.ts @@ -58,7 +58,8 @@ describe("Wallet management", () => { const walletRequest = newWalletRequest(walletName, "123456"); const walletCreateResult = await client.request("wallet_create", [ - walletRequest, + walletRequest + , "Basic" ]); expect(walletCreateResult).to.deep.eq(walletName); @@ -71,7 +72,7 @@ describe("Wallet management", () => { const walletRequest = newWalletRequest(walletName, "123456"); const walletCreateResponse = await client.request("wallet_create", [ - walletRequest, + walletRequest, "Basic" ]); expect(walletCreateResponse).to.deep.eq(walletName); @@ -95,12 +96,12 @@ describe("Wallet management", () => { const walletRequest = newWalletRequest(walletName, "123456"); const walletCreateResponse = await client.request("wallet_create", [ - walletRequest, + walletRequest,"Basic" ]); expect(walletCreateResponse).to.deep.eq(walletName); return expect( - client.request("wallet_create", [walletRequest]), + client.request("wallet_create", [walletRequest,"Basic"]), ).to.eventually.rejectedWith( `Invalid input: Wallet with name (${walletName}) already exists`, ); @@ -112,7 +113,7 @@ describe("Wallet management", () => { const walletRequest = newWalletRequest(walletName, walletPassphrase); await expect( - client.request("wallet_create", [walletRequest]), + client.request("wallet_create", [walletRequest,"Basic"]), ).to.eventually.deep.eq(walletName); const incorrectWalletPassphrase = "different_passphrase"; @@ -140,7 +141,7 @@ describe("Wallet management", () => { const walletPassphrase = "passphrase"; const walletRequest = newWalletRequest(walletName, walletPassphrase); - await client.request("wallet_create", [walletRequest]); + await client.request("wallet_create", [walletRequest, "Basic"]); const transferAddress = await client.request("wallet_createTransferAddress", [ walletRequest, @@ -159,7 +160,7 @@ describe("Wallet management", () => { const walletPassphrase = "passphrase"; const walletRequest = newWalletRequest(walletName, walletPassphrase); - await client.request("wallet_create", [walletRequest]); + await client.request("wallet_create", [walletRequest,"Basic"]); const stakingAddress = await client.request("wallet_createStakingAddress", [ walletRequest, diff --git a/integration-tests/client-rpc/test/wallet-transaction.test.ts b/integration-tests/client-rpc/test/wallet-transaction.test.ts index 5907733e2..d194edd2a 100644 --- a/integration-tests/client-rpc/test/wallet-transaction.test.ts +++ b/integration-tests/client-rpc/test/wallet-transaction.test.ts @@ -69,7 +69,7 @@ describe("Wallet transaction", () => { const transferAmount = "1000"; await asyncMiddleman( - zeroFeeRpcClient.request("wallet_create", [receiverWalletRequest]), + zeroFeeRpcClient.request("wallet_create", [receiverWalletRequest,"Basic"]), "Error when creating receiver wallet", ); @@ -209,7 +209,7 @@ describe("Wallet transaction", () => { const transferAmount = "1000"; await asyncMiddleman( - withFeeRpcClient.request("wallet_create", [receiverWalletRequest]), + withFeeRpcClient.request("wallet_create", [receiverWalletRequest,"Basic"]), "Error when creating receive wallet", );