Skip to content

Commit

Permalink
Implement Zcash sync process
Browse files Browse the repository at this point in the history
  • Loading branch information
cypt4 committed Dec 13, 2024
1 parent f6393b6 commit 18c98c3
Show file tree
Hide file tree
Showing 68 changed files with 2,826 additions and 506 deletions.
16 changes: 14 additions & 2 deletions components/brave_wallet/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,12 @@ static_library("browser") {
"wallet_data_files_installer.cc",
"wallet_data_files_installer.h",
"wallet_data_files_installer_delegate.h",
"zcash/zcash_action_context.cc",
"zcash/zcash_action_context.h",
"zcash/zcash_block_tracker.cc",
"zcash/zcash_block_tracker.h",
"zcash/zcash_complete_transaction_task.cc",
"zcash/zcash_complete_transaction_task.h",
"zcash/zcash_create_transparent_transaction_task.cc",
"zcash/zcash_create_transparent_transaction_task.h",
"zcash/zcash_discover_next_unused_zcash_address_task.cc",
Expand All @@ -242,8 +246,6 @@ static_library("browser") {
"zcash/zcash_serializer.h",
"zcash/zcash_transaction.cc",
"zcash/zcash_transaction.h",
"zcash/zcash_transaction_complete_manager.cc",
"zcash/zcash_transaction_complete_manager.h",
"zcash/zcash_transaction_utils.cc",
"zcash/zcash_transaction_utils.h",
"zcash/zcash_tx_manager.cc",
Expand Down Expand Up @@ -312,10 +314,20 @@ static_library("browser") {

if (enable_orchard) {
sources += [
"zcash/zcash_blocks_batch_scan_task.cc",
"zcash/zcash_blocks_batch_scan_task.h",
"zcash/zcash_create_shield_transaction_task.cc",
"zcash/zcash_create_shield_transaction_task.h",
"zcash/zcash_create_shielded_transaction_task.cc",
"zcash/zcash_create_shielded_transaction_task.h",
"zcash/zcash_scan_blocks_task.cc",
"zcash/zcash_scan_blocks_task.h",
"zcash/zcash_shield_sync_service.cc",
"zcash/zcash_shield_sync_service.h",
"zcash/zcash_update_subtree_roots_task.cc",
"zcash/zcash_update_subtree_roots_task.h",
"zcash/zcash_verify_chain_state_task.cc",
"zcash/zcash_verify_chain_state_task.h",
]

deps += [
Expand Down
4 changes: 4 additions & 0 deletions components/brave_wallet/browser/internal/hd_key_zip32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@ OrchardFullViewKey HDKeyZip32::GetFullViewKey() {
return orchard_extended_spending_key_->GetFullViewKey();
}

OrchardSpendingKey HDKeyZip32::GetSpendingKey() {
return orchard_extended_spending_key_->GetSpendingKey();
}

} // namespace brave_wallet
2 changes: 2 additions & 0 deletions components/brave_wallet/browser/internal/hd_key_zip32.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class HDKeyZip32 {
// Full view key(fvk) is used to decode incoming transactions
OrchardFullViewKey GetFullViewKey();

OrchardSpendingKey GetSpendingKey();

private:
explicit HDKeyZip32(std::unique_ptr<orchard::OrchardExtendedSpendingKey> key);
// Extended spending key is a root key of an account, all other keys can be
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ std::optional<size_t> OrchardBundleManager::random_seed_for_testing_ =
// static
std::unique_ptr<OrchardBundleManager> OrchardBundleManager::Create(
base::span<const uint8_t> tree_state,
const OrchardSpendsBundle& spends_bundle,
const std::vector<OrchardOutput>& orchard_outputs) {
if (orchard_outputs.empty()) {
return nullptr;
}
auto bundle = orchard::OrchardUnauthorizedBundle::Create(
tree_state, orchard_outputs, random_seed_for_testing_);
tree_state, spends_bundle, orchard_outputs, random_seed_for_testing_);
if (!bundle) {
return nullptr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class OrchardBundleManager {
// Returns in unauthorized state
static std::unique_ptr<OrchardBundleManager> Create(
base::span<const uint8_t> tree_state,
const OrchardSpendsBundle& spends_bundle,
const std::vector<OrchardOutput>& orchard_outputs);

static void OverrideRandomSeedForTesting(size_t seed) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ TEST(OrchardBundleManagerTest, SingleOutput) {
127, 239, 163, 246, 227, 18, 158, 164, 223, 176, 169, 233, 135, 3, 166,
61, 171, 146, 149, 137, 214, 220, 81, 201, 112, 249, 53, 179}});

auto unauthorized_state =
OrchardBundleManager::Create(std::vector<uint8_t>(), std::move(outputs));
OrchardSpendsBundle orchard_spends_bundle;
auto unauthorized_state = OrchardBundleManager::Create(
std::vector<uint8_t>(), orchard_spends_bundle, std::move(outputs));
EXPECT_TRUE(unauthorized_state);
// Unauthorized state doesn't have raw tx bytes
EXPECT_FALSE(unauthorized_state->GetRawTxBytes());
Expand Down Expand Up @@ -324,8 +325,9 @@ TEST(OrchardBundleManagerTest, MultiplyOutputs) {
0x91, 0xd7, 0x34, 0xdf, 0x12, 0xd0, 0x46, 0xc9, 0x69, 0x75, 0x13,
0x30, 0xbb, 0xf4, 0x93, 0xa2, 0x41, 0xec, 0x4b, 0x88, 0xbc}});

auto unauthorized_state =
OrchardBundleManager::Create(std::vector<uint8_t>(), std::move(outputs));
OrchardSpendsBundle orchard_spends_bundle;
auto unauthorized_state = OrchardBundleManager::Create(
std::vector<uint8_t>(), orchard_spends_bundle, std::move(outputs));
EXPECT_TRUE(unauthorized_state);
// Unauthorized state doesn't have raw tx bytes
EXPECT_FALSE(unauthorized_state->GetRawTxBytes());
Expand Down Expand Up @@ -602,9 +604,11 @@ TEST(OrchardBundleManagerTest, MultiplyOutputs) {
TEST(OrchardBundleManagerTest, NoOutputs) {
OrchardBundleManager::OverrideRandomSeedForTesting(0);

OrchardSpendsBundle orchard_spends_bundle;
std::vector<OrchardOutput> outputs;
auto unauthorized_state = OrchardBundleManager::Create(
std::vector<uint8_t>(), std::vector<OrchardOutput>());
std::vector<uint8_t>(), orchard_spends_bundle,
std::vector<OrchardOutput>());
EXPECT_FALSE(unauthorized_state);
}

Expand Down
25 changes: 25 additions & 0 deletions components/brave_wallet/browser/internal/orchard_sync_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,31 @@ OrchardSyncState::CalculateWitnessForCheckpoint(
return base::ok(std::move(result));
}

base::expected<std::optional<uint32_t>, OrchardStorage::Error>
OrchardSyncState::GetLatestShardIndex(const mojom::AccountIdPtr& account_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return storage_.GetLatestShardIndex(account_id);
}

base::expected<std::optional<uint32_t>, OrchardStorage::Error>
OrchardSyncState::GetMaxCheckpointedHeight(
const mojom::AccountIdPtr& account_id,
uint32_t chain_tip_height,
uint32_t min_confirmations) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return storage_.GetMaxCheckpointedHeight(account_id, chain_tip_height,
min_confirmations);
}

base::expected<OrchardStorage::Result, OrchardStorage::Error>
OrchardSyncState::UpdateSubtreeRoots(
const mojom::AccountIdPtr& account_id,
uint32_t start_index,
const std::vector<zcash::mojom::SubtreeRootPtr>& roots) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return storage_.UpdateSubtreeRoots(account_id, start_index, roots);
}

void OrchardSyncState::ResetDatabase() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
storage_.ResetDatabase();
Expand Down
13 changes: 13 additions & 0 deletions components/brave_wallet/browser/internal/orchard_sync_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ class OrchardSyncState {
const uint32_t latest_scanned_block,
const std::string& latest_scanned_block_hash);

base::expected<std::optional<uint32_t>, OrchardStorage::Error>
GetLatestShardIndex(const mojom::AccountIdPtr& account_id);

base::expected<std::optional<uint32_t>, OrchardStorage::Error>
GetMaxCheckpointedHeight(const mojom::AccountIdPtr& account_id,
uint32_t chain_tip_height,
uint32_t min_confirmations);

base::expected<OrchardStorage::Result, OrchardStorage::Error>
UpdateSubtreeRoots(const mojom::AccountIdPtr& account_id,
uint32_t start_index,
const std::vector<zcash::mojom::SubtreeRootPtr>& roots);

// Clears sync data related to the account except it's birthday.
base::expected<OrchardStorage::Result, OrchardStorage::Error>
ResetAccountSyncState(const mojom::AccountIdPtr& account_id);
Expand Down
11 changes: 11 additions & 0 deletions components/brave_wallet/browser/keyring_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2212,6 +2212,17 @@ std::optional<OrchardFullViewKey> KeyringService::GetOrchardFullViewKey(

return zcash_keyring->GetOrchardFullViewKey(account_id->account_index);
}

std::optional<OrchardSpendingKey> KeyringService::GetOrchardSpendingKey(
const mojom::AccountIdPtr& account_id) {
auto* zcash_keyring = GetZCashKeyringById(account_id->keyring_id);
if (!zcash_keyring) {
return std::nullopt;
}

return zcash_keyring->GetOrchardSpendingKey(account_id->account_index);
}

#endif

void KeyringService::UpdateNextUnusedAddressForBitcoinAccount(
Expand Down
2 changes: 2 additions & 0 deletions components/brave_wallet/browser/keyring_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ class KeyringService : public mojom::KeyringService {
const mojom::ZCashKeyIdPtr& key_id);
std::optional<OrchardFullViewKey> GetOrchardFullViewKey(
const mojom::AccountIdPtr& account_id);
std::optional<OrchardSpendingKey> GetOrchardSpendingKey(
const mojom::AccountIdPtr& account_id);
#endif

const std::vector<mojom::AccountInfoPtr>& GetAllAccountInfos();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#include "brave/components/brave_wallet/browser/zcash/rust/extended_spending_key_impl.h"

#include <utility>

#include "base/memory/ptr_util.h"

namespace brave_wallet::orchard {

ExtendedSpendingKeyImpl::ExtendedSpendingKeyImpl(
absl::variant<base::PassKey<class ExtendedSpendingKey>,
base::PassKey<class ExtendedSpendingKeyImpl>>,
rust::Box<CxxOrchardExtendedSpendingKey> esk)
: extended_spending_key_(std::move(esk)) {}

ExtendedSpendingKeyImpl::~ExtendedSpendingKeyImpl() = default;

std::unique_ptr<ExtendedSpendingKey>
ExtendedSpendingKeyImpl::DeriveHardenedChild(uint32_t index) {
auto esk = extended_spending_key_->derive(index);
if (esk->is_ok()) {
return std::make_unique<ExtendedSpendingKeyImpl>(
base::PassKey<class ExtendedSpendingKeyImpl>(), esk->unwrap());
}
return nullptr;
}

std::optional<OrchardAddrRawPart>
ExtendedSpendingKeyImpl::GetDiversifiedAddress(uint32_t div_index,
OrchardAddressKind kind) {
return kind == OrchardAddressKind::External
? extended_spending_key_->external_address(div_index)
: extended_spending_key_->internal_address(div_index);
}

// static
std::unique_ptr<ExtendedSpendingKey> ExtendedSpendingKey::GenerateFromSeed(
base::span<const uint8_t> seed) {
auto mk = generate_orchard_extended_spending_key_from_seed(
rust::Slice<const uint8_t>{seed.data(), seed.size()});
if (mk->is_ok()) {
return std::make_unique<ExtendedSpendingKeyImpl>(
base::PassKey<class ExtendedSpendingKey>(), mk->unwrap());
}
return nullptr;
}

OrchardFullViewKey ExtendedSpendingKeyImpl::GetFullViewKey() {
return extended_spending_key_->full_view_key();
}

OrchardSpendingKey ExtendedSpendingKeyImpl::GetSpendingKey() {
return extended_spending_key_->spending_key();
}

} // namespace brave_wallet::orchard
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class OrchardExtendedSpendingKey {
uint32_t div_index,
OrchardAddressKind kind) = 0;

virtual OrchardSpendingKey GetSpendingKey() = 0;

virtual OrchardFullViewKey GetFullViewKey() = 0;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,8 @@ OrchardFullViewKey OrchardExtendedSpendingKeyImpl::GetFullViewKey() {
return cxx_extended_spending_key_->full_view_key();
}

OrchardSpendingKey OrchardExtendedSpendingKeyImpl::GetSpendingKey() {
return cxx_extended_spending_key_->spending_key();
}

} // namespace brave_wallet::orchard
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class OrchardExtendedSpendingKeyImpl : public OrchardExtendedSpendingKey {

OrchardFullViewKey GetFullViewKey() override;

OrchardSpendingKey GetSpendingKey() override;

private:
// Extended spending key is a root key of an account, all other keys can be
// derived from esk
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class OrchardUnauthorizedBundle {
// Creates OrchardUnauthorizedBundle without shielded inputs
static std::unique_ptr<OrchardUnauthorizedBundle> Create(
base::span<const uint8_t> tree_state,
const ::brave_wallet::OrchardSpendsBundle& orchard_spends,
const std::vector<::brave_wallet::OrchardOutput>& orchard_outputs,
std::optional<size_t> random_seed_for_testing);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,27 @@ OrchardUnauthorizedBundleImpl::~OrchardUnauthorizedBundleImpl() = default;
// static
std::unique_ptr<OrchardUnauthorizedBundle> OrchardUnauthorizedBundle::Create(
base::span<const uint8_t> tree_state,
const ::brave_wallet::OrchardSpendsBundle& orchard_spends,
const std::vector<::brave_wallet::OrchardOutput>& orchard_outputs,
std::optional<size_t> random_seed_for_testing) {
::rust::Vec<orchard::CxxOrchardSpend> spends;
for (const auto& input : orchard_spends.inputs) {
if (!input.witness) {
return nullptr;
}

auto& note = input.note;

orchard::CxxMerklePath merkle_path;
merkle_path.position = input.witness->position;
for (const auto& merkle_hash : input.witness->merkle_path) {
merkle_path.auth_path.push_back(orchard::CxxMerkleHash{merkle_hash});
}
spends.push_back(orchard::CxxOrchardSpend{
orchard_spends.fvk, orchard_spends.sk, note.amount, note.addr, note.rho,
note.seed, std::move(merkle_path)});
}

::rust::Vec<orchard::CxxOrchardOutput> outputs;
for (const auto& output : orchard_outputs) {
outputs.push_back(orchard::CxxOrchardOutput{
Expand All @@ -39,8 +58,7 @@ std::unique_ptr<OrchardUnauthorizedBundle> OrchardUnauthorizedBundle::Create(
CHECK_IS_TEST();
auto bundle_result = create_testing_orchard_bundle(
::rust::Slice<const uint8_t>{tree_state.data(), tree_state.size()},
::rust::Vec<::brave_wallet::orchard::CxxOrchardSpend>(),
std::move(outputs), random_seed_for_testing.value());
std::move(spends), std::move(outputs), random_seed_for_testing.value());
if (!bundle_result->is_ok()) {
return nullptr;
}
Expand All @@ -50,8 +68,7 @@ std::unique_ptr<OrchardUnauthorizedBundle> OrchardUnauthorizedBundle::Create(
} else {
auto bundle_result = create_orchard_bundle(
::rust::Slice<const uint8_t>{tree_state.data(), tree_state.size()},
::rust::Vec<::brave_wallet::orchard::CxxOrchardSpend>(),
std::move(outputs));
std::move(spends), std::move(outputs));
if (!bundle_result->is_ok()) {
return nullptr;
}
Expand Down
28 changes: 28 additions & 0 deletions components/brave_wallet/browser/zcash/zcash_action_context.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

#include "brave/components/brave_wallet/browser/zcash/zcash_action_context.h"

namespace brave_wallet {

ZCashActionContext::ZCashActionContext(ZCashRpc& zcash_rpc,
#if BUILDFLAG(ENABLE_ORCHARD)
base::SequenceBound<OrchardSyncState>& sync_state,
#endif // BUILDFLAG(ENABLE_ORCHARD)
const mojom::AccountIdPtr& account_id,
const std::string& chain_id) :
zcash_rpc(zcash_rpc),
#if BUILDFLAG(ENABLE_ORCHARD)
sync_state(sync_state),
#endif // BUILDFLAG(ENABLE_ORCHARD)
account_id(account_id.Clone()),
chain_id(chain_id) {}

ZCashActionContext& ZCashActionContext::operator=(ZCashActionContext&&) = default;
ZCashActionContext::ZCashActionContext(ZCashActionContext&&) = default;

ZCashActionContext::~ZCashActionContext() = default;

} // namespace brave_wallet
Loading

0 comments on commit 18c98c3

Please sign in to comment.