diff --git a/Paymetheus.Bitcoin/Paymetheus.Bitcoin.csproj b/Paymetheus.Bitcoin/Paymetheus.Bitcoin.csproj
index 10d12aa..0cee54a 100644
--- a/Paymetheus.Bitcoin/Paymetheus.Bitcoin.csproj
+++ b/Paymetheus.Bitcoin/Paymetheus.Bitcoin.csproj
@@ -72,6 +72,7 @@
+
diff --git a/Paymetheus.Bitcoin/Util/TupleValue.cs b/Paymetheus.Bitcoin/Util/TupleValue.cs
new file mode 100644
index 0000000..c1fa243
--- /dev/null
+++ b/Paymetheus.Bitcoin/Util/TupleValue.cs
@@ -0,0 +1,46 @@
+// Copyright (c) 2016 The btcsuite developers
+// Licensed under the ISC license. See LICENSE file in the project root for full license information.
+
+namespace Paymetheus.Bitcoin.Util
+{
+ public struct TupleValue
+ {
+ public TupleValue(T1 item1, T2 item2)
+ {
+ Item1 = item1;
+ Item2 = item2;
+ }
+
+ public T1 Item1 { get; }
+ public T2 Item2 { get; }
+ }
+
+ public struct TupleValue
+ {
+ public TupleValue(T1 item1, T2 item2, T3 item3)
+ {
+ Item1 = item1;
+ Item2 = item2;
+ Item3 = item3;
+ }
+
+ public T1 Item1 { get; }
+ public T2 Item2 { get; }
+ public T3 Item3 { get; }
+ }
+
+ ///
+ /// TupleValue is an efficient alternative for the System.Tuple types. TupleValue is a
+ /// struct (value type) while Tuple is a class (reference type). A similar TupleValue struct
+ /// and tuple syntax sugar is planned for C# 7, which would eliminate the need for these
+ /// types if added.
+ ///
+ public static class TupleValue
+ {
+ public static TupleValue Create(T1 item1, T2 item2) =>
+ new TupleValue(item1, item2);
+
+ public static TupleValue Create(T1 item1, T2 item2, T3 item3) =>
+ new TupleValue(item1, item2, item3);
+ }
+}
diff --git a/Paymetheus.Bitcoin/Wallet/Wallet.cs b/Paymetheus.Bitcoin/Wallet/Wallet.cs
index b9c6969..258eb50 100644
--- a/Paymetheus.Bitcoin/Wallet/Wallet.cs
+++ b/Paymetheus.Bitcoin/Wallet/Wallet.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2016 The btcsuite developers
// Licensed under the ISC license. See LICENSE file in the project root for full license information.
+using Paymetheus.Bitcoin.Util;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -27,20 +28,26 @@ public sealed class Wallet
///
public const int MinRecentTransactions = 10;
- public Wallet(BlockChainIdentity activeChain, TransactionSet txSet, Dictionary accounts, BlockIdentity chainTip)
+ private const uint ImportedAccountNumber = 2147483647; // 2**31 - 1
+
+ public Wallet(BlockChainIdentity activeChain, TransactionSet txSet, List bip0032Accounts,
+ AccountProperties importedAccount, BlockIdentity chainTip)
{
if (activeChain == null)
throw new ArgumentNullException(nameof(activeChain));
- if (accounts == null)
- throw new ArgumentNullException(nameof(accounts));
+ if (bip0032Accounts == null)
+ throw new ArgumentNullException(nameof(bip0032Accounts));
+ if (importedAccount == null)
+ throw new ArgumentNullException(nameof(importedAccount));
if (chainTip == null)
throw new ArgumentNullException(nameof(chainTip));
- var totalBalance = accounts.Aggregate((Amount)0, (acc, kvp) => acc + kvp.Value.TotalBalance);
-
_transactionCount = txSet.MinedTransactions.Aggregate(0, (acc, b) => acc + b.Transactions.Count) +
txSet.UnminedTransactions.Count;
- _accounts = accounts;
+ _bip0032Accounts = bip0032Accounts;
+ _importedAccount = importedAccount;
+
+ var totalBalance = EnumerateAccounts().Aggregate((Amount)0, (acc, a) => acc + a.Item2.TotalBalance);
ActiveChain = activeChain;
RecentTransactions = txSet;
@@ -49,7 +56,8 @@ public Wallet(BlockChainIdentity activeChain, TransactionSet txSet, Dictionary _accounts;
+ private readonly List _bip0032Accounts;
+ private readonly AccountProperties _importedAccount;
public BlockChainIdentity ActiveChain { get; }
public TransactionSet RecentTransactions { get; }
@@ -64,7 +72,7 @@ private void AddTransactionToTotals(WalletTransaction tx, Dictionary _accounts[account];
+ public AccountProperties LookupAccountProperties(Account account)
+ {
+ if (account.AccountNumber == ImportedAccountNumber)
+ {
+ return _importedAccount;
+ }
+
+ var accountIndex = checked((int)account.AccountNumber);
+ return _bip0032Accounts[accountIndex];
+ }
- public string AccountName(Account account) => _accounts[account].AccountName;
+ public string AccountName(Account account) => LookupAccountProperties(account).AccountName;
- public IEnumerable> EnumrateAccounts() => _accounts;
+ public IEnumerable> EnumerateAccounts()
+ {
+ return _bip0032Accounts.Select((p, i) => TupleValue.Create(new Account((uint)i), p))
+ .Concat(new[] { TupleValue.Create(new Account(ImportedAccountNumber), _importedAccount) });
+ }
}
}
diff --git a/Paymetheus.Rpc/WalletClient.cs b/Paymetheus.Rpc/WalletClient.cs
index dd89832..6ece92a 100644
--- a/Paymetheus.Rpc/WalletClient.cs
+++ b/Paymetheus.Rpc/WalletClient.cs
@@ -411,20 +411,22 @@ public async Task> Synchronize(EventHandler new Account(a.AccountNumber),
- a => new AccountProperties
- {
- AccountName = a.AccountName,
- TotalBalance = a.TotalBalance,
- // TODO: uncomment when added to protospec and implemented by wallet.
- //ImmatureCoinbaseReward = a.ImmatureBalance,
- ExternalKeyCount = a.ExternalKeyCount,
- InternalKeyCount = a.InternalKeyCount,
- ImportedKeyCount = a.ImportedKeyCount,
- });
+ Func createProperties = a => new AccountProperties
+ {
+ AccountName = a.AccountName,
+ TotalBalance = a.TotalBalance,
+ // TODO: uncomment when added to protospec and implemented by wallet.
+ //ImmatureCoinbaseReward = a.ImmatureBalance,
+ ExternalKeyCount = a.ExternalKeyCount,
+ InternalKeyCount = a.InternalKeyCount,
+ ImportedKeyCount = a.ImportedKeyCount,
+ };
+ // This assumes that all but the last account listed in the RPC response are
+ // BIP0032 accounts, with the same account number as their List index.
+ var bip0032Accounts = rpcAccounts.Accounts.Take(rpcAccounts.Accounts.Count - 1).Select(createProperties).ToList();
+ var importedAccount = createProperties(rpcAccounts.Accounts.Last());
var chainTip = new BlockIdentity(lastAccountBlockHash, lastAccountBlockHeight);
- var wallet = new Wallet(activeBlockChain, txSet, accounts, chainTip);
+ var wallet = new Wallet(activeBlockChain, txSet, bip0032Accounts, importedAccount, chainTip);
wallet.ChangesProcessed += walletEventHandler;
var syncTask = Task.Run(async () =>
diff --git a/Paymetheus/RecentAccountViewModel.cs b/Paymetheus/RecentAccountViewModel.cs
index dbe613f..91dc5c3 100644
--- a/Paymetheus/RecentAccountViewModel.cs
+++ b/Paymetheus/RecentAccountViewModel.cs
@@ -18,30 +18,19 @@ public RecentAccountViewModel(ViewModelBase parent, Account account, AccountProp
throw new ArgumentNullException(nameof(properties));
Account = account;
- AccountName = properties.AccountName;
- Balance = properties.TotalBalance;
+ _accountProperties = properties;
}
+ private readonly AccountProperties _accountProperties;
+
public Account Account { get; }
- private string _accountName;
- public string AccountName
- {
- get { return _accountName; }
- set { if (_accountName != value) { _accountName = value; RaisePropertyChanged(); } }
- }
+ public string AccountName => _accountProperties.AccountName;
+ public string BalanceString => Denomination.Bitcoin.FormatAmount(_accountProperties.TotalBalance);
- private Amount _balance;
- public Amount Balance
+ public void NotifyPropertiesChanged()
{
- get { return _balance; }
- set
- {
- _balance = value;
- RaisePropertyChanged();
- RaisePropertyChanged(nameof(BalanceString));
- }
+ RaisePropertyChanged(nameof(AccountName));
+ RaisePropertyChanged(nameof(BalanceString));
}
-
- public string BalanceString => Denomination.Bitcoin.FormatAmount(Balance);
}
}
diff --git a/Paymetheus/ShellViewModel.cs b/Paymetheus/ShellViewModel.cs
index 21e7937..3ff7d13 100644
--- a/Paymetheus/ShellViewModel.cs
+++ b/Paymetheus/ShellViewModel.cs
@@ -120,8 +120,8 @@ private void OnSyncedWallet()
.Select(x => new TransactionViewModel(_wallet, x.Value, BlockIdentity.Unmined))
.Concat(txSet.MinedTransactions.ReverseList().SelectMany(b => b.Transactions.Select(tx => new TransactionViewModel(_wallet, tx, b.Identity))))
.Take(10);
- var recentAccounts = _wallet.EnumrateAccounts()
- .Select(a => new RecentAccountViewModel(this, a.Key, a.Value));
+ var recentAccounts = _wallet.EnumerateAccounts()
+ .Select(a => new RecentAccountViewModel(this, a.Item1, a.Item2));
Application.Current.Dispatcher.Invoke(() =>
{
foreach (var tx in recentTx)
@@ -139,8 +139,7 @@ private void NotifyRecalculatedBalances()
{
foreach (var recentAccount in RecentAccounts)
{
- var currentState = _wallet.LookupAccountProperties(recentAccount.Account);
- recentAccount.Balance = currentState.ZeroConfSpendableBalance;
+ recentAccount.NotifyPropertiesChanged();
}
RaisePropertyChanged(nameof(TotalBalance));
@@ -175,8 +174,7 @@ private void _wallet_ChangesProcessed(object sender, Wallet.ChangesProcessedEven
var recentAccountVM = RecentAccounts.FirstOrDefault(vm => vm.Account == account);
if (recentAccountVM != null)
{
- recentAccountVM.AccountName = state.AccountName;
- recentAccountVM.Balance = state.TotalBalance;
+ recentAccountVM.NotifyPropertiesChanged();
}
else
{