From f58eb2626e86920ca81d12e91e4c95fa99d37856 Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sat, 15 Dec 2018 12:58:07 +1100 Subject: [PATCH 01/14] Add SignTransaction helper method to FederationWalletManager --- .../Interfaces/IFederationWalletManager.cs | 8 +++ .../Wallet/FederationWalletManager.cs | 49 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IFederationWalletManager.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IFederationWalletManager.cs index 613aa7a6..18c74211 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IFederationWalletManager.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IFederationWalletManager.cs @@ -131,6 +131,14 @@ public interface IFederationWalletManager /// -1 if the occurs first and 1 otherwise. int CompareOutpoints(OutPoint outPoint1, OutPoint outPoint2); + /// + /// Signs a transaction if it is valid. + /// + /// The transaction. + /// A function that determines the validity of the withdrawal. + /// True if the withdrawal is valid and false otherwise. + Transaction SignTransaction(Transaction transaction, Func isValid); + /// /// Determines if federation has been activated. /// diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs index b6502d6d..21722c4d 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs @@ -910,6 +910,55 @@ public bool ValidateTransaction(Transaction transaction, bool checkSignature = f } } + /// + public Transaction SignTransaction(Transaction transaction, Func isValid) + { + Guard.NotNull(transaction, nameof(transaction)); + Guard.NotNull(isValid, nameof(isValid)); + + this.logger.LogTrace("({0}:'{1}')", nameof(transaction), transaction.ToHex(this.network)); + + IWithdrawal withdrawal = this.withdrawalExtractor.ExtractWithdrawalFromTransaction(transaction, 0, 0); + if (withdrawal == null) + { + this.logger.LogTrace("(-)[NOT_WITHDRAWAL]"); + return null; + } + + if (!isValid(transaction, withdrawal)) + { + this.logger.LogTrace("(-)[INVALID_WITHDRAWAL]"); + return null; + } + + var coins = new List(); + if (!TransactionHasValidUTXOs(transaction, coins)) + { + this.logger.LogTrace("(-)[INVALID_UTXOS]"); + return null; + } + + var builder = new TransactionBuilder(this.network); + + Transaction signedTransaction = null; + try + { + signedTransaction = builder + .AddCoins(coins) + .SignTransactionInPlace(transaction); + } + catch (Exception ex) + { + this.logger.LogTrace("Exception occurred: {0}", ex.ToString()); + this.logger.LogTrace("(-)[COULD_NOT_SIGN]"); + return null; + } + + this.logger.LogTrace("(-):{0}", signedTransaction.ToHex(this.network)); + + return signedTransaction; + } + /// public bool IsFederationActive() { From 489f66d45affb721332125cf9d569e61003739a7 Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sat, 15 Dec 2018 12:58:42 +1100 Subject: [PATCH 02/14] Add SignatureProvider to be used in API call --- .../Interfaces/ISignatureProvider.cs | 12 ++++ .../TargetChain/SignatureProvider.cs | 59 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs create mode 100644 src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs new file mode 100644 index 00000000..43798fc1 --- /dev/null +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs @@ -0,0 +1,12 @@ +namespace Stratis.FederatedPeg.Features.FederationGateway.Interfaces +{ + public interface ISignatureProvider + { + /// + /// Signs a transaction if it can be authorized. + /// + /// The hexadecimal representation transaction to sign. + /// The signed transaction or null if it can't be signed. + string SignTransaction(string transactionHex); + } +} diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs new file mode 100644 index 00000000..d8aa4841 --- /dev/null +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs @@ -0,0 +1,59 @@ +using System.Linq; +using NBitcoin; +using Stratis.FederatedPeg.Features.FederationGateway.Interfaces; + +namespace Stratis.FederatedPeg.Features.FederationGateway.TargetChain +{ + public class SignatureProvider: ISignatureProvider + { + private readonly IFederationWalletManager federationWalletManager; + private readonly ICrossChainTransferStore crossChainTransferStore; + private readonly Network network; + + public SignatureProvider( + IFederationWalletManager federationWalletManager, + ICrossChainTransferStore crossChainTransferStore, + Network network) + { + this.federationWalletManager = federationWalletManager; + this.crossChainTransferStore = crossChainTransferStore; + this.network = network; + } + + /// + /// Determines if a withdrawal transaction can be authorized. + /// + /// The transaction to authorize. + /// The withdrawal transaction already extracted from the transaction. + /// True if the withdrawal is valid and false otherwise. + private bool IsAuthorized(Transaction transaction, IWithdrawal withdrawal) + { + // It must be a transfer that we know about. + ICrossChainTransfer crossChainTransfer = this.crossChainTransferStore.GetAsync(new[] { withdrawal.DepositId }).GetAwaiter().GetResult().FirstOrDefault(); + if (crossChainTransfer == null) + return false; + + // If its already been seen in a block then we probably should not authorize it. + if (crossChainTransfer.Status == CrossChainTransferStatus.SeenInBlock) + return false; + + // The templates must match what we expect to see. + if (!CrossChainTransfer.TemplatesMatch(crossChainTransfer.PartialTransaction, transaction)) + return false; + + return true; + } + + private Transaction SignTransaction(Transaction transaction) + { + return this.federationWalletManager.SignTransaction(transaction, IsAuthorized); + } + + /// + public string SignTransaction(string transactionHex) + { + Transaction transaction = this.network.CreateTransaction(transactionHex); + return SignTransaction(transaction)?.ToHex(this.network); + } + } +} From f4e6c4da84448f4a83417e46988b7a0fc8fb79cc Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sat, 15 Dec 2018 12:59:34 +1100 Subject: [PATCH 03/14] Add AuthorizeWithdrawals API to gateway controller --- .../FederationGatewayController.cs | 41 ++++++++++++++++++- .../FederationGatewayFeature.cs | 2 +- .../Interfaces/IAuthorizeWithdrawalsModel.cs | 7 ++++ .../Models/AuthorizeWithdrawalsModel.cs | 16 ++++++++ .../FederationGatewayControllerTests.cs | 6 ++- 5 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IAuthorizeWithdrawalsModel.cs create mode 100644 src/Stratis.FederatedPeg.Features.FederationGateway/Models/AuthorizeWithdrawalsModel.cs diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs index b6f50e36..ee1ed867 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.Logging; -using NBitcoin; using Stratis.Bitcoin.Utilities; using Stratis.Bitcoin.Utilities.JsonErrors; using Stratis.FederatedPeg.Features.FederationGateway.Interfaces; @@ -19,6 +18,7 @@ public static class FederationGatewayRouteEndPoint public const string PushMaturedBlocks = "push_matured_blocks"; public const string PushCurrentBlockTip = "push_current_block_tip"; public const string GetMaturedBlockDeposits = "get_matured_block_deposits"; + public const string AuthorizeWithdrawals = "authorize_withdrwals"; // TODO commented out since those constants are unused. Remove them later or start using. //public const string CreateSessionOnCounterChain = "create-session-oncounterchain"; @@ -42,18 +42,22 @@ public class FederationGatewayController : Controller private readonly ILeaderReceiver leaderReceiver; + private readonly ISignatureProvider signatureProvider; + public FederationGatewayController( ILoggerFactory loggerFactory, IMaturedBlockReceiver maturedBlockReceiver, ILeaderProvider leaderProvider, IMaturedBlocksProvider maturedBlocksProvider, - ILeaderReceiver leaderReceiver) + ILeaderReceiver leaderReceiver, + ISignatureProvider signatureProvider) { this.logger = loggerFactory.CreateLogger(this.GetType().FullName); this.maturedBlockReceiver = maturedBlockReceiver; this.leaderProvider = leaderProvider; this.maturedBlocksProvider = maturedBlocksProvider; this.leaderReceiver = leaderReceiver; + this.signatureProvider = signatureProvider; } [Route(FederationGatewayRouteEndPoint.PushMaturedBlocks)] @@ -92,6 +96,39 @@ public IActionResult PushCurrentBlockTip([FromBody] BlockTipModel blockTip) } } + /// + /// Authorizes withdrawals. + /// + /// A structure containing one or more transactions to authorize. + /// An array containing one or more signed transaction or null for transaction that could not be authorized. + [Route(FederationGatewayRouteEndPoint.AuthorizeWithdrawals)] + [HttpPost] + public IActionResult AuthorizeWithdrawals([FromBody] AuthorizeWithdrawalsModel authRequest) + { + Guard.NotNull(authRequest, nameof(authRequest)); + + if (!this.ModelState.IsValid) + { + IEnumerable errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); + return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors)); + } + + try + { + for (int i = 0; i < authRequest.TransactionHex.Length; i++) + { + authRequest.TransactionHex[i] = this.signatureProvider.SignTransaction(authRequest.TransactionHex[i]); + } + + return this.Json(authRequest.TransactionHex); + } + catch (Exception e) + { + this.logger.LogTrace("Exception thrown calling /api/FederationGateway/{0}: {1}.", FederationGatewayRouteEndPoint.AuthorizeWithdrawals, e.Message); + return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, $"Could not authorize withdrawals: {e.Message}", e.ToString()); + } + } + /// /// Retrieves blocks deposits. /// diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/FederationGatewayFeature.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/FederationGatewayFeature.cs index e7f5748a..0686c86e 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/FederationGatewayFeature.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/FederationGatewayFeature.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; @@ -267,6 +266,7 @@ public static IFullNodeBuilder AddFederationGateway(this IFullNodeBuilder fullNo services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IAuthorizeWithdrawalsModel.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IAuthorizeWithdrawalsModel.cs new file mode 100644 index 00000000..73b7c63c --- /dev/null +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IAuthorizeWithdrawalsModel.cs @@ -0,0 +1,7 @@ +namespace Stratis.FederatedPeg.Features.FederationGateway.Interfaces +{ + public interface IAuthorizeWithdrawalsModel + { + string[] TransactionHex { get; } + } +} diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Models/AuthorizeWithdrawalsModel.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Models/AuthorizeWithdrawalsModel.cs new file mode 100644 index 00000000..f85f4d80 --- /dev/null +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Models/AuthorizeWithdrawalsModel.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; +using Newtonsoft.Json; +using Stratis.Bitcoin.Features.Wallet.Models; +using Stratis.FederatedPeg.Features.FederationGateway.Interfaces; + +namespace Stratis.FederatedPeg.Features.FederationGateway.Models +{ + /// + /// An instance of this class represents a particular block hash and associated height on the source chain. + /// + public class AuthorizeWithdrawalsModel : RequestModel, IAuthorizeWithdrawalsModel + { + [Required(ErrorMessage = "An array of transactions is required")] + public string[] TransactionHex { get; set; } + } +} diff --git a/src/Stratis.FederatedPeg.Tests/FederationGatewayControllerTests.cs b/src/Stratis.FederatedPeg.Tests/FederationGatewayControllerTests.cs index 9324cabf..4a253b4c 100644 --- a/src/Stratis.FederatedPeg.Tests/FederationGatewayControllerTests.cs +++ b/src/Stratis.FederatedPeg.Tests/FederationGatewayControllerTests.cs @@ -38,6 +38,8 @@ public class FederationGatewayControllerTests private readonly ILeaderReceiver leaderReceiver; + private readonly ISignatureProvider signatureProvider; + public FederationGatewayControllerTests() { this.network = FederatedPegNetwork.NetworksSelector.Regtest(); @@ -49,6 +51,7 @@ public FederationGatewayControllerTests() this.leaderProvider = Substitute.For(); this.depositExtractor = Substitute.For(); this.leaderReceiver = Substitute.For(); + this.signatureProvider = Substitute.For(); } private FederationGatewayController CreateController() @@ -58,7 +61,8 @@ private FederationGatewayController CreateController() this.maturedBlockReceiver, this.leaderProvider, this.GetMaturedBlocksProvider(), - this.leaderReceiver); + this.leaderReceiver, + this.signatureProvider); return controller; } From df2b5486b38d328e6b9dffe42792cfc49c298cbe Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sat, 15 Dec 2018 14:42:28 +1100 Subject: [PATCH 04/14] Update SignTransaction method --- .../Wallet/FederationWalletManager.cs | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs index 21722c4d..68b69b49 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs @@ -911,41 +911,61 @@ public bool ValidateTransaction(Transaction transaction, bool checkSignature = f } /// - public Transaction SignTransaction(Transaction transaction, Func isValid) + public Transaction SignTransaction(Transaction externalTransaction, Func isValid) { - Guard.NotNull(transaction, nameof(transaction)); + Guard.NotNull(externalTransaction, nameof(externalTransaction)); Guard.NotNull(isValid, nameof(isValid)); - this.logger.LogTrace("({0}:'{1}')", nameof(transaction), transaction.ToHex(this.network)); + this.logger.LogTrace("({0}:'{1}')", nameof(externalTransaction), externalTransaction.ToHex(this.network)); + + FederationWallet wallet = this.Wallet; + if (wallet == null || this.Secret == null) + { + this.logger.LogTrace("(-)[FEDERATION_INACTIVE]"); + return null; + } + + Key key = wallet.MultiSigAddress.GetPrivateKey(wallet.EncryptedSeed, this.Secret.WalletPassword, this.network); + if (key.PubKey.ToHex() != this.federationGatewaySettings.PublicKey) + { + this.logger.LogTrace("(-)[FEDERATION_KEY_INVALID]"); + return null; + } - IWithdrawal withdrawal = this.withdrawalExtractor.ExtractWithdrawalFromTransaction(transaction, 0, 0); + IWithdrawal withdrawal = this.withdrawalExtractor.ExtractWithdrawalFromTransaction(externalTransaction, 0, 0); if (withdrawal == null) { this.logger.LogTrace("(-)[NOT_WITHDRAWAL]"); return null; } - if (!isValid(transaction, withdrawal)) + // Checks that the deposit id in the transaction is associated with a valid transfer. + if (!isValid(externalTransaction, withdrawal)) { this.logger.LogTrace("(-)[INVALID_WITHDRAWAL]"); return null; } var coins = new List(); - if (!TransactionHasValidUTXOs(transaction, coins)) + foreach (TxIn input in externalTransaction.Inputs) { - this.logger.LogTrace("(-)[INVALID_UTXOS]"); - return null; + TransactionData transactionData = this.outpointLookup[input.PrevOut]; + if (transactionData == null) + { + this.logger.LogTrace("(-)[INVALID_UTXOS]"); + return null; + } + coins.Add(new Coin(transactionData.Id, (uint)transactionData.Index, transactionData.Amount, transactionData.ScriptPubKey)); } - var builder = new TransactionBuilder(this.network); - Transaction signedTransaction = null; try { + var builder = new TransactionBuilder(this.network); signedTransaction = builder + .AddKeys(key) .AddCoins(coins) - .SignTransactionInPlace(transaction); + .SignTransactionInPlace(externalTransaction); } catch (Exception ex) { @@ -954,7 +974,7 @@ public Transaction SignTransaction(Transaction transaction, Func Date: Sat, 15 Dec 2018 14:42:52 +1100 Subject: [PATCH 05/14] Add unit test --- .../SignatureProviderTests.cs | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs diff --git a/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs b/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs new file mode 100644 index 00000000..97755b4b --- /dev/null +++ b/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs @@ -0,0 +1,110 @@ +using System.Linq; +using System.Reactive.Linq; +using NBitcoin; +using NBitcoin.Policy; +using Stratis.Bitcoin.Configuration; +using Stratis.FederatedPeg.Features.FederationGateway.Interfaces; +using Stratis.FederatedPeg.Features.FederationGateway.Models; +using Stratis.FederatedPeg.Features.FederationGateway.SourceChain; +using Stratis.FederatedPeg.Features.FederationGateway.TargetChain; +using Xunit; + +namespace Stratis.FederatedPeg.Tests +{ + public class SignatureProviderTests : CrossChainTestBase + { + public SignatureProviderTests() : base() + { + } + + [Fact] + public void OtherMembersCanAddSignaturesToMyTransaction() + { + var dataFolder = new DataFolder(CreateTestDir(this)); + + this.Init(dataFolder); + this.AddFunding(); + this.AppendBlocks(5); + + using (ICrossChainTransferStore crossChainTransferStore = this.CreateStore()) + { + crossChainTransferStore.Initialize(); + crossChainTransferStore.Start(); + + Assert.Equal(this.chain.Tip.HashBlock, crossChainTransferStore.TipHashAndHeight.HashBlock); + Assert.Equal(this.chain.Tip.Height, crossChainTransferStore.TipHashAndHeight.Height); + + BitcoinAddress address = (new Key()).PubKey.Hash.GetAddress(this.network); + + var deposit = new Deposit(0, new Money(160m, MoneyUnit.BTC), address.ToString(), crossChainTransferStore.NextMatureDepositHeight, 1); + + IMaturedBlockDeposits[] blockDeposits = new[] { new MaturedBlockDepositsModel( + new MaturedBlockModel() { + BlockHash = 1, + BlockHeight = crossChainTransferStore.NextMatureDepositHeight }, + new[] { deposit }) + }; + + crossChainTransferStore.RecordLatestMatureDepositsAsync(blockDeposits).GetAwaiter().GetResult(); + + ICrossChainTransfer crossChainTransfer = crossChainTransferStore.GetAsync(new[] { deposit.Id }).GetAwaiter().GetResult().SingleOrDefault(); + + Assert.NotNull(crossChainTransfer); + + Transaction transaction = crossChainTransfer.PartialTransaction; + + Assert.True(crossChainTransferStore.ValidateTransaction(transaction)); + + // Create a separate instance to generate another transaction. + Transaction transaction2; + var newTest = new SignatureProviderTests(); + var dataFolder2 = new DataFolder(CreateTestDir(this)); + + newTest.federationKeys = this.federationKeys; + newTest.SetExtendedKey(1); + newTest.Init(dataFolder2); + newTest.AddFunding(); + newTest.AppendBlocks(3); + + using (ICrossChainTransferStore crossChainTransferStore2 = newTest.CreateStore()) + { + crossChainTransferStore2.Initialize(); + crossChainTransferStore2.Start(); + + Assert.Equal(newTest.chain.Tip.HashBlock, crossChainTransferStore2.TipHashAndHeight.HashBlock); + Assert.Equal(newTest.chain.Tip.Height, crossChainTransferStore2.TipHashAndHeight.Height); + + crossChainTransferStore2.RecordLatestMatureDepositsAsync(blockDeposits).GetAwaiter().GetResult(); + + ICrossChainTransfer crossChainTransfer2 = crossChainTransferStore2.GetAsync(new[] { deposit.Id }).GetAwaiter().GetResult().SingleOrDefault(); + + Assert.NotNull(crossChainTransfer2); + + transaction2 = crossChainTransfer2.PartialTransaction; + + Assert.True(crossChainTransferStore2.ValidateTransaction(transaction2)); + + // The first instance acts as signatory for the transaction coming from the second instance. + ISignatureProvider signatureProvider = new SignatureProvider(this.federationWalletManager, crossChainTransferStore, this.network); + + string signedTransactionHex = signatureProvider.SignTransaction(transaction2.ToHex(this.network)); + Assert.NotNull(signedTransactionHex); + + // The second instance parses the hex. + Transaction signedTransaction = newTest.network.CreateTransaction(signedTransactionHex); + Assert.NotNull(signedTransaction); + + // The second instance validates the transaction and signature. + var outpointLookup = newTest.wallet.MultiSigAddress.Transactions.ToDictionary(t => new OutPoint(t.Id, t.Index)); + Coin[] coins = signedTransaction.Inputs + .Select(input => outpointLookup[input.PrevOut]) + .Select(td => new Coin(td.Id, (uint)td.Index, td.Amount, td.ScriptPubKey)) + .ToArray(); + + TransactionBuilder builder = new TransactionBuilder(newTest.wallet.Network).AddCoins(coins); + Assert.True(builder.Verify(signedTransaction, this.federationGatewaySettings.TransactionFee, out TransactionPolicyError[] errors)); + } + } + } + } +} From 3efdfcaf2e2cfec82ff60038985e750dd742201e Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sat, 15 Dec 2018 16:09:16 +1100 Subject: [PATCH 06/14] Refactor to reduce overhead of key decryption --- .../Controllers/FederationGatewayController.cs | 7 ++----- .../Interfaces/IFederationWalletManager.cs | 3 ++- .../Interfaces/ISignatureProvider.cs | 6 +++--- .../Wallet/FederationWalletManager.cs | 16 +--------------- 4 files changed, 8 insertions(+), 24 deletions(-) diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs index ee1ed867..da01e478 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs @@ -115,12 +115,9 @@ public IActionResult AuthorizeWithdrawals([FromBody] AuthorizeWithdrawalsModel a try { - for (int i = 0; i < authRequest.TransactionHex.Length; i++) - { - authRequest.TransactionHex[i] = this.signatureProvider.SignTransaction(authRequest.TransactionHex[i]); - } + string[] result = this.signatureProvider.SignTransactions(authRequest.TransactionHex); - return this.Json(authRequest.TransactionHex); + return this.Json(result); } catch (Exception e) { diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IFederationWalletManager.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IFederationWalletManager.cs index 18c74211..be2c7b44 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IFederationWalletManager.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IFederationWalletManager.cs @@ -136,8 +136,9 @@ public interface IFederationWalletManager /// /// The transaction. /// A function that determines the validity of the withdrawal. + /// The key to use. /// True if the withdrawal is valid and false otherwise. - Transaction SignTransaction(Transaction transaction, Func isValid); + Transaction SignTransaction(Transaction transaction, Func isValid, Key key); /// /// Determines if federation has been activated. diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs index 43798fc1..80e0ba3c 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs @@ -5,8 +5,8 @@ public interface ISignatureProvider /// /// Signs a transaction if it can be authorized. /// - /// The hexadecimal representation transaction to sign. - /// The signed transaction or null if it can't be signed. - string SignTransaction(string transactionHex); + /// The hexadecimal representations of transactions to sign. + /// An array of signed transactions (in hex) or null for transactions that can't be signed. + string[] SignTransactions(string[] transactionHex); } } diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs index 68b69b49..d293ea70 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs @@ -911,27 +911,13 @@ public bool ValidateTransaction(Transaction transaction, bool checkSignature = f } /// - public Transaction SignTransaction(Transaction externalTransaction, Func isValid) + public Transaction SignTransaction(Transaction externalTransaction, Func isValid, Key key) { Guard.NotNull(externalTransaction, nameof(externalTransaction)); Guard.NotNull(isValid, nameof(isValid)); this.logger.LogTrace("({0}:'{1}')", nameof(externalTransaction), externalTransaction.ToHex(this.network)); - FederationWallet wallet = this.Wallet; - if (wallet == null || this.Secret == null) - { - this.logger.LogTrace("(-)[FEDERATION_INACTIVE]"); - return null; - } - - Key key = wallet.MultiSigAddress.GetPrivateKey(wallet.EncryptedSeed, this.Secret.WalletPassword, this.network); - if (key.PubKey.ToHex() != this.federationGatewaySettings.PublicKey) - { - this.logger.LogTrace("(-)[FEDERATION_KEY_INVALID]"); - return null; - } - IWithdrawal withdrawal = this.withdrawalExtractor.ExtractWithdrawalFromTransaction(externalTransaction, 0, 0); if (withdrawal == null) { From 2756fb20bdc4f55e0ab6526f8b6271118be02b42 Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sat, 15 Dec 2018 16:09:31 +1100 Subject: [PATCH 07/14] Improve logging --- .../TargetChain/SignatureProvider.cs | 51 ++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs index d8aa4841..c88cd08c 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs @@ -1,6 +1,9 @@ using System.Linq; +using Microsoft.Extensions.Logging; using NBitcoin; +using Stratis.Bitcoin.Utilities; using Stratis.FederatedPeg.Features.FederationGateway.Interfaces; +using Stratis.FederatedPeg.Features.FederationGateway.Wallet; namespace Stratis.FederatedPeg.Features.FederationGateway.TargetChain { @@ -8,13 +11,24 @@ public class SignatureProvider: ISignatureProvider { private readonly IFederationWalletManager federationWalletManager; private readonly ICrossChainTransferStore crossChainTransferStore; + private readonly IFederationGatewaySettings federationGatewaySettings; private readonly Network network; + private readonly ILogger logger; public SignatureProvider( IFederationWalletManager federationWalletManager, ICrossChainTransferStore crossChainTransferStore, - Network network) + IFederationGatewaySettings federationGatewaySettings, + Network network, + ILoggerFactory loggerFactory) { + Guard.NotNull(federationWalletManager, nameof(federationWalletManager)); + Guard.NotNull(crossChainTransferStore, nameof(crossChainTransferStore)); + Guard.NotNull(federationGatewaySettings, nameof(federationGatewaySettings)); + Guard.NotNull(network, nameof(network)); + Guard.NotNull(loggerFactory, nameof(loggerFactory)); + + this.logger = loggerFactory.CreateLogger(this.GetType().FullName); this.federationWalletManager = federationWalletManager; this.crossChainTransferStore = crossChainTransferStore; this.network = network; @@ -44,16 +58,41 @@ private bool IsAuthorized(Transaction transaction, IWithdrawal withdrawal) return true; } - private Transaction SignTransaction(Transaction transaction) + private Transaction SignTransaction(Transaction transaction, Key key) { - return this.federationWalletManager.SignTransaction(transaction, IsAuthorized); + return this.federationWalletManager.SignTransaction(transaction, IsAuthorized, key); } /// - public string SignTransaction(string transactionHex) + public string[] SignTransactions(string[] transactionHex) { - Transaction transaction = this.network.CreateTransaction(transactionHex); - return SignTransaction(transaction)?.ToHex(this.network); + Guard.NotNull(transactionHex, nameof(transactionHex)); + + this.logger.LogTrace("():{0}", transactionHex); + + FederationWallet wallet = this.federationWalletManager.GetWallet(); + if (wallet == null || this.federationWalletManager.Secret == null) + { + this.logger.LogTrace("(-)[FEDERATION_INACTIVE]"); + return null; + } + + Key key = wallet.MultiSigAddress.GetPrivateKey(wallet.EncryptedSeed, this.federationWalletManager.Secret.WalletPassword, this.network); + if (key.PubKey.ToHex() != this.federationGatewaySettings.PublicKey) + { + this.logger.LogTrace("(-)[FEDERATION_KEY_INVALID]"); + return null; + } + + for (int i = 0; i < transactionHex.Length; i++) + { + Transaction transaction = this.network.CreateTransaction(transactionHex[i]); + transactionHex[i] = SignTransaction(transaction, key)?.ToHex(this.network); + } + + this.logger.LogTrace("(-):{0}", transactionHex); + + return transactionHex; } } } From 620635fe084f345b1049231556e9c2bf51f93e16 Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sat, 15 Dec 2018 16:14:41 +1100 Subject: [PATCH 08/14] Update test --- .../TargetChain/SignatureProvider.cs | 1 + .../SignatureProviderTests.cs | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs index c88cd08c..5a4af8b7 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs @@ -30,6 +30,7 @@ public SignatureProvider( this.logger = loggerFactory.CreateLogger(this.GetType().FullName); this.federationWalletManager = federationWalletManager; + this.federationGatewaySettings = federationGatewaySettings; this.crossChainTransferStore = crossChainTransferStore; this.network = network; } diff --git a/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs b/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs index 97755b4b..ae38aa36 100644 --- a/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs +++ b/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs @@ -85,9 +85,14 @@ public void OtherMembersCanAddSignaturesToMyTransaction() Assert.True(crossChainTransferStore2.ValidateTransaction(transaction2)); // The first instance acts as signatory for the transaction coming from the second instance. - ISignatureProvider signatureProvider = new SignatureProvider(this.federationWalletManager, crossChainTransferStore, this.network); - - string signedTransactionHex = signatureProvider.SignTransaction(transaction2.ToHex(this.network)); + ISignatureProvider signatureProvider = new SignatureProvider( + this.federationWalletManager, + crossChainTransferStore, + this.federationGatewaySettings, + this.network, + this.loggerFactory); + + string signedTransactionHex = signatureProvider.SignTransactions(new[] { transaction2.ToHex(this.network) }).FirstOrDefault(); Assert.NotNull(signedTransactionHex); // The second instance parses the hex. From 043268199dd481c094291764c9a44e6ffad0cbd4 Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sat, 15 Dec 2018 17:24:57 +1100 Subject: [PATCH 09/14] Revert to one transaction per call --- .../Controllers/FederationGatewayController.cs | 2 +- .../Interfaces/IAuthorizeWithdrawalsModel.cs | 2 +- .../Interfaces/ISignatureProvider.cs | 2 +- .../Models/AuthorizeWithdrawalsModel.cs | 4 ++-- .../TargetChain/SignatureProvider.cs | 11 +++++------ .../SignatureProviderTests.cs | 2 +- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs index da01e478..5cfea2e2 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs @@ -115,7 +115,7 @@ public IActionResult AuthorizeWithdrawals([FromBody] AuthorizeWithdrawalsModel a try { - string[] result = this.signatureProvider.SignTransactions(authRequest.TransactionHex); + string result = this.signatureProvider.SignTransaction(authRequest.TransactionHex); return this.Json(result); } diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IAuthorizeWithdrawalsModel.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IAuthorizeWithdrawalsModel.cs index 73b7c63c..5a62758c 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IAuthorizeWithdrawalsModel.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/IAuthorizeWithdrawalsModel.cs @@ -2,6 +2,6 @@ { public interface IAuthorizeWithdrawalsModel { - string[] TransactionHex { get; } + string TransactionHex { get; } } } diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs index 80e0ba3c..2ddffcb4 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs @@ -7,6 +7,6 @@ public interface ISignatureProvider /// /// The hexadecimal representations of transactions to sign. /// An array of signed transactions (in hex) or null for transactions that can't be signed. - string[] SignTransactions(string[] transactionHex); + string SignTransaction(string transactionHex); } } diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Models/AuthorizeWithdrawalsModel.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Models/AuthorizeWithdrawalsModel.cs index f85f4d80..94dcd485 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Models/AuthorizeWithdrawalsModel.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Models/AuthorizeWithdrawalsModel.cs @@ -10,7 +10,7 @@ namespace Stratis.FederatedPeg.Features.FederationGateway.Models /// public class AuthorizeWithdrawalsModel : RequestModel, IAuthorizeWithdrawalsModel { - [Required(ErrorMessage = "An array of transactions is required")] - public string[] TransactionHex { get; set; } + [Required(ErrorMessage = "The transaction to authorize")] + public string TransactionHex { get; set; } } } diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs index 5a4af8b7..619bd162 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs @@ -65,7 +65,7 @@ private Transaction SignTransaction(Transaction transaction, Key key) } /// - public string[] SignTransactions(string[] transactionHex) + public string SignTransaction(string transactionHex) { Guard.NotNull(transactionHex, nameof(transactionHex)); @@ -85,11 +85,10 @@ public string[] SignTransactions(string[] transactionHex) return null; } - for (int i = 0; i < transactionHex.Length; i++) - { - Transaction transaction = this.network.CreateTransaction(transactionHex[i]); - transactionHex[i] = SignTransaction(transaction, key)?.ToHex(this.network); - } + // Check that the transactions are spending exactly all the oldest UTXOs. + Transaction transaction = this.network.CreateTransaction(transactionHex); + + transactionHex = SignTransaction(transaction, key)?.ToHex(this.network); this.logger.LogTrace("(-):{0}", transactionHex); diff --git a/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs b/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs index ae38aa36..d991d211 100644 --- a/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs +++ b/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs @@ -92,7 +92,7 @@ public void OtherMembersCanAddSignaturesToMyTransaction() this.network, this.loggerFactory); - string signedTransactionHex = signatureProvider.SignTransactions(new[] { transaction2.ToHex(this.network) }).FirstOrDefault(); + string signedTransactionHex = signatureProvider.SignTransaction(transaction2.ToHex(this.network)); Assert.NotNull(signedTransactionHex); // The second instance parses the hex. From ea053f2006707cc1943a07023688f3a6bad52ac1 Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sat, 15 Dec 2018 17:39:56 +1100 Subject: [PATCH 10/14] Add TODO --- .../TargetChain/SignatureProvider.cs | 1 - .../Wallet/FederationWalletManager.cs | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs index 619bd162..1aa76240 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs @@ -85,7 +85,6 @@ public string SignTransaction(string transactionHex) return null; } - // Check that the transactions are spending exactly all the oldest UTXOs. Transaction transaction = this.network.CreateTransaction(transactionHex); transactionHex = SignTransaction(transaction, key)?.ToHex(this.network); diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs index d293ea70..91b40eef 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Wallet/FederationWalletManager.cs @@ -913,6 +913,9 @@ public bool ValidateTransaction(Transaction transaction, bool checkSignature = f /// public Transaction SignTransaction(Transaction externalTransaction, Func isValid, Key key) { + // TODO: Check that the transaction is spending exactly the expected UTXO(s). + // TODO: Check that the transaction is serving the next expected UTXO(s). + Guard.NotNull(externalTransaction, nameof(externalTransaction)); Guard.NotNull(isValid, nameof(isValid)); From e1dbf166568407e8115c58ac919bd68940be17fb Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sat, 15 Dec 2018 22:11:04 +1100 Subject: [PATCH 11/14] Fix test --- .../CrossChainTestBase.cs | 22 +++++++++++++------ .../SignatureProviderTests.cs | 15 +++++++++---- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/Stratis.FederatedPeg.Tests/CrossChainTestBase.cs b/src/Stratis.FederatedPeg.Tests/CrossChainTestBase.cs index 6508f023..993514c9 100644 --- a/src/Stratis.FederatedPeg.Tests/CrossChainTestBase.cs +++ b/src/Stratis.FederatedPeg.Tests/CrossChainTestBase.cs @@ -62,9 +62,13 @@ protected Script redeemScript /// /// Initializes the cross-chain transfer tests. /// - public CrossChainTestBase() + public CrossChainTestBase() : this(FederatedPegNetwork.NetworksSelector.Regtest()) { - this.network = FederatedPegNetwork.NetworksSelector.Regtest(); + } + + public CrossChainTestBase(Network network) + { + this.network = network; NetworkRegistration.Register(this.network); var serializer = new DBreezeSerializer(); @@ -222,9 +226,6 @@ protected void AppendBlocks(int blocks) /// The last chained header. protected ChainedHeader AppendBlock(params Transaction[] transactions) { - ChainedHeader last = null; - uint nonce = RandomUtils.GetUInt32(); - Block block = this.network.CreateBlock(); // Create coinbase. @@ -238,9 +239,16 @@ protected ChainedHeader AppendBlock(params Transaction[] transactions) block.UpdateMerkleRoot(); block.Header.HashPrevBlock = this.chain.Tip.HashBlock; - block.Header.Nonce = nonce; - if (!this.chain.TrySetTip(block.Header, out last)) + block.Header.Nonce = RandomUtils.GetUInt32(); + + return AppendBlock(block); + } + + protected ChainedHeader AppendBlock(Block block) + { + if (!this.chain.TrySetTip(block.Header, out ChainedHeader last)) throw new InvalidOperationException("Previous not existing"); + this.blockDict[block.GetHash()] = block; this.federationWalletSyncManager.ProcessBlock(block); diff --git a/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs b/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs index d991d211..6a22b6e1 100644 --- a/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs +++ b/src/Stratis.FederatedPeg.Tests/SignatureProviderTests.cs @@ -3,6 +3,7 @@ using NBitcoin; using NBitcoin.Policy; using Stratis.Bitcoin.Configuration; +using Stratis.Bitcoin.Networks; using Stratis.FederatedPeg.Features.FederationGateway.Interfaces; using Stratis.FederatedPeg.Features.FederationGateway.Models; using Stratis.FederatedPeg.Features.FederationGateway.SourceChain; @@ -13,7 +14,7 @@ namespace Stratis.FederatedPeg.Tests { public class SignatureProviderTests : CrossChainTestBase { - public SignatureProviderTests() : base() + public SignatureProviderTests() : base(Networks.Stratis.Testnet()) { } @@ -24,7 +25,7 @@ public void OtherMembersCanAddSignaturesToMyTransaction() this.Init(dataFolder); this.AddFunding(); - this.AppendBlocks(5); + this.AppendBlocks(this.federationGatewaySettings.MinCoinMaturity); using (ICrossChainTransferStore crossChainTransferStore = this.CreateStore()) { @@ -63,8 +64,14 @@ public void OtherMembersCanAddSignaturesToMyTransaction() newTest.federationKeys = this.federationKeys; newTest.SetExtendedKey(1); newTest.Init(dataFolder2); - newTest.AddFunding(); - newTest.AppendBlocks(3); + + // Clone chain + for (int i = 1; i <= this.chain.Height; i++) + { + ChainedHeader header = this.chain.GetBlock(i); + Block block = this.blockDict[header.HashBlock]; + newTest.AppendBlock(block); + } using (ICrossChainTransferStore crossChainTransferStore2 = newTest.CreateStore()) { From e2122b6791288d2db42efdceb044308df0cb77a1 Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sat, 15 Dec 2018 22:13:19 +1100 Subject: [PATCH 12/14] Small typo --- .../Controllers/FederationGatewayController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs index 5cfea2e2..883ab1c4 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Controllers/FederationGatewayController.cs @@ -18,7 +18,7 @@ public static class FederationGatewayRouteEndPoint public const string PushMaturedBlocks = "push_matured_blocks"; public const string PushCurrentBlockTip = "push_current_block_tip"; public const string GetMaturedBlockDeposits = "get_matured_block_deposits"; - public const string AuthorizeWithdrawals = "authorize_withdrwals"; + public const string AuthorizeWithdrawals = "authorize_withdrawals"; // TODO commented out since those constants are unused. Remove them later or start using. //public const string CreateSessionOnCounterChain = "create-session-oncounterchain"; From dfe90eb71fc794a909b47ea5a8ad486e2983a435 Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sun, 16 Dec 2018 09:56:08 +1100 Subject: [PATCH 13/14] Add comments --- .../Interfaces/ISignatureProvider.cs | 9 ++++++++- .../TargetChain/SignatureProvider.cs | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs index 2ddffcb4..448a0115 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/Interfaces/ISignatureProvider.cs @@ -3,8 +3,15 @@ public interface ISignatureProvider { /// - /// Signs a transaction if it can be authorized. + /// Signs an externally provided withdrawal transaction if it is deemed valid. This method + /// is used to sign a transaction in response to signature requests from the federation + /// leader. /// + /// + /// This method requires federation to be active as the wallet password is supplied during + /// activation. Transaction's are validated to ensure that they are expected as per + /// the deposits received on the source chain. + /// /// The hexadecimal representations of transactions to sign. /// An array of signed transactions (in hex) or null for transactions that can't be signed. string SignTransaction(string transactionHex); diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs index 1aa76240..07aa70dc 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs @@ -7,6 +7,13 @@ namespace Stratis.FederatedPeg.Features.FederationGateway.TargetChain { + /// + /// The purpose of this class is to sign externally provided withdrawal transactions if they + /// are deemed valid. Transaction are signed in response to signature requests from the federation + /// leader. The federation is required to be active as the wallet password is supplied during + /// activation. Transaction's are validated to ensure that they are expected as per + /// the deposits received on the source chain. + /// public class SignatureProvider: ISignatureProvider { private readonly IFederationWalletManager federationWalletManager; From 19bc7b07e0442aa4fdb19d6bc28de621476b88e7 Mon Sep 17 00:00:00 2001 From: quantumagi Date: Sun, 16 Dec 2018 10:08:18 +1100 Subject: [PATCH 14/14] Revisit class comment --- .../TargetChain/SignatureProvider.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs index 07aa70dc..91817fdf 100644 --- a/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs +++ b/src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/SignatureProvider.cs @@ -8,11 +8,12 @@ namespace Stratis.FederatedPeg.Features.FederationGateway.TargetChain { /// - /// The purpose of this class is to sign externally provided withdrawal transactions if they - /// are deemed valid. Transaction are signed in response to signature requests from the federation - /// leader. The federation is required to be active as the wallet password is supplied during - /// activation. Transaction's are validated to ensure that they are expected as per - /// the deposits received on the source chain. + /// The purpose of this class is to sign externally provided withdrawal transactions if they are + /// deemed valid. Transactions would typically be signed in response to signature requests from + /// the federation leader. The federation is required to be active as the wallet password is + /// supplied during activation. Transaction's are validated to ensure that they are expected as + /// per the deposits received on the source chain. Out-of-sequence transactions or transactions + /// that are not utilising the expected UTXOs will not be signed. /// public class SignatureProvider: ISignatureProvider {