Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding multisig wallet #354

Open
wants to merge 24 commits into
base: multisig-wallet
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
30b6405
Added multisig wallet
rodendron-xrhodium Sep 17, 2021
1cd6679
Extracting root account interface so that it can be substituted
rodendron-xrhodium Sep 17, 2021
3121132
Extracting account interface so that it can be substituted
rodendron-xrhodium Sep 17, 2021
39459b3
Adding multisig scheme class
rodendron-xrhodium Sep 17, 2021
f8e60a4
Testing multisig address derivation
rodendron-xrhodium Sep 17, 2021
736a8a4
Changing wallet class use interfaces instead of concrete classes
rodendron-xrhodium Sep 17, 2021
8480e28
Integrating multisig wallet and interfaces into wallet manager
rodendron-xrhodium Sep 17, 2021
912b880
Walletmanager should prefer dealing with interface based objects
rodendron-xrhodium Sep 17, 2021
3762664
Refactoring to use interfaces instead of concrete classes.
rodendron-xrhodium Sep 17, 2021
e49168f
Refactoring to use interfaces instead of concrete classes.
rodendron-xrhodium Sep 17, 2021
6f36959
Refactoring to use interfaces instead of concrete classes
rodendron-xrhodium Sep 17, 2021
8b3b554
Handling strange build problems.
rodendron-xrhodium Sep 17, 2021
cb57401
Handling strange build problems again
rodendron-xrhodium Sep 17, 2021
65faa2d
Refactored to use interface collection instead of concreted class.
rodendron-xrhodium Sep 17, 2021
f6a6ff8
Added create multisig wallet operation to IWalletManager interface.
rodendron-xrhodium Sep 29, 2021
4326068
Added explicit network parameter to GeneratePublicKey with default nu…
rodendron-xrhodium Sep 29, 2021
210650d
Created transaction hex response model for wallet RPCs.
rodendron-xrhodium Sep 29, 2021
0e93ac6
Changed HD paths back to m/44' from m/45' as this was breaking privat…
rodendron-xrhodium Sep 29, 2021
a5e4b00
Cleand up imports /usings.
rodendron-xrhodium Sep 29, 2021
982f81e
Updated CreateMutisigWallet to use seed and xpubs as previous version…
rodendron-xrhodium Sep 29, 2021
978c3d9
Modified tests to verify private key + (n)xpub multisig wallet.
rodendron-xrhodium Sep 29, 2021
5950514
Modified tests to verify private key + (n)xpub multisig wallet.
rodendron-xrhodium Sep 29, 2021
a3e7c1e
Added RPCs to create multisig wallet, create multisig transctions, co…
rodendron-xrhodium Sep 29, 2021
f1b3066
Bug fix for null LastBlockSynchedHash after creating new wallet
rodendron-xrhodium Jan 29, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,15 @@ private void AddComponentStats(StringBuilder benchLog)
{
// Get all the accounts, including the ones used for cold staking.
// TODO: change GetAccounts to accept a filter.
foreach (HdAccount account in this.coldStakingManager.GetAccounts(walletName))
foreach (IHdAccount account in this.coldStakingManager.GetAccounts(walletName))
{
AccountBalance accountBalance = this.coldStakingManager.GetBalances(walletName, account.Name).Single();
benchLog.AppendLine(($"{walletName}/{account.Name}" + ",").PadRight(LoggingConfiguration.ColumnLength + 20)
+ (" Confirmed balance: " + accountBalance.AmountConfirmed.ToString()).PadRight(LoggingConfiguration.ColumnLength + 20)
+ " Unconfirmed balance: " + accountBalance.AmountUnconfirmed.ToString());
}

HdAccount coldStakingAccount = this.coldStakingManager.GetColdStakingAccount(this.coldStakingManager.GetWallet(walletName), true);
IHdAccount coldStakingAccount = this.coldStakingManager.GetColdStakingAccount(this.coldStakingManager.GetWallet(walletName), true);
if (coldStakingAccount != null)
{
AccountBalance accountBalance = this.coldStakingManager.GetBalances(walletName, coldStakingAccount.Name).Single();
Expand All @@ -181,7 +181,7 @@ private void AddComponentStats(StringBuilder benchLog)
+ " Unconfirmed balance: " + accountBalance.AmountUnconfirmed.ToString());
}

