public async Task <string> CreateHubCommitment(string clientPubKey, IAsset asset, decimal amount, string signedByClientChannel) { var address = await _multisigService.GetMultisig(clientPubKey); if (address == null) { throw new BackendException($"Client {clientPubKey} is not registered", ErrorCode.BadInputParameter); } var channel = await _offchainChannelRepository.GetChannel(address.MultisigAddress, asset.Id); if (channel == null) { throw new BackendException("Channel is not found", ErrorCode.ShouldOpenNewChannel); } if (amount < 0 && channel.ClientAmount < Math.Abs(amount)) { throw new BackendException("Client amount in channel is low than required", ErrorCode.BadChannelAmount); } if (amount > 0 && channel.HubAmount < amount) { throw new BackendException("Hub amount in channel is low than required", ErrorCode.BadChannelAmount); } if (!TransactionComparer.CompareTransactions(channel.InitialTransaction, signedByClientChannel)) { throw new BackendException("Provided signed transaction is not equal initial transaction", ErrorCode.BadTransaction); } if (!await _signatureVerifier.Verify(signedByClientChannel, clientPubKey)) { throw new BackendException("Provided signed transaction is not signed by client", ErrorCode.BadTransaction); } var fullSignedChannel = await _signatureApiProvider.SignTransaction(signedByClientChannel); if (!_signatureVerifier.VerifyScriptSigs(fullSignedChannel)) { throw new BackendException("Channel transaction is not full signed", ErrorCode.BadFullSignTransaction); } await _offchainChannelRepository.SetFullSignedTransaction(address.MultisigAddress, asset.Id, fullSignedChannel); var hubRevokeKey = new Key(); var newHubAmount = channel.HubAmount - amount; var newClientAmount = channel.ClientAmount + amount; var commitmentResult = CreateCommitmentTransaction(address, new PubKey(address.ExchangePubKey), new PubKey(clientPubKey), hubRevokeKey.PubKey, new PubKey(clientPubKey), asset, newHubAmount, newClientAmount, fullSignedChannel); await _commitmentRepository.CreateCommitment(CommitmentType.Hub, channel.ChannelId, address.MultisigAddress, asset.Id, new BitcoinSecret(hubRevokeKey, _connectionParams.Network).ToString(), hubRevokeKey.PubKey.ToHex(), commitmentResult.Transaction.ToHex(), newClientAmount, newHubAmount, commitmentResult.LockedAddress, commitmentResult.LockedScript); return(commitmentResult.Transaction.ToHex()); }
private void ProceedSort() { var item = _repository.Categories.Item; TransactionComparer comparer = new TransactionComparer(_repository.Categories.Item); var reports = _repository.Reports.Item.Reports.ToList(); foreach (var report in reports) { report.Transactions.Sort(comparer); } _iOutput.ShowReports(reports); }
public IEnumerable <Transaction> Order(BlockHeader blockHeader, IEnumerable <Transaction> transactions) { UInt256 GetPriority(Transaction tx) => _priorities.TryGetValue(blockHeader, tx, out var destination) ? destination.Value : UInt256.Zero; ISet <Address> sendersWhitelist = _sendersWhitelist.GetItemsFromContractAtBlock(blockHeader).AsSet(); IComparer <Transaction> transactionComparer = new TransactionComparer( t => sendersWhitelist.Contains(t.SenderAddress), GetPriority); // We group transactions by sender. Each group is sorted by nonce and then by priority desc, then gasprice desc, then gaslimit asc // transactions grouped by sender with nonce order then priority: // A -> N0_P3, N1_P1, N1_P0, N3_P5... // B -> N4_P4, N5_P3, N6_P3... IEnumerable <IEnumerable <Transaction> > bySenderOrdered = transactions .Where(tx => tx != null) // for safety .GroupBy(tx => tx.SenderAddress) .Select(g => g.OrderBy(tx => tx.Nonce).ThenBy(t => t, transactionComparer)); return(Order(bySenderOrdered, transactionComparer)); }
public async Task Broadcast([FromBody] BroadcastTransactionRequest model) { var signRequest = await _transactionSignRequestRepository.GetSignRequest(model.TransactionId); if (signRequest == null) { throw new BackendException("Transaction is not found", ErrorCode.BadTransaction); } if (signRequest.Invalidated == true) { throw new BackendException("Transaction was invalidated", ErrorCode.BadTransaction); } var initialTransaction = await _transactionBlobStorage.GetTransaction(model.TransactionId, TransactionBlobType.Initial); if (!TransactionComparer.CompareTransactions(initialTransaction, model.Transaction)) { throw new BackendException("Signed transaction is not equals to initial transaction", ErrorCode.BadTransaction); } var transaction = new Transaction(model.Transaction); if (transaction.Inputs.All(o => o.ScriptSig == null || o.ScriptSig.Length == 0)) { throw new BackendException("Transaction is not signed by client", ErrorCode.BadTransaction); } var fullSignedHex = signRequest.DoNotSign ? model.Transaction : await _signatureApiProvider.SignTransaction(model.Transaction); await _transactionBlobStorage.AddOrReplaceTransaction(model.TransactionId, TransactionBlobType.Signed, fullSignedHex); var fullSigned = new Transaction(fullSignedHex); await _broadcastService.BroadcastTransaction(model.TransactionId, fullSigned, useHandlers : false, savePaidFees : !signRequest.DoNotSign); }
// Transactions can only be instantiated by type public Transactions(Type type) { this.type = type; comparer = new TransactionComparer(type); }
public async Task <ICommitment> GetCommitment(string multisig, string asset, string transactionHex) { return((await _table.GetDataAsync(o => o.Multisig == multisig && o.AssetId == asset && o.Actual)).FirstOrDefault(o => TransactionComparer.CompareTransactions(o.InitialTransaction, transactionHex))); }
public async Task <string> Finalize(string clientPubKey, string hotWalletPubKey, IAsset asset, string clientRevokePubKey, string signedByClientHubCommitment) { var address = await _multisigService.GetMultisig(clientPubKey); if (address == null) { throw new BackendException($"Client {clientPubKey} is not registered", ErrorCode.BadInputParameter); } var channel = await _offchainChannelRepository.GetChannel(address.MultisigAddress, asset.Id); if (channel == null) { throw new BackendException("Channel is not found", ErrorCode.ShouldOpenNewChannel); } var hubCommitment = await _commitmentRepository.GetLastCommitment(address.MultisigAddress, asset.Id, CommitmentType.Hub); if (hubCommitment == null) { throw new BackendException("Commitment is not found", ErrorCode.CommitmentNotFound); } if (!TransactionComparer.CompareTransactions(signedByClientHubCommitment, hubCommitment.InitialTransaction)) { throw new BackendException("Provided signed transaction is not equal initial transaction", ErrorCode.BadTransaction); } if (!await _signatureVerifier.Verify(signedByClientHubCommitment, clientPubKey, SigHash.Single | SigHash.AnyoneCanPay)) { throw new BackendException("Provided signed transaction is not signed by client", ErrorCode.BadTransaction); } var fullSignedCommitment = await _signatureApiProvider.SignTransaction(signedByClientHubCommitment, SigHash.Single | SigHash.AnyoneCanPay); if (!_signatureVerifier.VerifyScriptSigs(fullSignedCommitment)) { throw new BackendException("Transaction is not full signed", ErrorCode.BadFullSignTransaction); } await _commitmentRepository.SetFullSignedTransaction(hubCommitment.CommitmentId, address.MultisigAddress, asset.Id, fullSignedCommitment); var clientCommitmentResult = CreateCommitmentTransaction(address, new PubKey(clientPubKey), new PubKey(hotWalletPubKey), new PubKey(clientRevokePubKey), new PubKey(address.ExchangePubKey), asset, hubCommitment.ClientAmount, hubCommitment.HubAmount, channel.FullySignedChannel); var signedByHubCommitment = await _signatureApiProvider.SignTransaction(clientCommitmentResult.Transaction.ToHex(), SigHash.Single | SigHash.AnyoneCanPay); await _commitmentRepository.CreateCommitment(CommitmentType.Client, channel.ChannelId, address.MultisigAddress, asset.Id, null, clientRevokePubKey, signedByHubCommitment, hubCommitment.ClientAmount, hubCommitment.HubAmount, clientCommitmentResult.LockedAddress, clientCommitmentResult.LockedScript); if (!channel.IsBroadcasted) { var channelTr = new Transaction(channel.FullySignedChannel); await _lykkeTransactionBuilderService.SaveSpentOutputs(channel.ChannelId, channelTr); await _rpcBitcoinClient.BroadcastTransaction(channelTr, channel.ChannelId); await _offchainChannelRepository.SetChannelBroadcasted(address.MultisigAddress, asset.Id); if (channel.PrevChannelTrnasactionId.HasValue) { await _commitmentRepository.CloseCommitmentsOfChannel(address.MultisigAddress, asset.Id, channel.PrevChannelTrnasactionId.Value); } } await _offchainChannelRepository.UpdateAmounts(address.MultisigAddress, asset.Id, hubCommitment.ClientAmount, hubCommitment.HubAmount); return(signedByHubCommitment); }