Skip to content
This repository has been archived by the owner on Aug 16, 2021. It is now read-only.

Commit

Permalink
[3.0.8.0] Added ability to scan through available accounts (#4222)
Browse files Browse the repository at this point in the history
* Added ledger support

* Fixed block explorer

* Added CL args

* Added a flag to ignore balance check

* Fixed explorer test

* Minor changes as per feedback

* Minor changes as per feedback

* Added global.json to lock the version

* DOwngraded to 2.1

* Removed unused tests

* Added keypath param for advanced users

* Fixed address scanning

* Fix for index

* Added more logs

* Added more logs

* Added logic to scan change addresses

* Added more logs

Co-authored-by: Igor Goldobin <[email protected]>
  • Loading branch information
fenix2222 and fenix2222 authored Feb 22, 2021
1 parent f28c425 commit f20c9ce
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 20 deletions.
15 changes: 15 additions & 0 deletions src/AddressOwnershipTool/AddressCheckResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace AddressOwnershipTool
{
public class AddressCheckResult
{
public AddressCheckResult(bool hasBalance, bool hasActivity)
{
this.HasActivity = hasActivity;
this.HasBalance = hasBalance;
}

public bool HasBalance { get; set; }

public bool HasActivity { get; set; }
}
}
12 changes: 11 additions & 1 deletion src/AddressOwnershipTool/BlockExplorerClient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Linq;
using System.Collections.Generic;
using Stratis.Bitcoin.Controllers.Models;

namespace AddressOwnershipTool
{
Expand All @@ -13,5 +15,13 @@ public bool HasBalance(string address)

return balance > 0;
}

public bool HasActivity(string address)
{
var stratisApiClient = new NodeApiClient($"{ExplorerBaseUrl}api");
List<AddressBalanceChange> changes = stratisApiClient.GetVerboseAddressBalance(address);

return changes.Any();
}
}
}
87 changes: 68 additions & 19 deletions src/AddressOwnershipTool/LedgerService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
Expand All @@ -16,6 +17,8 @@ public class LedgerService

private readonly BlockExplorerClient blockExplorerClient;

private const int maximumInactiveAddresses = 20;

public LedgerService(bool testnet)
{
this.network = testnet ? new StratisTest() : new StratisMain();
Expand All @@ -26,33 +29,44 @@ public async Task ExportAddressesAsync(int numberOfAddressesToScan, string desti
{
LedgerClient ledger = (await LedgerClient.GetHIDLedgersAsync()).First();

var numberOfIterations = string.IsNullOrEmpty(keyPath) ? numberOfAddressesToScan : 1;

// m / purpose' / coin_type' / account' / change / address_index
for (int index = 0; index < numberOfIterations; index++)
if (!string.IsNullOrEmpty(keyPath))
{
var key = new KeyPath(string.IsNullOrEmpty(keyPath) ? $"m/44'/105'/0'/0/{index}" : keyPath);
await ProcessAddressAsync(ledger, keyPath, ignoreBalance, destinationAddress);
return;
}

bool foundInactiveAccount = false;

GetWalletPubKeyResponse walletPubKey = await ledger.GetWalletPubKeyAsync(key);
for (int accountIndex = 0; !foundInactiveAccount; accountIndex++)
{
var addressChecks = new List<AddressCheckResult>();

PubKey pubKey = walletPubKey.ExtendedPublicKey.PubKey;
var address = walletPubKey.Address;
Console.WriteLine($"Checking addresses for m/44'/105'/{accountIndex}");

if (!ignoreBalance)
for (int addressIndex = 0; addressIndex < numberOfAddressesToScan; addressIndex++)
{
Console.WriteLine($"Checking balance for {address}");
if (!this.blockExplorerClient.HasBalance(address))
continue;
var currentKeyPath = $"m/44'/105'/{accountIndex}'/0/{addressIndex}";

AddressCheckResult addressCheckResult = await this.ProcessAddressAsync(ledger, currentKeyPath, ignoreBalance, destinationAddress);
addressChecks.Add(addressCheckResult);

if (addressIndex == maximumInactiveAddresses - 1 && addressChecks.All(a => !a.HasActivity))
{
foundInactiveAccount = true;
break;
}
}

await ledger.PrepareMessage(key, address);
var resp = await ledger.SignMessage();

var signature = GetSignature(address, resp, pubKey);
if (signature == null)

if (foundInactiveAccount)
continue;

this.OutputToFile(address, destinationAddress, signature);
// Now scan all change addresses if account was active
for (int addressIndex = 0; addressIndex < numberOfAddressesToScan; addressIndex++)
{
var currentKeyPath = $"m/44'/105'/{accountIndex}'/1/{addressIndex}";

await this.ProcessAddressAsync(ledger, currentKeyPath, ignoreBalance, destinationAddress);
}
}
}

Expand All @@ -68,6 +82,41 @@ public void OutputToFile(string address, string destinationAddress, string signa
}
}

private async Task<AddressCheckResult> ProcessAddressAsync(LedgerClient ledger, string keyPath, bool ignoreBalance, string destinationAddress)
{
var result = new AddressCheckResult(false, false);
var key = new KeyPath(keyPath);

GetWalletPubKeyResponse walletPubKey = await ledger.GetWalletPubKeyAsync(key);

PubKey pubKey = walletPubKey.ExtendedPublicKey.PubKey;
var address = walletPubKey.Address;

var hasActivity = this.blockExplorerClient.HasActivity(address);
result.HasActivity = hasActivity;

if (!ignoreBalance)
{
Console.WriteLine($"Checking balance for {address}");
if (!this.blockExplorerClient.HasBalance(address))
return result;

Console.WriteLine($"Balance Found for {keyPath} - Please confirm transaction on your ledger device.");
result.HasBalance = true;
}

await ledger.PrepareMessage(key, address);
var resp = await ledger.SignMessage();

var signature = GetSignature(address, resp, pubKey);
if (signature == null)
return result;

this.OutputToFile(address, destinationAddress, signature);

return result;
}

private string GetSignature(string address, byte[] resp, PubKey pubKey)
{
// Convert the ASN.1 signature into the proper format for NBitcoin/NStratis to validate in the ownership tool
Expand Down
15 changes: 15 additions & 0 deletions src/AddressOwnershipTool/NodeApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,21 @@ public decimal GetAddressBalance(string address)
return addressBalance.Balance.ToDecimal(MoneyUnit.Satoshi);
}

public List<AddressBalanceChange> GetVerboseAddressBalance(string address)
{
VerboseAddressBalancesResult result = $"{this.baseUrl}"
.AppendPathSegment("Blockstore/getverboseaddressesbalances")
.SetQueryParam("addresses", address)
.GetJsonAsync<VerboseAddressBalancesResult>().GetAwaiter().GetResult();

AddressIndexerData addressBalance = result.BalancesData.FirstOrDefault();

if (addressBalance == null)
return new List<AddressBalanceChange>();

return addressBalance.BalanceChanges;
}

public WalletBuildTransactionModel BuildTransaction(string walletName, string walletPassword, string accountName, List<RecipientModel> recipients)
{
var result = $"{this.baseUrl}"
Expand Down

0 comments on commit f20c9ce

Please sign in to comment.