HdAccount hotStakingAccount = this.coldStakingManager.GetColdStakingAccount(this.coldStakingManager.GetWallet(walletName), false);
IHdAccount hotStakingAccount = this.coldStakingManager.GetColdStakingAccount(this.coldStakingManager.GetWallet(walletName), false);
if (hotStakingAccount != null)
{
AccountBalance accountBalance = this.coldStakingManager.GetBalances(walletName, hotStakingAccount.Name).Single();
Expand Down
20 changes: 10 additions & 10 deletions src/Features/Blockcore.Features.ColdStaking/ColdStakingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,10 @@ public GetColdStakingInfoResponse GetColdStakingInfo(string walletName)
/// <param name="wallet">The wallet where we wish to create the account.</param>
/// <param name="isColdWalletAccount">Indicates whether we need the cold wallet account (versus the hot wallet account).</param>
/// <returns>The cold staking account or <c>null</c> if the account does not exist.</returns>
public HdAccount GetColdStakingAccount(Wallet.Types.Wallet wallet, bool isColdWalletAccount)
public IHdAccount GetColdStakingAccount(Wallet.Types.Wallet wallet, bool isColdWalletAccount)
{
var coinType = wallet.Network.Consensus.CoinType;
HdAccount account = wallet.GetAccount(isColdWalletAccount ? ColdWalletAccountName : HotWalletAccountName);
IHdAccount account = wallet.GetAccount(isColdWalletAccount ? ColdWalletAccountName : HotWalletAccountName);
if (account == null)
{
this.logger.LogTrace("(-)[ACCOUNT_DOES_NOT_EXIST]:null");
Expand All @@ -213,11 +213,11 @@ public HdAccount GetColdStakingAccount(Wallet.Types.Wallet wallet, bool isColdWa
/// <param name="isColdWalletAccount">Indicates whether we need the cold wallet account (versus the hot wallet account).</param>
/// <param name="walletPassword">The wallet password which will be used to create the account.</param>
/// <returns>The new or existing cold staking account.</returns>
public HdAccount GetOrCreateColdStakingAccount(string walletName, bool isColdWalletAccount, string walletPassword)
public IHdAccount GetOrCreateColdStakingAccount(string walletName, bool isColdWalletAccount, string walletPassword)
{
Wallet.Types.Wallet wallet = this.GetWalletByName(walletName);

HdAccount account = this.GetColdStakingAccount(wallet, isColdWalletAccount);
IHdAccount account = this.GetColdStakingAccount(wallet, isColdWalletAccount);
if (account != null)
{
this.logger.LogTrace("(-)[ACCOUNT_ALREADY_EXIST]:'{0}'", account.Name);
Expand Down Expand Up @@ -279,7 +279,7 @@ internal HdAddress GetFirstUnusedColdStakingAddress(string walletName, bool isCo
Guard.NotNull(walletName, nameof(walletName));

Wallet.Types.Wallet wallet = this.GetWalletByName(walletName);
HdAccount account = this.GetColdStakingAccount(wallet, isColdWalletAddress);
IHdAccount account = this.GetColdStakingAccount(wallet, isColdWalletAddress);
if (account == null)
{
this.logger.LogTrace("(-)[ACCOUNT_DOES_NOT_EXIST]:null");
Expand Down Expand Up @@ -340,8 +340,8 @@ internal Transaction GetColdStakingSetupTransaction(IWalletTransactionHandler wa
Wallet.Types.Wallet wallet = this.GetWalletByName(walletName);

// Get/create the cold staking accounts.
HdAccount coldAccount = this.GetOrCreateColdStakingAccount(walletName, true, walletPassword);
HdAccount hotAccount = this.GetOrCreateColdStakingAccount(walletName, false, walletPassword);
IHdAccount coldAccount = this.GetOrCreateColdStakingAccount(walletName, true, walletPassword);
IHdAccount hotAccount = this.GetOrCreateColdStakingAccount(walletName, false, walletPassword);

HdAddress coldAddress = coldAccount?.ExternalAddresses.FirstOrDefault(s => s.Address == coldWalletAddress || s.Bech32Address == coldWalletAddress);
HdAddress hotAddress = hotAccount?.ExternalAddresses.FirstOrDefault(s => s.Address == hotWalletAddress || s.Bech32Address == hotWalletAddress);
Expand Down Expand Up @@ -474,7 +474,7 @@ internal Transaction GetColdStakingWithdrawalTransaction(IWalletTransactionHandl
Wallet.Types.Wallet wallet = this.GetWalletByName(walletName);

// Get the cold staking account.
HdAccount coldAccount = this.GetColdStakingAccount(wallet, true);
IHdAccount coldAccount = this.GetColdStakingAccount(wallet, true);
if (coldAccount == null)
{
this.logger.LogTrace("(-)[COLDSTAKE_ACCOUNT_DOES_NOT_EXIST]");
Expand All @@ -488,7 +488,7 @@ internal Transaction GetColdStakingWithdrawalTransaction(IWalletTransactionHandl
throw new WalletException("You can't send the money to a cold staking cold wallet account.");
}

HdAccount hotAccount = this.GetColdStakingAccount(wallet, false);
IHdAccount hotAccount = this.GetColdStakingAccount(wallet, false);
if (hotAccount != null && hotAccount.ExternalAddresses.Concat(hotAccount.InternalAddresses).Any(s => s.Address == receivingAddress || s.Bech32Address == receivingAddress))
{
this.logger.LogTrace("(-)[COLDSTAKE_INVALID_HOT_WALLET_ADDRESS_USAGE]");
Expand Down Expand Up @@ -599,7 +599,7 @@ public IEnumerable<UnspentOutputReference> GetSpendableTransactionsInColdWallet(
/// </summary>
/// <param name="script">The script (possibly a cold staking script) to check.</param>
/// <param name="accountFilter">The account filter.</param>
public override void TransactionFoundInternal(Wallet.Types.Wallet wallet, Script script, Func<HdAccount, bool> accountFilter = null)
public override void TransactionFoundInternal(Wallet.Types.Wallet wallet, Script script, Func<IHdAccount, bool> accountFilter = null)
{
if (ColdStakingScriptTemplate.Instance.ExtractScriptPubKeyParameters(script, out KeyId hotPubKeyHash, out KeyId coldPubKeyHash))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ internal WalletAccountReference GetAccount()
throw new Exception(noWalletMessage);
}

HdAccount account = this.walletManager.GetAccounts(walletName).FirstOrDefault();
IHdAccount account = this.walletManager.GetAccounts(walletName).FirstOrDefault();
if (account == null)
{
this.logger.LogError(ExceptionOccurredMessage, noAccountMessage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ private WalletAccountReference GetAccount()
if (walletName == null)
throw new RPCServerException(RPCErrorCode.RPC_INVALID_REQUEST, "No wallet found");

HdAccount account = this.walletManager.GetAccounts(walletName).FirstOrDefault();
IHdAccount account = this.walletManager.GetAccounts(walletName).FirstOrDefault();
if (account == null)
throw new RPCServerException(RPCErrorCode.RPC_INVALID_REQUEST, "No account found on wallet");

Expand Down
2 changes: 1 addition & 1 deletion src/Features/Blockcore.Features.PoA/PoAMiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ private Script GetScriptPubKeyFromWallet()
if (walletName == null)
return null;

HdAccount account = this.walletManager.GetAccounts(walletName).FirstOrDefault();
IHdAccount account = this.walletManager.GetAccounts(walletName).FirstOrDefault();

if (account == null)
return null;
Expand Down
16 changes: 8 additions & 8 deletions src/Features/Blockcore.Features.RPC/RPCMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public async Task InvokeAsync(HttpContext httpContext)
throw new NotImplementedException("The request is not supported.");
}

httpContext.Response.ContentType = ContentType;
httpContext.Response.ContentType = this.ContentType;

// Write the response body.
using (StreamWriter streamWriter = new StreamWriter(httpContext.Response.Body, Encoding.Default, 1024, true))
Expand Down Expand Up @@ -134,44 +134,44 @@ private async Task HandleRpcInvokeExceptionAsync(HttpContext httpContext, Except
if (ex is ArgumentException || ex is FormatException)
{
JObject response = CreateError(RPCErrorCode.RPC_MISC_ERROR, "Argument error: " + ex.Message);
httpContext.Response.ContentType = ContentType;
httpContext.Response.ContentType = this.ContentType;
await httpContext.Response.WriteAsync(response.ToString(Formatting.Indented));
}
else if (ex is BlockNotFoundException)
{
JObject response = CreateError(RPCErrorCode.RPC_INVALID_REQUEST, "Argument error: " + ex.Message);
httpContext.Response.ContentType = ContentType;
httpContext.Response.ContentType = this.ContentType;
await httpContext.Response.WriteAsync(response.ToString(Formatting.Indented));
}
else if (ex is ConfigurationException)
{
JObject response = CreateError(RPCErrorCode.RPC_INTERNAL_ERROR, ex.Message);
httpContext.Response.ContentType = ContentType;
httpContext.Response.ContentType = this.ContentType;
await httpContext.Response.WriteAsync(response.ToString(Formatting.Indented));
}
else if (ex is RPCServerException)
{
var rpcEx = (RPCServerException)ex;
JObject response = CreateError(rpcEx.ErrorCode, ex.Message);
httpContext.Response.ContentType = ContentType;
httpContext.Response.ContentType = this.ContentType;
await httpContext.Response.WriteAsync(response.ToString(Formatting.Indented));
}
else if (httpContext.Response?.StatusCode == 404)
{
JObject response = CreateError(RPCErrorCode.RPC_METHOD_NOT_FOUND, "Method not found");
httpContext.Response.ContentType = ContentType;
httpContext.Response.ContentType = this.ContentType;
await httpContext.Response.WriteAsync(response.ToString(Formatting.Indented));
}
else if (this.IsDependencyFailure(ex))
{
JObject response = CreateError(RPCErrorCode.RPC_METHOD_NOT_FOUND, ex.Message);
httpContext.Response.ContentType = ContentType;
httpContext.Response.ContentType = this.ContentType;
await httpContext.Response.WriteAsync(response.ToString(Formatting.Indented));
}
else if (httpContext.Response?.StatusCode == 500 || ex != null)
{
JObject response = CreateError(RPCErrorCode.RPC_INTERNAL_ERROR, "Internal error");
httpContext.Response.ContentType = ContentType;
httpContext.Response.ContentType = this.ContentType;
this.logger.LogError(new EventId(0), ex, "Internal error while calling RPC Method");
await httpContext.Response.WriteAsync(response.ToString(Formatting.Indented));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,7 @@ public IActionResult BuildTransaction([FromBody] BuildTransactionRequest request
if (!string.IsNullOrWhiteSpace(request.ChangeAddress))
{
Types.Wallet wallet = this.walletManager.GetWallet(request.WalletName);
HdAccount account = wallet.GetAccount(request.AccountName);
IHdAccount account = wallet.GetAccount(request.AccountName);
if (account == null)
{
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Account not found.", $"No account with the name '{request.AccountName}' could be found in wallet {wallet.Name}.");
Expand Down Expand Up @@ -952,7 +952,7 @@ public IActionResult CreateNewAccount([FromBody] GetUnusedAccountModel request)

try
{
HdAccount result = this.walletManager.GetUnusedAccount(request.WalletName, request.Password);
IHdAccount result = this.walletManager.GetUnusedAccount(request.WalletName, request.Password);
return this.Json(result.Name);
}
catch (CannotAddAccountToXpubKeyWalletException e)
Expand Down Expand Up @@ -986,7 +986,7 @@ public IActionResult ListAccounts([FromQuery] ListAccountsModel request)

try
{
IEnumerable<HdAccount> result = this.walletManager.GetAccounts(request.WalletName);
IEnumerable<IHdAccount> result = this.walletManager.GetAccounts(request.WalletName);
return this.Json(result.Select(a => a.Name));
}
catch (Exception e)
Expand Down Expand Up @@ -1081,7 +1081,7 @@ public IActionResult GetAllAddresses([FromQuery] GetAllAddressesModel request)
try
{
Types.Wallet wallet = this.walletManager.GetWallet(request.WalletName);
HdAccount account = wallet.GetAccount(request.AccountName);
IHdAccount account = wallet.GetAccount(request.AccountName);
if (account == null)
throw new WalletException($"No account with the name '{request.AccountName}' could be found.");

Expand Down Expand Up @@ -1436,7 +1436,7 @@ public IActionResult DistributeUtxos([FromBody] DistributeUtxosRequest request)
var walletReference = new WalletAccountReference(request.WalletName, request.AccountName);

Types.Wallet wallet = this.walletManager.GetWallet(request.WalletName);
HdAccount account = wallet.GetAccount(request.AccountName);
IHdAccount account = wallet.GetAccount(request.AccountName);

var addresses = new List<HdAddress>();

Expand Down
Loading