/// <summary> /// Broadcast the partial transaction request to federation members. /// </summary> /// <param name="payload">The payload to broadcast.</param> private async Task BroadcastAsync(RequestPartialTransactionPayload payload) { if (this.AttachedPeer.IsConnected && this.federatedPegSettings.FederationNodeIpEndPoints.Contains(Utils.EnsureIPv6(this.AttachedPeer.PeerEndPoint))) { await this.AttachedPeer.SendMessageAsync(payload).ConfigureAwait(false); } }
/// <inheritdoc /> public async Task BroadcastAsync(RequestPartialTransactionPayload payload) { List <INetworkPeer> peers = this.connectionManager.ConnectedPeers.ToList(); var ipAddressComparer = new IPAddressComparer(); foreach (INetworkPeer peer in peers) { // Broadcast to peers. if (!peer.IsConnected) { continue; } if (this.federationGatewaySettings.FederationNodeIpEndPoints.Any(e => ipAddressComparer.Equals(e.Address, peer.PeerEndPoint.Address))) { try { await peer.SendMessageAsync(payload).ConfigureAwait(false); } catch (OperationCanceledException) { } } } }
/// <summary> /// Broadcast the partial transaction request to federation members. /// </summary> /// <param name="payload">The payload to broadcast.</param> private async Task BroadcastAsync(RequestPartialTransactionPayload payload) { if (this.federatedPegSettings.FederationNodeIpEndPoints.Any(e => this.ipAddressComparer.Equals(e.Address, this.AttachedPeer.PeerEndPoint.Address))) { await this.AttachedPeer.SendMessageAsync(payload).ConfigureAwait(false); } }
private async Task HandleConsolidationTransactionRequest(INetworkPeer peer, RequestPartialTransactionPayload payload) { ConsolidationSignatureResult result = this.inputConsolidator.CombineSignatures(payload.PartialTransaction); if (result.Signed) { this.logger.LogDebug("Signed consolidating transaction to produce {0} from {1}", result.TransactionResult.GetHash(), payload.PartialTransaction.GetHash()); await this.BroadcastAsync(payload.AddPartial(result.TransactionResult)); } }
/// <summary> /// Broadcast the partial transaction request to federation members. /// </summary> /// <param name="payload">The payload to broadcast.</param> private async Task BroadcastAsync(RequestPartialTransactionPayload payload) { this.logger.Debug("Broadcasting to {0}", this.AttachedPeer.PeerEndPoint.Address); await this.AttachedPeer.SendMessageAsync(payload).ConfigureAwait(false); }
///<inheritdoc/> public async Task <uint256> ProcessCounterChainSession(int blockHeight) { //todo this method is doing too much. factor some of this into private methods after we added the counterchainid. this.logger.LogTrace("({0}:'{1}'", nameof(blockHeight), blockHeight); this.logger.LogInformation("Session Registered."); // Check if this has already been done then we just return the transactionId if (this.sessions.TryGetValue(blockHeight, out var counterchainSession)) { // This is the mechanism that tells the round robin not to continue and also // notifies the monitorChain of the completed transactionId from the counterChain transaction. if (counterchainSession.CounterChainTransactionId != uint256.Zero) { // If we get here: // 1. One of the nodes became the boss and successfully broadcast a completed transaction. // 2. The monitor in this node received the block with the transaction (identified by the sessionId in the op_return). // 3. The monitor wrote the CounterChainTransactionId into the counterChainSession to indicate all was done. // This method then does not try to process the transaction and instead signals to the monitorChain that this // transaction already completed by passing back the transactionId. this.logger.LogInformation($"Counterchain Session for block: {blockHeight} was already completed. Doing nothing."); return(counterchainSession.CounterChainTransactionId); } } else { throw new InvalidOperationException($"No CounterChainSession found in the counter chain for block height {blockHeight}."); } // Check if the password has been added. If not, no need to go further. if (this.federationWalletManager.Secret == null || string.IsNullOrEmpty(this.federationWalletManager.Secret.WalletPassword)) { string errorMessage = "The password needed for signing multisig transactions is missing."; this.logger.LogError(errorMessage); throw new WalletException(errorMessage); } var wallet = this.federationWalletManager.GetWallet(); var multiSigAddress = wallet.MultiSigAddress; var recipients = counterchainSession.CrossChainTransactions.Select(s => new Recipient.Recipient { Amount = s.Amount, ScriptPubKey = BitcoinAddress.Create(s.DestinationAddress, this.network).ScriptPubKey }).ToList(); // We are the Boss so first I build the multisig transaction template. var multiSigContext = new TransactionBuildContext(recipients, this.federationWalletManager.Secret.WalletPassword, Encoding.UTF8.GetBytes(blockHeight.ToString())) { TransactionFee = Money.Coins(0.01m), MinConfirmations = 1, Shuffle = true, MultiSig = multiSigAddress, IgnoreVerify = true, Sign = false }; this.logger.LogInformation("Building template Transaction."); var templateTransaction = this.federationWalletTransactionHandler.BuildTransaction(multiSigContext); //add my own partial this.logger.LogInformation("Verify own partial."); var counterChainSession = this.VerifySession(blockHeight, templateTransaction); if (counterChainSession == null) { var exists = this.sessions.TryGetValue(blockHeight, out counterChainSession); if (exists) { return(counterChainSession.CounterChainTransactionId); } throw new InvalidOperationException($"No CounterChainSession found in the counter chain for block height {blockHeight}."); } this.MarkSessionAsSigned(counterChainSession); var partialTransaction = wallet.SignPartialTransaction(templateTransaction, this.federationWalletManager.Secret.WalletPassword); uint256 bossCard = BossTable.MakeBossTableEntry(blockHeight, this.federationGatewaySettings.PublicKey); this.logger.LogInformation("My bossCard: {0}.", bossCard); this.ReceivePartial(blockHeight, partialTransaction, bossCard); //now build the requests for the partials var requestPartialTransactionPayload = new RequestPartialTransactionPayload(templateTransaction, blockHeight); // Only broadcast to the federation members. var federationNetworkPeers = this.connectionManager.ConnectedPeers .Where(p => !p.Inbound && federationGatewaySettings.FederationNodeIpEndPoints.Any(e => this.ipAddressComparer.Equals(e.Address, p.PeerEndPoint.Address))); foreach (INetworkPeer peer in federationNetworkPeers) { try { this.logger.LogInformation("Broadcasting Partial Transaction Request to {0}.", peer.PeerEndPoint); await peer.SendMessageAsync(requestPartialTransactionPayload).ConfigureAwait(false); } catch (OperationCanceledException) { } } this.logger.LogTrace("(-)"); // We don't want to say this is complete yet. We wait until we get the transaction back in a block. return(uint256.Zero); }