public async Task BroadcastCoinJoinIfFullySignedAsync() { using (await RoundSyncronizerLock.LockAsync()) { // Check if fully signed. if (SignedCoinJoin.Inputs.All(x => x.HasWitness())) { Logger.LogInfo <CcjRound>($"Round ({RoundId}): Trying to broadcast coinjoin."); try { Coin[] spentCoins = Alices.SelectMany(x => x.Inputs.Select(y => new Coin(y.OutPoint, y.Output))).ToArray(); Money networkFee = SignedCoinJoin.GetFee(spentCoins); Logger.LogInfo <CcjRound>($"Round ({RoundId}): Network Fee: {networkFee.ToString(false, false)} BTC."); Logger.LogInfo <CcjRound>($"Round ({RoundId}): Coordinator Fee: {SignedCoinJoin.Outputs.SingleOrDefault(x => x.ScriptPubKey == Constants.GetCoordinatorAddress(RpcClient.Network).ScriptPubKey)?.Value?.ToString(false, false) ?? "0"} BTC."); FeeRate feeRate = SignedCoinJoin.GetFeeRate(spentCoins); Logger.LogInfo <CcjRound>($"Round ({RoundId}): Network Fee Rate: {feeRate.FeePerK.ToDecimal(MoneyUnit.Satoshi) / 1000} satoshi/byte."); Logger.LogInfo <CcjRound>($"Round ({RoundId}): Number of inputs: {SignedCoinJoin.Inputs.Count}."); Logger.LogInfo <CcjRound>($"Round ({RoundId}): Number of outputs: {SignedCoinJoin.Outputs.Count}."); Logger.LogInfo <CcjRound>($"Round ({RoundId}): Serialized Size: {SignedCoinJoin.GetSerializedSize() / 1024} KB."); Logger.LogInfo <CcjRound>($"Round ({RoundId}): VSize: {SignedCoinJoin.GetVirtualSize() / 1024} KB."); foreach (var o in SignedCoinJoin.GetIndistinguishableOutputs().Where(x => x.count > 1)) { Logger.LogInfo <CcjRound>($"Round ({RoundId}): There are {o.count} occurences of {o.value.ToString(true, false)} BTC output."); } await RpcClient.SendRawTransactionAsync(SignedCoinJoin); Succeed(syncLock: false); Logger.LogInfo <CcjRound>($"Round ({RoundId}): Successfully broadcasted the CoinJoin: {SignedCoinJoin.GetHash()}."); } catch (Exception ex) { Logger.LogError <CcjRound>($"Round ({RoundId}): Failed to broadcast the CoinJoin: {SignedCoinJoin.GetHash()}."); Logger.LogError <CcjRound>(ex); Fail(syncLock: false); } } } }