From 52e921fad9c2f758d8b42d8cdc1e1a4f2d635335 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 10 Feb 2022 11:42:29 -0800 Subject: [PATCH 01/14] adding base64 package --- Cargo.lock | 1 + full-service/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 3cfe3bb9b..23264e255 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2310,6 +2310,7 @@ dependencies = [ name = "mc-full-service" version = "1.4.0" dependencies = [ + "base64 0.13.0", "bs58", "chrono", "crossbeam-channel", diff --git a/full-service/Cargo.toml b/full-service/Cargo.toml index fde57a237..e2db3c5b4 100644 --- a/full-service/Cargo.toml +++ b/full-service/Cargo.toml @@ -38,6 +38,7 @@ mc-util-parse = { path = "../mobilecoin/util/parse" } mc-util-serial = { path = "../mobilecoin/util/serial", default-features = false } mc-util-uri = { path = "../mobilecoin/util/uri" } +base64 = "0.13.0" chrono = { version = "0.4", default-features = false, features = ["alloc"] } crossbeam-channel = "0.5" diesel = { version = "1.4.6", features = ["sqlcipher-bundled"] } From f180f3b770e9eaf2031244e005e267c52fdec4a9 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 10 Feb 2022 11:43:24 -0800 Subject: [PATCH 02/14] Using base64 instead of hex to decode fog_authority_spki --- full-service/src/db/account.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/full-service/src/db/account.rs b/full-service/src/db/account.rs index 5996801af..62967c07b 100644 --- a/full-service/src/db/account.rs +++ b/full-service/src/db/account.rs @@ -187,7 +187,7 @@ impl AccountModel for Account { .try_into_account_key( &fog_report_url.unwrap_or_else(|| "".to_string()), &fog_report_id.unwrap_or_else(|| "".to_string()), - &hex::decode(fog_authority_spki.unwrap_or_else(|| "".to_string())) + &base64::decode(fog_authority_spki.unwrap_or_else(|| "".to_string())) .expect("invalid spki"), ) .unwrap(); @@ -219,8 +219,10 @@ impl AccountModel for Account { root_entropy: entropy.clone(), fog_report_url: fog_report_url.unwrap_or_else(|| "".to_string()), fog_report_id: fog_report_id.unwrap_or_else(|| "".to_string()), - fog_authority_spki: hex::decode(fog_authority_spki.unwrap_or_else(|| "".to_string())) - .expect("invalid spki"), + fog_authority_spki: base64::decode( + fog_authority_spki.unwrap_or_else(|| "".to_string()), + ) + .expect("invalid spki"), }; let account_key = AccountKey::from(&root_id); From b28d67c43015fbb96daaac2cb4d09d82d4f85680 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 10 Feb 2022 11:43:46 -0800 Subject: [PATCH 03/14] adding fog params to create_account function --- full-service/src/json_rpc/json_rpc_request.rs | 3 +++ full-service/src/json_rpc/wallet.rs | 12 +++++++--- full-service/src/service/account.rs | 22 ++++++++++++++----- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/full-service/src/json_rpc/json_rpc_request.rs b/full-service/src/json_rpc/json_rpc_request.rs index 62628d005..43d43c366 100644 --- a/full-service/src/json_rpc/json_rpc_request.rs +++ b/full-service/src/json_rpc/json_rpc_request.rs @@ -114,6 +114,9 @@ pub enum JsonCommandRequest { }, create_account { name: Option, + fog_report_url: Option, + fog_report_id: Option, + fog_authority_spki: Option, }, create_payment_request { account_id: String, diff --git a/full-service/src/json_rpc/wallet.rs b/full-service/src/json_rpc/wallet.rs index 15c8ef7e1..d6b1392b0 100644 --- a/full-service/src/json_rpc/wallet.rs +++ b/full-service/src/json_rpc/wallet.rs @@ -336,9 +336,15 @@ where txo_id: TxoID::from(&tx.prefix.outputs[0]).to_string(), } } - JsonCommandRequest::create_account { name } => { - let account: db::models::Account = - service.create_account(name).map_err(format_error)?; + JsonCommandRequest::create_account { + name, + fog_report_url, + fog_report_id, + fog_authority_spki, + } => { + let account: db::models::Account = service + .create_account(name, fog_report_url, fog_report_id, fog_authority_spki) + .map_err(format_error)?; JsonCommandResponse::create_account { account: json_rpc::account::Account::try_from(&account).map_err(|e| { diff --git a/full-service/src/service/account.rs b/full-service/src/service/account.rs index d3045c771..34fd8332c 100644 --- a/full-service/src/service/account.rs +++ b/full-service/src/service/account.rs @@ -79,7 +79,13 @@ impl From for AccountServiceError { /// accounts. pub trait AccountService { /// Creates a new account with default values. - fn create_account(&self, name: Option) -> Result; + fn create_account( + &self, + name: Option, + fog_report_url: Option, + fog_report_id: Option, + fog_authority_spki: Option, + ) -> Result; /// Import an existing account to the wallet using the entropy. #[allow(clippy::too_many_arguments)] @@ -130,7 +136,13 @@ where T: BlockchainConnection + UserTxConnection + 'static, FPR: FogPubkeyResolver + Send + Sync + 'static, { - fn create_account(&self, name: Option) -> Result { + fn create_account( + &self, + name: Option, + fog_report_url: Option, + fog_report_id: Option, + fog_authority_spki: Option, + ) -> Result { log::info!(self.logger, "Creating account {:?}", name,); // Generate entropy for the account @@ -153,9 +165,9 @@ where Some(import_block_index), None, &name.unwrap_or_else(|| "".to_string()), - None, - None, - None, + fog_report_url, + fog_report_id, + fog_authority_spki, &conn, )?; From a40aefe95c1b41a8e9015a39304c5ea6c2885ed6 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 10 Feb 2022 11:52:11 -0800 Subject: [PATCH 04/14] fixing tests for create_account new params --- full-service/src/json_rpc/e2e.rs | 6 +++--- full-service/src/service/account.rs | 4 +++- full-service/src/service/gift_code.rs | 6 +++--- full-service/src/service/receipt.rs | 16 ++++++++-------- full-service/src/service/transaction.rs | 10 +++++----- full-service/src/service/txo.rs | 4 ++-- 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/full-service/src/json_rpc/e2e.rs b/full-service/src/json_rpc/e2e.rs index a83cb472e..c7739b176 100644 --- a/full-service/src/json_rpc/e2e.rs +++ b/full-service/src/json_rpc/e2e.rs @@ -418,18 +418,18 @@ mod e2e { "first_block_index": "200", "fog_report_url": "fog://fog-report.example.com", "fog_report_id": "", - "fog_authority_spki": "30820222300d06092a864886f70d01010105000382020f003082020a0282020100c853a8724bc211cf5370ed4dbec8947c5573bed0ec47ae14211454977b41336061f0a040f77dbf529f3a46d8095676ec971b940ab4c9642578760779840a3f9b3b893b2f65006c544e9c16586d33649769b7c1c94552d7efa081a56ad612dec932812676ebec091f2aed69123604f4888a125e04ff85f5a727c286664378581cf34c7ee13eb01cc4faf3308ed3c07a9415f98e5fbfe073e6c357967244e46ba6ebbe391d8154e6e4a1c80524b1a6733eca46e37bfdd62d75816988a79aac6bdb62a06b1237a8ff5e5c848d01bbff684248cf06d92f301623c893eb0fba0f3faee2d197ea57ac428f89d6c000f76d58d5aacc3d70204781aca45bc02b1456b454231d2f2ed4ca6614e5242c7d7af0fe61e9af6ecfa76674ffbc29b858091cbfb4011538f0e894ce45d21d7fac04ba2ff57e9ff6db21e2afd9468ad785c262ec59d4a1a801c5ec2f95fc107dc9cb5f7869d70aa84450b8c350c2fa48bddef20752a1e43676b246c7f59f8f1f4aee43c1a15f36f7a36a9ec708320ea42089991551f2656ec62ea38233946b85616ff182cf17cd227e596329b546ea04d13b053be4cf3338de777b50bc6eca7a6185cf7a5022bc9be3749b1bb43e10ecc88a0c580f2b7373138ee49c7bafd8be6a64048887230480b0c85a045255494e04a9a81646369ce7a10e08da6fae27333ec0c16c8a74d93779a9e055395078d0b07286f9930203010001" + "fog_authority_spki": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvnB9wTbTOT5uoizRYaYbw7XIEkInl8E7MGOAQj+xnC+F1rIXiCnc/t1+5IIWjbRGhWzo7RAwI5sRajn2sT4rRn9NXbOzZMvIqE4hmhmEzy1YQNDnfALAWNQ+WBbYGW+Vqm3IlQvAFFjVN1YYIdYhbLjAPdkgeVsWfcLDforHn6rR3QBZYZIlSBQSKRMY/tywTxeTCvK2zWcS0kbbFPtBcVth7VFFVPAZXhPi9yy1AvnldO6n7KLiupVmojlEMtv4FQkk604nal+j/dOplTATV8a9AJBbPRBZ/yQg57EG2Y2MRiHOQifJx0S5VbNyMm9bkS8TD7Goi59aCW6OT1gyeotWwLg60JRZTfyJ7lYWBSOzh0OnaCytRpSWtNZ6barPUeOnftbnJtE8rFhF7M4F66et0LI/cuvXYecwVwykovEVBKRF4HOK9GgSm17mQMtzrD7c558TbaucOWabYR04uhdAc3s10MkuONWG0wIQhgIChYVAGnFLvSpp2/aQEq3xrRSETxsixUIjsZyWWROkuA0IFnc8d7AmcnUBvRW7FT/5thWyk5agdYUGZ+7C1o69ihR1YxmoGh69fLMPIEOhYh572+3ckgl2SaV4uo9Gvkz8MMGRBcMIMlRirSwhCfozV2RyT5Wn1NgPpyc8zJL7QdOhL7Qxb+5WjnCVrQYHI2cCAwEAAQ==" } }); let res = dispatch(&client, body, &logger); let result = res.get("result").unwrap(); let account_obj = result.get("account").unwrap(); let public_address = account_obj.get("main_address").unwrap().as_str().unwrap(); - assert_eq!(public_address, "mpcKQqPcgbB2oPneTAuLiZu9ZHp9qNkQo9k6949dupe89HruwmEgvcyVRFFNQccsurgMaZBykWAR1tGwbZqw4FGckqJsAcs2Fc1912Bf84S2am1kLKiRdQWfWUm6rQ8LCw75k14htjiD4u1PfYxwEvXWHXPK2R7PpzfWv5xc8129J5DykCC6wRDUZiqDcesjf7zi91frhfWvX3E6QPnc6kKZj4mfZQPjFVkHdcXWAuQoaJc"); + assert_eq!(public_address, "2kD4vRp3DaBdRrNLNhJ5BKf5FsZxcAijoMt5pxjJpbk5jQRubngUXnd92vuXWkFyezuLgjCiKu4JHjpjNCnmzf1gAdW6PbqXsecQtp8Qr8uoeeDKrd1a5PtA6apXuDVtnrKsDCcHiJqdeSt3bRsPBvkBP4JqpGyAeKFsC7s2LQwuZ88BxFe2kyeZp5G3zENfvLaMripxTKkWGDopok2LCyA9NiCDf1vwjA5opLU7eqaRfh9"); let account_id = account_obj.get("account_id").unwrap().as_str().unwrap(); assert_eq!( account_id, - "e260179ba2bed78ed47266a55106a7365f96329203cd95edfc0915f08b7947ce" + "0b8a95253a7d57faf8510d8092ab55fb8610a9d691a7fa3bfafbf49945b845a2" ); // Export account secrets and check fog info. diff --git a/full-service/src/service/account.rs b/full-service/src/service/account.rs index 34fd8332c..631a06006 100644 --- a/full-service/src/service/account.rs +++ b/full-service/src/service/account.rs @@ -327,7 +327,9 @@ mod tests { let wallet_db = &service.wallet_db; // Create an account. - let account = service.create_account(Some("A".to_string())).unwrap(); + let account = service + .create_account(Some("A".to_string()), None, None, None) + .unwrap(); // Add a transaction, with transaction status. let account_key: AccountKey = mc_util_serial::decode(&account.account_key).unwrap(); diff --git a/full-service/src/service/gift_code.rs b/full-service/src/service/gift_code.rs index fc30f576b..55fc1b663 100644 --- a/full-service/src/service/gift_code.rs +++ b/full-service/src/service/gift_code.rs @@ -714,7 +714,7 @@ mod tests { // Create our main account for the wallet let alice = service - .create_account(Some("Alice's Main Account".to_string())) + .create_account(Some("Alice's Main Account".to_string()), None, None, None) .unwrap(); // Add a block with a transaction for Alice @@ -831,7 +831,7 @@ mod tests { // Claim the gift code to another account log::info!(logger, "Creating new account to receive gift code"); let bob = service - .create_account(Some("Bob's Main Account".to_string())) + .create_account(Some("Bob's Main Account".to_string()), None, None, None) .unwrap(); manually_sync_account( &ledger_db, @@ -895,7 +895,7 @@ mod tests { // Create our main account for the wallet let alice = service - .create_account(Some("Alice's Main Account".to_string())) + .create_account(Some("Alice's Main Account".to_string()), None, None, None) .unwrap(); // Add a block with a transaction for Alice diff --git a/full-service/src/service/receipt.rs b/full-service/src/service/receipt.rs index 8525f2220..dd29dccb0 100644 --- a/full-service/src/service/receipt.rs +++ b/full-service/src/service/receipt.rs @@ -341,7 +341,7 @@ mod tests { let service = setup_wallet_service(ledger_db.clone(), logger.clone()); let alice = service - .create_account(Some("Alice's Main Account".to_string())) + .create_account(Some("Alice's Main Account".to_string()), None, None, None) .unwrap(); // Fund Alice @@ -363,7 +363,7 @@ mod tests { ); let bob = service - .create_account(Some("Bob's Main Account".to_string())) + .create_account(Some("Bob's Main Account".to_string()), None, None, None) .unwrap(); let bob_addresses = service .get_addresses_for_account(&AccountID(bob.account_id_hex.clone()), None, None) @@ -466,7 +466,7 @@ mod tests { let service = setup_wallet_service(ledger_db.clone(), logger.clone()); let alice = service - .create_account(Some("Alice's Main Account".to_string())) + .create_account(Some("Alice's Main Account".to_string()), None, None, None) .unwrap(); // Fund Alice @@ -488,7 +488,7 @@ mod tests { ); let bob = service - .create_account(Some("Bob's Main Account".to_string())) + .create_account(Some("Bob's Main Account".to_string()), None, None, None) .unwrap(); let bob_addresses = service .get_addresses_for_account(&AccountID(bob.account_id_hex.clone()), None, None) @@ -580,7 +580,7 @@ mod tests { let service = setup_wallet_service(ledger_db.clone(), logger.clone()); let alice = service - .create_account(Some("Alice's Main Account".to_string())) + .create_account(Some("Alice's Main Account".to_string()), None, None, None) .unwrap(); // Fund Alice @@ -602,7 +602,7 @@ mod tests { ); let bob = service - .create_account(Some("Bob's Main Account".to_string())) + .create_account(Some("Bob's Main Account".to_string()), None, None, None) .unwrap(); let bob_addresses = service .get_addresses_for_account(&AccountID(bob.account_id_hex.clone()), None, None) @@ -698,7 +698,7 @@ mod tests { let service = setup_wallet_service(ledger_db.clone(), logger.clone()); let alice = service - .create_account(Some("Alice's Main Account".to_string())) + .create_account(Some("Alice's Main Account".to_string()), None, None, None) .unwrap(); // Fund Alice @@ -720,7 +720,7 @@ mod tests { ); let bob = service - .create_account(Some("Bob's Main Account".to_string())) + .create_account(Some("Bob's Main Account".to_string()), None, None, None) .unwrap(); let bob_addresses = service .get_addresses_for_account(&AccountID(bob.account_id_hex.clone()), None, None) diff --git a/full-service/src/service/transaction.rs b/full-service/src/service/transaction.rs index 96c2957ab..21a4e25da 100644 --- a/full-service/src/service/transaction.rs +++ b/full-service/src/service/transaction.rs @@ -371,7 +371,7 @@ mod tests { // Create our main account for the wallet let alice = service - .create_account(Some("Alice's Main Account".to_string())) + .create_account(Some("Alice's Main Account".to_string()), None, None, None) .unwrap(); // Add a block with a transaction for Alice @@ -415,7 +415,7 @@ mod tests { // Add an account for Bob let bob = service - .create_account(Some("Bob's Main Account".to_string())) + .create_account(Some("Bob's Main Account".to_string()), None, None, None) .unwrap(); let bob_account_key: AccountKey = mc_util_serial::decode(&bob.account_key).expect("Could not decode account key"); @@ -515,7 +515,7 @@ mod tests { // Create our main account for the wallet let alice = service - .create_account(Some("Alice's Main Account".to_string())) + .create_account(Some("Alice's Main Account".to_string()), None, None, None) .unwrap(); // Add a block with a transaction for Alice @@ -546,7 +546,7 @@ mod tests { // Add an account for Bob let bob = service - .create_account(Some("Bob's Main Account".to_string())) + .create_account(Some("Bob's Main Account".to_string()), None, None, None) .unwrap(); let bob_account_key: AccountKey = mc_util_serial::decode(&bob.account_key).expect("Could not decode account key"); @@ -700,7 +700,7 @@ mod tests { // Create our main account for the wallet let alice = service - .create_account(Some("Alice's Main Account".to_string())) + .create_account(Some("Alice's Main Account".to_string()), None, None, None) .unwrap(); // Add a block with a transaction for Alice diff --git a/full-service/src/service/txo.rs b/full-service/src/service/txo.rs index 7cecf4b5d..ca2b99282 100644 --- a/full-service/src/service/txo.rs +++ b/full-service/src/service/txo.rs @@ -198,7 +198,7 @@ mod tests { let service = setup_wallet_service(ledger_db.clone(), logger.clone()); let alice = service - .create_account(Some("Alice's Main Account".to_string())) + .create_account(Some("Alice's Main Account".to_string()), None, None, None) .unwrap(); // Add a block with a transaction for this recipient @@ -233,7 +233,7 @@ mod tests { // Add another account let bob = service - .create_account(Some("Bob's Main Account".to_string())) + .create_account(Some("Bob's Main Account".to_string()), None, None, None) .unwrap(); // Construct a new transaction to Bob From 12a04c0426e0545a83a5d53b8ed31b11d0a92c21 Mon Sep 17 00:00:00 2001 From: Brian Date: Fri, 11 Feb 2022 11:51:50 -0800 Subject: [PATCH 05/14] Handle errors during account key creation --- full-service/src/db/account.rs | 6 ++---- full-service/src/db/models.rs | 3 +++ full-service/src/db/wallet_db_error.rs | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/full-service/src/db/account.rs b/full-service/src/db/account.rs index 62967c07b..476ab2af7 100644 --- a/full-service/src/db/account.rs +++ b/full-service/src/db/account.rs @@ -187,10 +187,8 @@ impl AccountModel for Account { .try_into_account_key( &fog_report_url.unwrap_or_else(|| "".to_string()), &fog_report_id.unwrap_or_else(|| "".to_string()), - &base64::decode(fog_authority_spki.unwrap_or_else(|| "".to_string())) - .expect("invalid spki"), - ) - .unwrap(); + &base64::decode(fog_authority_spki.unwrap_or_else(|| "".to_string()))?, + )?; Account::create( mnemonic.entropy(), diff --git a/full-service/src/db/models.rs b/full-service/src/db/models.rs index 0568c4087..bad05b5eb 100644 --- a/full-service/src/db/models.rs +++ b/full-service/src/db/models.rs @@ -100,6 +100,8 @@ pub struct Account { pub import_block_index: Option, /// Name of this account. pub name: String, /* empty string for nullable */ + // /// If this is a FOG enabled account + // pub fog_enabled: bool, } /// A structure that can be inserted to create a new entity in the `accounts` @@ -118,6 +120,7 @@ pub struct NewAccount<'a> { pub next_block_index: i64, pub import_block_index: Option, pub name: &'a str, + // pub fog_enabled: bool, } /// A transaction output entity that either was received to an Account in this diff --git a/full-service/src/db/wallet_db_error.rs b/full-service/src/db/wallet_db_error.rs index d18a7f6d4..0eba9cb05 100644 --- a/full-service/src/db/wallet_db_error.rs +++ b/full-service/src/db/wallet_db_error.rs @@ -119,6 +119,12 @@ pub enum WalletDbError { /// Error converting to/from API protos: {0} ProtoConversion(mc_api::ConversionError), + + /// Error while generating a Slip10Key: {0} + Slip10Key(mc_account_keys_slip10::Error), + + /// Decode from Base64 error: {0} + Base64Decode(base64::DecodeError), } impl From for WalletDbError { @@ -168,3 +174,15 @@ impl From for WalletDbError { Self::LedgerDB(src) } } + +impl From for WalletDbError { + fn from(src: mc_account_keys_slip10::Error) -> Self { + Self::Slip10Key(src) + } +} + +impl From for WalletDbError { + fn from(src: base64::DecodeError) -> Self { + Self::Base64Decode(src) + } +} From a274df1d166fecab95fabf4ab518b7ccb660a07f Mon Sep 17 00:00:00 2001 From: Brian Date: Fri, 11 Feb 2022 11:57:05 -0800 Subject: [PATCH 06/14] fmt changes --- full-service/src/db/account.rs | 11 +++++------ full-service/src/db/models.rs | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/full-service/src/db/account.rs b/full-service/src/db/account.rs index 476ab2af7..73df9e4b9 100644 --- a/full-service/src/db/account.rs +++ b/full-service/src/db/account.rs @@ -183,12 +183,11 @@ impl AccountModel for Account { fog_authority_spki: Option, conn: &PooledConnection>, ) -> Result<(AccountID, String), WalletDbError> { - let account_key = Slip10Key::from(mnemonic.clone()) - .try_into_account_key( - &fog_report_url.unwrap_or_else(|| "".to_string()), - &fog_report_id.unwrap_or_else(|| "".to_string()), - &base64::decode(fog_authority_spki.unwrap_or_else(|| "".to_string()))?, - )?; + let account_key = Slip10Key::from(mnemonic.clone()).try_into_account_key( + &fog_report_url.unwrap_or_else(|| "".to_string()), + &fog_report_id.unwrap_or_else(|| "".to_string()), + &base64::decode(fog_authority_spki.unwrap_or_else(|| "".to_string()))?, + )?; Account::create( mnemonic.entropy(), diff --git a/full-service/src/db/models.rs b/full-service/src/db/models.rs index bad05b5eb..e937fa991 100644 --- a/full-service/src/db/models.rs +++ b/full-service/src/db/models.rs @@ -100,8 +100,8 @@ pub struct Account { pub import_block_index: Option, /// Name of this account. pub name: String, /* empty string for nullable */ - // /// If this is a FOG enabled account - // pub fog_enabled: bool, + /// Fog enabled address + pub fog_enabled: bool, } /// A structure that can be inserted to create a new entity in the `accounts` @@ -120,7 +120,7 @@ pub struct NewAccount<'a> { pub next_block_index: i64, pub import_block_index: Option, pub name: &'a str, - // pub fog_enabled: bool, + pub fog_enabled: bool, } /// A transaction output entity that either was received to an Account in this From a6a5bf2abced26e96d57b5215d9cc8346cffcafa Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 15 Feb 2022 12:21:56 -0800 Subject: [PATCH 07/14] Added migration and updated schema --- .../migrations/2022-02-15-200456_fog_enabled_accounts/down.sql | 1 + .../migrations/2022-02-15-200456_fog_enabled_accounts/up.sql | 1 + full-service/src/db/schema.rs | 1 + 3 files changed, 3 insertions(+) create mode 100644 full-service/migrations/2022-02-15-200456_fog_enabled_accounts/down.sql create mode 100644 full-service/migrations/2022-02-15-200456_fog_enabled_accounts/up.sql diff --git a/full-service/migrations/2022-02-15-200456_fog_enabled_accounts/down.sql b/full-service/migrations/2022-02-15-200456_fog_enabled_accounts/down.sql new file mode 100644 index 000000000..10b52b017 --- /dev/null +++ b/full-service/migrations/2022-02-15-200456_fog_enabled_accounts/down.sql @@ -0,0 +1 @@ +ALTER TABLE accounts DROP COLUMN fog_enabled; \ No newline at end of file diff --git a/full-service/migrations/2022-02-15-200456_fog_enabled_accounts/up.sql b/full-service/migrations/2022-02-15-200456_fog_enabled_accounts/up.sql new file mode 100644 index 000000000..5bc1c3cf3 --- /dev/null +++ b/full-service/migrations/2022-02-15-200456_fog_enabled_accounts/up.sql @@ -0,0 +1 @@ +ALTER TABLE accounts ADD COLUMN fog_enabled BOOLEAN NOT NULL DEFAULT FALSE; \ No newline at end of file diff --git a/full-service/src/db/schema.rs b/full-service/src/db/schema.rs index 7b6e93cab..460dd2aaf 100644 --- a/full-service/src/db/schema.rs +++ b/full-service/src/db/schema.rs @@ -12,6 +12,7 @@ table! { next_block_index -> BigInt, import_block_index -> Nullable, name -> Text, + fog_enabled -> Bool, } } From bae5593f3a870a8e61aab626d78178e0ae2ff11f Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 15 Feb 2022 12:22:27 -0800 Subject: [PATCH 08/14] accounts with fog credentials get flagged as fog_enabled on creation --- full-service/src/db/account.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/full-service/src/db/account.rs b/full-service/src/db/account.rs index 43952a4a6..a288783dc 100644 --- a/full-service/src/db/account.rs +++ b/full-service/src/db/account.rs @@ -94,6 +94,7 @@ pub trait AccountModel { import_block_index: Option, next_subaddress_index: Option, name: &str, + fog_enabled: bool, conn: &PooledConnection>, ) -> Result<(AccountID, String), WalletDbError>; @@ -183,6 +184,11 @@ impl AccountModel for Account { fog_authority_spki: Option, conn: &PooledConnection>, ) -> Result<(AccountID, String), WalletDbError> { + let fog_enabled = match fog_report_url { + Some(_) => true, + None => false, + }; + let account_key = Slip10Key::from(mnemonic.clone()).try_into_account_key( &fog_report_url.unwrap_or_else(|| "".to_string()), &fog_report_id.unwrap_or_else(|| "".to_string()), @@ -197,6 +203,7 @@ impl AccountModel for Account { import_block_index, next_subaddress_index, name, + fog_enabled, conn, ) } @@ -212,6 +219,11 @@ impl AccountModel for Account { fog_authority_spki: Option, conn: &PooledConnection>, ) -> Result<(AccountID, String), WalletDbError> { + let fog_enabled = match fog_report_url { + Some(_) => true, + None => false, + }; + let root_id = RootIdentity { root_entropy: entropy.clone(), fog_report_url: fog_report_url.unwrap_or_else(|| "".to_string()), @@ -231,6 +243,7 @@ impl AccountModel for Account { import_block_index, next_subaddress_index, name, + fog_enabled, conn, ) } @@ -243,6 +256,7 @@ impl AccountModel for Account { import_block_index: Option, next_subaddress_index: Option, name: &str, + fog_enabled: bool, conn: &PooledConnection>, ) -> Result<(AccountID, String), WalletDbError> { use crate::db::schema::accounts; @@ -264,6 +278,7 @@ impl AccountModel for Account { next_block_index: fb as i64, import_block_index: import_block_index.map(|i| i as i64), name, + fog_enabled, }; diesel::insert_into(accounts::table) From 17ad3d896904366b526012a4c270fc4ea4deb8f3 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 15 Feb 2022 12:50:35 -0800 Subject: [PATCH 09/14] FOG accounts only use main subaddress for everything --- full-service/src/db/account.rs | 42 ++++++++++++++-------- full-service/src/db/assigned_subaddress.rs | 4 +++ full-service/src/db/wallet_db_error.rs | 3 ++ 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/full-service/src/db/account.rs b/full-service/src/db/account.rs index a288783dc..88a7f2542 100644 --- a/full-service/src/db/account.rs +++ b/full-service/src/db/account.rs @@ -264,6 +264,18 @@ impl AccountModel for Account { let account_id = AccountID::from(account_key); let fb = first_block_index.unwrap_or(DEFAULT_FIRST_BLOCK_INDEX); + let change_subaddress_index = if fog_enabled { + DEFAULT_SUBADDRESS_INDEX as i64 + } else { + DEFAULT_CHANGE_SUBADDRESS_INDEX as i64 + }; + + let next_subaddress_index = if fog_enabled { + 1 + } else { + next_subaddress_index.unwrap_or(DEFAULT_NEXT_SUBADDRESS_INDEX) as i64 + }; + let new_account = NewAccount { account_id_hex: &account_id.to_string(), account_key: &mc_util_serial::encode(account_key), /* FIXME: WS-6 - add @@ -271,9 +283,8 @@ impl AccountModel for Account { entropy, key_derivation_version: key_derivation_version as i32, main_subaddress_index: DEFAULT_SUBADDRESS_INDEX as i64, - change_subaddress_index: DEFAULT_CHANGE_SUBADDRESS_INDEX as i64, - next_subaddress_index: next_subaddress_index.unwrap_or(DEFAULT_NEXT_SUBADDRESS_INDEX) - as i64, + change_subaddress_index, + next_subaddress_index, first_block_index: fb as i64, next_block_index: fb as i64, import_block_index: import_block_index.map(|i| i as i64), @@ -293,18 +304,19 @@ impl AccountModel for Account { "Main", conn, )?; - - let _change_subaddress_b58 = AssignedSubaddress::create( - account_key, - None, /* FIXME: WS-8 - Address Book Entry if details provided, or None - * always for main? */ - DEFAULT_CHANGE_SUBADDRESS_INDEX, - "Change", - conn, - )?; - - for subaddress_index in 2..next_subaddress_index.unwrap_or(DEFAULT_NEXT_SUBADDRESS_INDEX) { - AssignedSubaddress::create(account_key, None, subaddress_index, "", conn)?; + if !fog_enabled { + AssignedSubaddress::create( + account_key, + None, /* FIXME: WS-8 - Address Book Entry if details provided, or None + * always for main? */ + DEFAULT_CHANGE_SUBADDRESS_INDEX, + "Change", + conn, + )?; + + for subaddress_index in 2..next_subaddress_index { + AssignedSubaddress::create(account_key, None, subaddress_index as u64, "", conn)?; + } } Ok((account_id, main_subaddress_b58)) diff --git a/full-service/src/db/assigned_subaddress.rs b/full-service/src/db/assigned_subaddress.rs index 408499dec..a0edc2fa6 100644 --- a/full-service/src/db/assigned_subaddress.rs +++ b/full-service/src/db/assigned_subaddress.rs @@ -145,6 +145,10 @@ impl AssignedSubaddressModel for AssignedSubaddress { let account = Account::get(&AccountID(account_id_hex.to_string()), conn)?; + if account.fog_enabled { + return Err(WalletDbError::SubaddressesNotSupportedForFOGEnabledAccounts); + } + let account_key: AccountKey = mc_util_serial::decode(&account.account_key)?; let account_view_key = account_key.view_key(); let subaddress_index = account.next_subaddress_index; diff --git a/full-service/src/db/wallet_db_error.rs b/full-service/src/db/wallet_db_error.rs index 0eba9cb05..c61ae5a7d 100644 --- a/full-service/src/db/wallet_db_error.rs +++ b/full-service/src/db/wallet_db_error.rs @@ -125,6 +125,9 @@ pub enum WalletDbError { /// Decode from Base64 error: {0} Base64Decode(base64::DecodeError), + + /// Subaddresses are not supported for FOG enabled accounts + SubaddressesNotSupportedForFOGEnabledAccounts, } impl From for WalletDbError { From e5169069217fd139e3cfd2a6f6046a99bfa875cb Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 15 Feb 2022 12:55:39 -0800 Subject: [PATCH 10/14] adding fog_enabled flag to json_rpc account model --- full-service/src/json_rpc/account.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/full-service/src/json_rpc/account.rs b/full-service/src/json_rpc/account.rs index 79921aca9..d918c6a09 100644 --- a/full-service/src/json_rpc/account.rs +++ b/full-service/src/json_rpc/account.rs @@ -46,6 +46,12 @@ pub struct Account { /// found TXOs. It is recommended to move all MOB to another account after /// recovery if the user is unsure of the assigned addresses. pub recovery_mode: bool, + + /// A flag that indicates if this account is FOG enabled, which means that + /// it will send any change to it's main subaddress (index 0) instead of + /// the default change subaddress (index 1). It also generates + /// PublicAddressB58's with fog credentials. + pub fog_enabled: bool, } impl TryFrom<&db::models::Account> for Account { @@ -68,6 +74,7 @@ impl TryFrom<&db::models::Account> for Account { first_block_index: (src.first_block_index as u64).to_string(), next_block_index: (src.next_block_index as u64).to_string(), recovery_mode: false, + fog_enabled: src.fog_enabled, }) } } From e7477e40cbdb6234a0d37d859b52a9e49dbad506 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 15 Feb 2022 12:57:17 -0800 Subject: [PATCH 11/14] fixing test --- full-service/src/db/account.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/full-service/src/db/account.rs b/full-service/src/db/account.rs index 88a7f2542..f1d54eea1 100644 --- a/full-service/src/db/account.rs +++ b/full-service/src/db/account.rs @@ -527,6 +527,7 @@ mod tests { next_block_index: 0, import_block_index: None, name: "Alice's Main Account".to_string(), + fog_enabled: false, }; assert_eq!(expected_account, acc); @@ -589,6 +590,7 @@ mod tests { next_block_index: 51, import_block_index: Some(50), name: "".to_string(), + fog_enabled: false, }; assert_eq!(expected_account_secondary, acc_secondary); From 390f35abe151ee6762198369166b16f09c3ff430 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 17 Feb 2022 10:17:18 -0800 Subject: [PATCH 12/14] add test_create_fog_account --- full-service/src/db/account.rs | 69 ++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/full-service/src/db/account.rs b/full-service/src/db/account.rs index f1d54eea1..4061069e4 100644 --- a/full-service/src/db/account.rs +++ b/full-service/src/db/account.rs @@ -184,10 +184,7 @@ impl AccountModel for Account { fog_authority_spki: Option, conn: &PooledConnection>, ) -> Result<(AccountID, String), WalletDbError> { - let fog_enabled = match fog_report_url { - Some(_) => true, - None => false, - }; + let fog_enabled = fog_report_url.is_some(); let account_key = Slip10Key::from(mnemonic.clone()).try_into_account_key( &fog_report_url.unwrap_or_else(|| "".to_string()), @@ -219,10 +216,7 @@ impl AccountModel for Account { fog_authority_spki: Option, conn: &PooledConnection>, ) -> Result<(AccountID, String), WalletDbError> { - let fog_enabled = match fog_report_url { - Some(_) => true, - None => false, - }; + let fog_enabled = fog_report_url.is_some(); let root_id = RootIdentity { root_entropy: entropy.clone(), @@ -658,4 +652,63 @@ mod tests { let decoded_account_key: AccountKey = mc_util_serial::decode(&account.account_key).unwrap(); assert_eq!(decoded_account_key, account_key); } + + #[test_with_logger] + fn test_create_fog_account(logger: Logger) { + let mut rng: StdRng = SeedableRng::from_seed([20u8; 32]); + + let db_test_context = WalletDbTestContext::default(); + let wallet_db = db_test_context.get_db_instance(logger); + + let root_id = RootIdentity::from_random(&mut rng); + let account_id_hex = { + let conn = wallet_db.get_conn().unwrap(); + let (account_id_hex, _public_address_b58) = Account::create_from_root_entropy( + &root_id.root_entropy, + Some(0), + None, + None, + "Alice's FOG Account", + Some("fog//some.fog.url".to_string()), + Some("".to_string()), + Some("DefinitelyARealFOGAuthoritySPKI".to_string()), + &conn, + ) + .unwrap(); + account_id_hex + }; + + { + let conn = wallet_db.get_conn().unwrap(); + let res = Account::list_all(&conn).unwrap(); + assert_eq!(res.len(), 1); + } + + let acc = Account::get(&account_id_hex, &wallet_db.get_conn().unwrap()).unwrap(); + let expected_account = Account { + id: 1, + account_id_hex: account_id_hex.to_string(), + account_key: [ + 10, 34, 10, 32, 129, 223, 141, 215, 200, 104, 120, 117, 123, 154, 151, 210, 253, + 23, 148, 151, 2, 18, 182, 100, 83, 138, 144, 99, 225, 74, 214, 14, 175, 68, 167, 4, + 18, 34, 10, 32, 24, 98, 18, 92, 9, 50, 142, 184, 114, 99, 34, 125, 211, 54, 146, + 33, 98, 71, 179, 56, 136, 67, 98, 97, 230, 228, 31, 194, 119, 169, 189, 8, 26, 17, + 102, 111, 103, 47, 47, 115, 111, 109, 101, 46, 102, 111, 103, 46, 117, 114, 108, + 42, 23, 13, 231, 226, 158, 43, 94, 151, 32, 17, 121, 169, 69, 56, 96, 46, 182, 26, + 43, 138, 220, 146, 60, 162, + ] + .to_vec(), + entropy: root_id.root_entropy.bytes.to_vec(), + key_derivation_version: 1, + main_subaddress_index: 0, + change_subaddress_index: 0, + next_subaddress_index: 1, + first_block_index: 0, + next_block_index: 0, + import_block_index: None, + name: "Alice's FOG Account".to_string(), + fog_enabled: true, + }; + assert_eq!(expected_account, acc); + } } From 927047d99839d9080462daa1fc2f2601bf53057f Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 17 Feb 2022 10:46:49 -0800 Subject: [PATCH 13/14] adding TODOs for tests --- full-service/src/json_rpc/e2e.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/full-service/src/json_rpc/e2e.rs b/full-service/src/json_rpc/e2e.rs index fc432b130..d8bef9ae9 100644 --- a/full-service/src/json_rpc/e2e.rs +++ b/full-service/src/json_rpc/e2e.rs @@ -3467,4 +3467,14 @@ mod e2e { let result = res["result"]["gift_codes"].as_array().unwrap(); assert_eq!(result.len(), 0); } + + // TODO - Add test to make sure fog account imports successfully with both + // import styles + + // TODO - Add test to make sure fog account creates successfully + + // TODO - Add test to make sure fog account sends change to main subaddress + // (index 0) + + // TODO - Add test to make sure fog accounts fail to assign next subaddress } From 821c379934070f20a21b7044fcf476589b630774 Mon Sep 17 00:00:00 2001 From: Colin Carey Date: Thu, 17 Feb 2022 15:52:20 -0800 Subject: [PATCH 14/14] Add e2e tests for fog accounts --- full-service/src/json_rpc/e2e.rs | 208 ++++++++++++++++++++++--------- 1 file changed, 147 insertions(+), 61 deletions(-) diff --git a/full-service/src/json_rpc/e2e.rs b/full-service/src/json_rpc/e2e.rs index d8bef9ae9..7477a56cc 100644 --- a/full-service/src/json_rpc/e2e.rs +++ b/full-service/src/json_rpc/e2e.rs @@ -50,6 +50,7 @@ mod e2e { assert!(account_obj.get("main_address").is_some()); assert_eq!(account_obj.get("next_subaddress_index").unwrap(), "2"); assert_eq!(account_obj.get("recovery_mode").unwrap(), false); + assert_eq!(account_obj.get("fog_enabled").unwrap(), false); let account_id = account_obj.get("account_id").unwrap(); @@ -142,6 +143,36 @@ mod e2e { assert_eq!(accounts.len(), 0); } + #[test_with_logger] + fn test_e2e_create_account_with_fog(logger: Logger) { + let mut rng: StdRng = SeedableRng::from_seed([20u8; 32]); + let (client, _ledger_db, _db_ctx, _network_state) = setup(&mut rng, logger.clone()); + // Create Account + let body = json!({ + "jsonrpc": "2.0", + "id": 1, + "method": "create_account", + "params": { + "name": "Alice Main Account", + "fog_report_url": "fog://fog-report.example.com", + "fog_report_id": "", + "fog_authority_spki": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvnB9wTbTOT5uoizRYaYbw7XIEkInl8E7MGOAQj+xnC+F1rIXiCnc/t1+5IIWjbRGhWzo7RAwI5sRajn2sT4rRn9NXbOzZMvIqE4hmhmEzy1YQNDnfALAWNQ+WBbYGW+Vqm3IlQvAFFjVN1YYIdYhbLjAPdkgeVsWfcLDforHn6rR3QBZYZIlSBQSKRMY/tywTxeTCvK2zWcS0kbbFPtBcVth7VFFVPAZXhPi9yy1AvnldO6n7KLiupVmojlEMtv4FQkk604nal+j/dOplTATV8a9AJBbPRBZ/yQg57EG2Y2MRiHOQifJx0S5VbNyMm9bkS8TD7Goi59aCW6OT1gyeotWwLg60JRZTfyJ7lYWBSOzh0OnaCytRpSWtNZ6barPUeOnftbnJtE8rFhF7M4F66et0LI/cuvXYecwVwykovEVBKRF4HOK9GgSm17mQMtzrD7c558TbaucOWabYR04uhdAc3s10MkuONWG0wIQhgIChYVAGnFLvSpp2/aQEq3xrRSETxsixUIjsZyWWROkuA0IFnc8d7AmcnUBvRW7FT/5thWyk5agdYUGZ+7C1o69ihR1YxmoGh69fLMPIEOhYh572+3ckgl2SaV4uo9Gvkz8MMGRBcMIMlRirSwhCfozV2RyT5Wn1NgPpyc8zJL7QdOhL7Qxb+5WjnCVrQYHI2cCAwEAAQ==" + }, + }); + + let res = dispatch(&client, body, &logger); + assert_eq!(res.get("jsonrpc").unwrap(), "2.0"); + + let result = res.get("result").unwrap(); + let account_obj = result.get("account").unwrap(); + assert!(account_obj.get("account_id").is_some()); + assert_eq!(account_obj.get("name").unwrap(), "Alice Main Account"); + assert_eq!(account_obj.get("recovery_mode").unwrap(), false); + assert!(account_obj.get("main_address").is_some()); + assert_eq!(account_obj.get("next_subaddress_index").unwrap(), "1"); + assert_eq!(account_obj.get("fog_enabled").unwrap(), true); + } + #[test_with_logger] fn test_e2e_import_account(logger: Logger) { let mut rng: StdRng = SeedableRng::from_seed([20u8; 32]); @@ -173,6 +204,8 @@ mod e2e { *account_obj.get("first_block_index").unwrap(), serde_json::json!("200") ); + assert_eq!(account_obj.get("next_subaddress_index").unwrap(), "2"); + assert_eq!(account_obj.get("fog_enabled").unwrap(), false); } #[test_with_logger] @@ -242,6 +275,77 @@ mod e2e { *account_obj.get("first_block_index").unwrap(), serde_json::json!("200") ); + assert_eq!(account_obj.get("next_subaddress_index").unwrap(), "2"); + assert_eq!(account_obj.get("fog_enabled").unwrap(), false); + } + + #[test_with_logger] + fn test_e2e_import_account_fog(logger: Logger) { + let mut rng: StdRng = SeedableRng::from_seed([20u8; 32]); + let (client, _ledger_db, _db_ctx, _network_state) = setup(&mut rng, logger.clone()); + + // Import an account with fog info. + let body = json!({ + "jsonrpc": "2.0", + "id": 1, + "method": "import_account", + "params": { + "mnemonic": "sheriff odor square mistake huge skate mouse shoot purity weapon proof stuff correct concert blanket neck own shift clay mistake air viable stick group", + "key_derivation_version": "2", + "name": "Alice Main Account", + "first_block_index": "200", + "fog_report_url": "fog://fog-report.example.com", + "fog_report_id": "", + "fog_authority_spki": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvnB9wTbTOT5uoizRYaYbw7XIEkInl8E7MGOAQj+xnC+F1rIXiCnc/t1+5IIWjbRGhWzo7RAwI5sRajn2sT4rRn9NXbOzZMvIqE4hmhmEzy1YQNDnfALAWNQ+WBbYGW+Vqm3IlQvAFFjVN1YYIdYhbLjAPdkgeVsWfcLDforHn6rR3QBZYZIlSBQSKRMY/tywTxeTCvK2zWcS0kbbFPtBcVth7VFFVPAZXhPi9yy1AvnldO6n7KLiupVmojlEMtv4FQkk604nal+j/dOplTATV8a9AJBbPRBZ/yQg57EG2Y2MRiHOQifJx0S5VbNyMm9bkS8TD7Goi59aCW6OT1gyeotWwLg60JRZTfyJ7lYWBSOzh0OnaCytRpSWtNZ6barPUeOnftbnJtE8rFhF7M4F66et0LI/cuvXYecwVwykovEVBKRF4HOK9GgSm17mQMtzrD7c558TbaucOWabYR04uhdAc3s10MkuONWG0wIQhgIChYVAGnFLvSpp2/aQEq3xrRSETxsixUIjsZyWWROkuA0IFnc8d7AmcnUBvRW7FT/5thWyk5agdYUGZ+7C1o69ihR1YxmoGh69fLMPIEOhYh572+3ckgl2SaV4uo9Gvkz8MMGRBcMIMlRirSwhCfozV2RyT5Wn1NgPpyc8zJL7QdOhL7Qxb+5WjnCVrQYHI2cCAwEAAQ==" + } + }); + let res = dispatch(&client, body, &logger); + let result = res.get("result").unwrap(); + let account_obj = result.get("account").unwrap(); + let public_address = account_obj.get("main_address").unwrap().as_str().unwrap(); + assert_eq!(public_address, "2kD4vRp3DaBdRrNLNhJ5BKf5FsZxcAijoMt5pxjJpbk5jQRubngUXnd92vuXWkFyezuLgjCiKu4JHjpjNCnmzf1gAdW6PbqXsecQtp8Qr8uoeeDKrd1a5PtA6apXuDVtnrKsDCcHiJqdeSt3bRsPBvkBP4JqpGyAeKFsC7s2LQwuZ88BxFe2kyeZp5G3zENfvLaMripxTKkWGDopok2LCyA9NiCDf1vwjA5opLU7eqaRfh9"); + let account_id = account_obj.get("account_id").unwrap().as_str().unwrap(); + assert_eq!( + account_id, + "0b8a95253a7d57faf8510d8092ab55fb8610a9d691a7fa3bfafbf49945b845a2" + ); + + assert_eq!(account_obj.get("next_subaddress_index").unwrap(), "1"); + assert_eq!(account_obj.get("fog_enabled").unwrap(), true); + } + + #[test_with_logger] + fn test_e2e_import_account_legacy_fog(logger: Logger) { + let mut rng: StdRng = SeedableRng::from_seed([20u8; 32]); + let (client, _ledger_db, _db_ctx, _network_state) = setup(&mut rng, logger.clone()); + + let body = json!({ + "jsonrpc": "2.0", + "id": 1, + "method": "import_account_from_legacy_root_entropy", + "params": { + "entropy": "c593274dc6f6eb94242e34ae5f0ab16bc3085d45d49d9e18b8a8c6f057e6b56b", + "name": "Alice Main Account", + "first_block_index": "200", + "fog_report_url": "fog://fog-report.example.com", + "fog_report_id": "", + "fog_authority_spki": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvnB9wTbTOT5uoizRYaYbw7XIEkInl8E7MGOAQj+xnC+F1rIXiCnc/t1+5IIWjbRGhWzo7RAwI5sRajn2sT4rRn9NXbOzZMvIqE4hmhmEzy1YQNDnfALAWNQ+WBbYGW+Vqm3IlQvAFFjVN1YYIdYhbLjAPdkgeVsWfcLDforHn6rR3QBZYZIlSBQSKRMY/tywTxeTCvK2zWcS0kbbFPtBcVth7VFFVPAZXhPi9yy1AvnldO6n7KLiupVmojlEMtv4FQkk604nal+j/dOplTATV8a9AJBbPRBZ/yQg57EG2Y2MRiHOQifJx0S5VbNyMm9bkS8TD7Goi59aCW6OT1gyeotWwLg60JRZTfyJ7lYWBSOzh0OnaCytRpSWtNZ6barPUeOnftbnJtE8rFhF7M4F66et0LI/cuvXYecwVwykovEVBKRF4HOK9GgSm17mQMtzrD7c558TbaucOWabYR04uhdAc3s10MkuONWG0wIQhgIChYVAGnFLvSpp2/aQEq3xrRSETxsixUIjsZyWWROkuA0IFnc8d7AmcnUBvRW7FT/5thWyk5agdYUGZ+7C1o69ihR1YxmoGh69fLMPIEOhYh572+3ckgl2SaV4uo9Gvkz8MMGRBcMIMlRirSwhCfozV2RyT5Wn1NgPpyc8zJL7QdOhL7Qxb+5WjnCVrQYHI2cCAwEAAQ==" + } + }); + let res = dispatch(&client, body, &logger); + let result = res.get("result").unwrap(); + let account_obj = result.get("account").unwrap(); + let public_address = account_obj.get("main_address").unwrap().as_str().unwrap(); + assert_eq!(public_address, "d3FhtyUQDYJFpEmzoXmRtF9VA5FTLycgQBKf1JEJJj8K6UXCuwzGD2uVYw1cxzZpbSivZLSxf9nZpMgUnuRxSpJA9qCDpDZd2qtc7j2N2x4758dQ91jrSCxzyuR1aJR7zgdcgdF2KwSShUhQ5n7M9uebf2HqiCWt8vttqESJ7aRNDwiW8TVmeKWviWunzYG46c8vo4DeZYK4wFfLNdwmeSn9HXKkQVpNgzsMz87cKpHRnzn"); + let account_id = account_obj.get("account_id").unwrap().as_str().unwrap(); + // Catches if a change results in changed accounts_ids, which should always be + // made to be backward compatible. + assert_eq!( + account_id, + "9111a17691a1eecb85bbeaa789c69471e7c8b9789e0068de02204f9d7264263d" + ); + assert_eq!(account_obj.get("next_subaddress_index").unwrap(), "1"); + assert_eq!(account_obj.get("fog_enabled").unwrap(), true); } #[test_with_logger] @@ -401,57 +505,6 @@ mod e2e { ); } - #[test_with_logger] - fn test_e2e_import_account_fog(logger: Logger) { - let mut rng: StdRng = SeedableRng::from_seed([20u8; 32]); - let (client, _ledger_db, _db_ctx, _network_state) = setup(&mut rng, logger.clone()); - - // Import an account with fog info. - let body = json!({ - "jsonrpc": "2.0", - "id": 1, - "method": "import_account", - "params": { - "mnemonic": "sheriff odor square mistake huge skate mouse shoot purity weapon proof stuff correct concert blanket neck own shift clay mistake air viable stick group", - "key_derivation_version": "2", - "name": "Alice Main Account", - "first_block_index": "200", - "fog_report_url": "fog://fog-report.example.com", - "fog_report_id": "", - "fog_authority_spki": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvnB9wTbTOT5uoizRYaYbw7XIEkInl8E7MGOAQj+xnC+F1rIXiCnc/t1+5IIWjbRGhWzo7RAwI5sRajn2sT4rRn9NXbOzZMvIqE4hmhmEzy1YQNDnfALAWNQ+WBbYGW+Vqm3IlQvAFFjVN1YYIdYhbLjAPdkgeVsWfcLDforHn6rR3QBZYZIlSBQSKRMY/tywTxeTCvK2zWcS0kbbFPtBcVth7VFFVPAZXhPi9yy1AvnldO6n7KLiupVmojlEMtv4FQkk604nal+j/dOplTATV8a9AJBbPRBZ/yQg57EG2Y2MRiHOQifJx0S5VbNyMm9bkS8TD7Goi59aCW6OT1gyeotWwLg60JRZTfyJ7lYWBSOzh0OnaCytRpSWtNZ6barPUeOnftbnJtE8rFhF7M4F66et0LI/cuvXYecwVwykovEVBKRF4HOK9GgSm17mQMtzrD7c558TbaucOWabYR04uhdAc3s10MkuONWG0wIQhgIChYVAGnFLvSpp2/aQEq3xrRSETxsixUIjsZyWWROkuA0IFnc8d7AmcnUBvRW7FT/5thWyk5agdYUGZ+7C1o69ihR1YxmoGh69fLMPIEOhYh572+3ckgl2SaV4uo9Gvkz8MMGRBcMIMlRirSwhCfozV2RyT5Wn1NgPpyc8zJL7QdOhL7Qxb+5WjnCVrQYHI2cCAwEAAQ==" - } - }); - let res = dispatch(&client, body, &logger); - let result = res.get("result").unwrap(); - let account_obj = result.get("account").unwrap(); - let public_address = account_obj.get("main_address").unwrap().as_str().unwrap(); - assert_eq!(public_address, "2kD4vRp3DaBdRrNLNhJ5BKf5FsZxcAijoMt5pxjJpbk5jQRubngUXnd92vuXWkFyezuLgjCiKu4JHjpjNCnmzf1gAdW6PbqXsecQtp8Qr8uoeeDKrd1a5PtA6apXuDVtnrKsDCcHiJqdeSt3bRsPBvkBP4JqpGyAeKFsC7s2LQwuZ88BxFe2kyeZp5G3zENfvLaMripxTKkWGDopok2LCyA9NiCDf1vwjA5opLU7eqaRfh9"); - let account_id = account_obj.get("account_id").unwrap().as_str().unwrap(); - assert_eq!( - account_id, - "0b8a95253a7d57faf8510d8092ab55fb8610a9d691a7fa3bfafbf49945b845a2" - ); - - // Export account secrets and check fog info. - let body = json!({ - "jsonrpc": "2.0", - "id": 1, - "method": "export_account_secrets", - "params": { - "account_id": account_id, - } - }); - let res = dispatch(&client, body, &logger); - let result = res.get("result").unwrap(); - let secrets = result.get("account_secrets").unwrap(); - let account_key = secrets.get("account_key").unwrap(); - - assert_eq!( - *account_key.get("fog_report_url").unwrap(), - serde_json::json!("fog://fog-report.example.com") - ); - } - #[test_with_logger] fn test_e2e_get_balance(logger: Logger) { let mut rng: StdRng = SeedableRng::from_seed([20u8; 32]); @@ -1867,6 +1920,49 @@ mod e2e { assert_eq!(addresses_page[..], addresses_all[1..5]); } + #[test_with_logger] + fn test_next_subaddress_fails_with_fog(logger: Logger) { + use crate::db::WalletDbError::SubaddressesNotSupportedForFOGEnabledAccounts as subaddress_error; + + let mut rng: StdRng = SeedableRng::from_seed([20u8; 32]); + let (client, mut _ledger_db, _db_ctx, _network_state) = setup(&mut rng, logger.clone()); + + // Create Account + let body = json!({ + "jsonrpc": "2.0", + "id": 1, + "method": "create_account", + "params": { + "name": "Alice Main Account", + "fog_report_url": "fog://fog-report.example.com", + "fog_report_id": "", + "fog_authority_spki": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvnB9wTbTOT5uoizRYaYbw7XIEkInl8E7MGOAQj+xnC+F1rIXiCnc/t1+5IIWjbRGhWzo7RAwI5sRajn2sT4rRn9NXbOzZMvIqE4hmhmEzy1YQNDnfALAWNQ+WBbYGW+Vqm3IlQvAFFjVN1YYIdYhbLjAPdkgeVsWfcLDforHn6rR3QBZYZIlSBQSKRMY/tywTxeTCvK2zWcS0kbbFPtBcVth7VFFVPAZXhPi9yy1AvnldO6n7KLiupVmojlEMtv4FQkk604nal+j/dOplTATV8a9AJBbPRBZ/yQg57EG2Y2MRiHOQifJx0S5VbNyMm9bkS8TD7Goi59aCW6OT1gyeotWwLg60JRZTfyJ7lYWBSOzh0OnaCytRpSWtNZ6barPUeOnftbnJtE8rFhF7M4F66et0LI/cuvXYecwVwykovEVBKRF4HOK9GgSm17mQMtzrD7c558TbaucOWabYR04uhdAc3s10MkuONWG0wIQhgIChYVAGnFLvSpp2/aQEq3xrRSETxsixUIjsZyWWROkuA0IFnc8d7AmcnUBvRW7FT/5thWyk5agdYUGZ+7C1o69ihR1YxmoGh69fLMPIEOhYh572+3ckgl2SaV4uo9Gvkz8MMGRBcMIMlRirSwhCfozV2RyT5Wn1NgPpyc8zJL7QdOhL7Qxb+5WjnCVrQYHI2cCAwEAAQ==" + }, + }); + + let creation_res = dispatch(&client, body, &logger); + let creation_result = creation_res.get("result").unwrap(); + let account_obj = creation_result.get("account").unwrap(); + let account_id = account_obj.get("account_id").unwrap().as_str().unwrap(); + assert_eq!(creation_res.get("jsonrpc").unwrap(), "2.0"); + + // assign next subaddress for account + let body = json!({ + "jsonrpc": "2.0", + "id": 1, + "method": "assign_address_for_account", + "params": { + "account_id": account_id, + "metadata": "subaddress_index_2", + } + }); + let res = dispatch(&client, body, &logger); + let error = res.get("error").unwrap(); + let data = error.get("data").unwrap(); + let details = data.get("details").unwrap(); + assert!(details.to_string().contains(&subaddress_error.to_string())); + } + #[test_with_logger] fn test_import_account_with_next_subaddress_index(logger: Logger) { let mut rng: StdRng = SeedableRng::from_seed([20u8; 32]); @@ -3467,14 +3563,4 @@ mod e2e { let result = res["result"]["gift_codes"].as_array().unwrap(); assert_eq!(result.len(), 0); } - - // TODO - Add test to make sure fog account imports successfully with both - // import styles - - // TODO - Add test to make sure fog account creates successfully - - // TODO - Add test to make sure fog account sends change to main subaddress - // (index 0) - - // TODO - Add test to make sure fog accounts fail to assign next subaddress }