Commit 8c4ab891 authored by Jeremy Bokobza's avatar Jeremy Bokobza

Modofied the GetUnusedAddress a bit for Wallet recovery work

parent e125985c
...@@ -173,6 +173,34 @@ namespace Breeze.Wallet ...@@ -173,6 +173,34 @@ namespace Breeze.Wallet
/// </summary> /// </summary>
[JsonProperty(PropertyName = "internalAddresses")] [JsonProperty(PropertyName = "internalAddresses")]
public IEnumerable<HdAddress> InternalAddresses { get; set; } public IEnumerable<HdAddress> InternalAddresses { get; set; }
/// <summary>
/// Gets the type of coin this account is for.
/// </summary>
/// <returns>A <see cref="CoinType"/>.</returns>
public CoinType GetCoinType()
{
string[] pathElements = this.HdPath.Split('/');
int coinType = int.Parse(pathElements[2].Replace("'", string.Empty));
return (CoinType)coinType;
}
/// <summary>
/// Gets the first receiving address that contains no transaction.
/// </summary>
/// <returns>An unused address</returns>
public HdAddress GetFirstUnusedExternalAddress()
{
var unusedAddresses = this.ExternalAddresses.Where(acc => !acc.Transactions.Any()).ToList();
if (!unusedAddresses.Any())
{
return null;
}
// gets the unused address with the lowest index
var index = unusedAddresses.Min(a => a.Index);
return unusedAddresses.Single(a => a.Index == index);
}
} }
/// <summary> /// <summary>
......
...@@ -18,7 +18,7 @@ namespace Breeze.Wallet ...@@ -18,7 +18,7 @@ namespace Breeze.Wallet
{ {
public List<Wallet> Wallets { get; } public List<Wallet> Wallets { get; }
public HashSet<Script> PubKeys { get; } public HashSet<Script> PubKeys { get; set; }
public HashSet<TransactionDetails> TrackedTransactions { get; } public HashSet<TransactionDetails> TrackedTransactions { get; }
...@@ -142,7 +142,7 @@ namespace Breeze.Wallet ...@@ -142,7 +142,7 @@ namespace Breeze.Wallet
// get the extended pub key used to generate addresses for this account // get the extended pub key used to generate addresses for this account
var privateKey = Key.Parse(wallet.EncryptedSeed, password, wallet.Network); var privateKey = Key.Parse(wallet.EncryptedSeed, password, wallet.Network);
var seedExtKey = new ExtKey(privateKey, wallet.ChainCode); var seedExtKey = new ExtKey(privateKey, wallet.ChainCode);
var accountHdPath = $"m/44'/{(int) coinType}'/{newAccountIndex}'"; var accountHdPath = $"m/44'/{(int)coinType}'/{newAccountIndex}'";
KeyPath keyPath = new KeyPath(accountHdPath); KeyPath keyPath = new KeyPath(accountHdPath);
ExtKey accountExtKey = seedExtKey.Derive(keyPath); ExtKey accountExtKey = seedExtKey.Derive(keyPath);
ExtPubKey accountExtPubKey = accountExtKey.Neuter(); ExtPubKey accountExtPubKey = accountExtKey.Neuter();
...@@ -180,8 +180,6 @@ namespace Breeze.Wallet ...@@ -180,8 +180,6 @@ namespace Breeze.Wallet
throw new Exception($"No account with name {accountName} could be found."); throw new Exception($"No account with name {accountName} could be found.");
} }
int newAddressIndex = 0;
// validate address creation // validate address creation
if (account.ExternalAddresses.Any()) if (account.ExternalAddresses.Any())
{ {
...@@ -192,30 +190,63 @@ namespace Breeze.Wallet ...@@ -192,30 +190,63 @@ namespace Breeze.Wallet
{ {
return lastAddress.Address; return lastAddress.Address;
} }
}
// creates an address
this.CreateAddressesInAccount(account, wallet.Network, 1);
// persists the address to the wallet file
this.SaveToFile(wallet);
newAddressIndex = lastAddressIndex + 1; // adds the address to the list of tracked addresses
this.PubKeys = this.LoadKeys(coinType);
return account.GetFirstUnusedExternalAddress().Address;
}
/// <summary>
/// Creates a number of addresses in the provided account.
/// </summary>
/// <param name="account">The account.</param>
/// <param name="network">The network.</param>
/// <param name="addressesQuantity">The addresses quantity.</param>
/// <returns>A list of addresses in Base58.</returns>
private List<string> CreateAddressesInAccount(HdAccount account, Network network, int addressesQuantity)
{
List<string> addressesCreated = new List<string>();
// gets the index of the last address with transactions
int indexOfLastUsedAddress = 0;
if (account.ExternalAddresses.Any())
{
indexOfLastUsedAddress = account.ExternalAddresses.Where(a => a.Transactions.Any()).Max(add => add.Index);
}
for (int i = indexOfLastUsedAddress + 1; i <= indexOfLastUsedAddress + addressesQuantity; i++)
{
// skip over addresses that already exist
if (account.ExternalAddresses.ElementAtOrDefault(i) != null)
{
continue;
} }
// generate new receiving address // generate new receiving address
BitcoinPubKeyAddress address = this.GenerateAddress(account.ExtendedPubKey, newAddressIndex, false, wallet.Network); BitcoinPubKeyAddress address = this.GenerateAddress(account.ExtendedPubKey, i, false, network);
// add address details // add address details
account.ExternalAddresses = account.ExternalAddresses.Concat(new[] {new HdAddress account.ExternalAddresses = account.ExternalAddresses.Concat(new[] {new HdAddress
{ {
Index = newAddressIndex, Index = i,
HdPath = CreateBip44Path(coinType, account.Index, newAddressIndex, false), HdPath = CreateBip44Path(account.GetCoinType(), account.Index, i, false),
ScriptPubKey = address.ScriptPubKey, ScriptPubKey = address.ScriptPubKey,
Address = address.ToString(), Address = address.ToString(),
Transactions = new List<TransactionData>(), Transactions = new List<TransactionData>(),
CreationTime = DateTimeOffset.Now CreationTime = DateTimeOffset.Now
}}); }});
// persists the address to the wallet file addressesCreated.Add(address.ToString());
this.SaveToFile(wallet); }
// adds the address to the list of tracked addresses return addressesCreated;
this.PubKeys.Add(address.ScriptPubKey);
return address.ToString();
} }
public WalletGeneralInfoModel GetGeneralInfo(string name) public WalletGeneralInfoModel GetGeneralInfo(string name)
...@@ -318,7 +349,7 @@ namespace Breeze.Wallet ...@@ -318,7 +349,7 @@ namespace Breeze.Wallet
{ {
foreach (var account in accountRoot.Accounts) foreach (var account in accountRoot.Accounts)
{ {
foreach (var address in account.ExternalAddresses)//.Where(a => a.ScriptPubKey == script)) foreach (var address in account.ExternalAddresses.Where(a => a.ScriptPubKey == script))
{ {
address.Transactions = address.Transactions.Concat(new[] address.Transactions = address.Transactions.Concat(new[]
{ {
...@@ -498,9 +529,9 @@ namespace Breeze.Wallet ...@@ -498,9 +529,9 @@ namespace Breeze.Wallet
SelectMany(w => w.AccountsRoot.Where(a => a.CoinType == coinType)). SelectMany(w => w.AccountsRoot.Where(a => a.CoinType == coinType)).
SelectMany(a => a.Accounts). SelectMany(a => a.Accounts).
SelectMany(a => a.ExternalAddresses). SelectMany(a => a.ExternalAddresses).
//Select(s => s.ScriptPubKey)); Select(s => s.ScriptPubKey));
// uncomment the following for testing on a random address // uncomment the following for testing on a random address
Select(t => (new BitcoinPubKeyAddress(t.Address, Network.Main)).ScriptPubKey)); //Select(t => (new BitcoinPubKeyAddress(t.Address, Network.Main)).ScriptPubKey));
} }
/// <summary> /// <summary>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment