// ToDo: The finding of transaction in DB will probably has a better algorithm
        // The following one by one version is the preliminary design
        private async Task <Transaction> FindThePunishment(BalanceOperation op, MultisigOutputEntity output)
        {
            using (OffchainMonitorContext context = new OffchainMonitorContext())
            {
                var commitments = from c in context.Commitments
                                  where c.CommitmentOutput.TransactionId == output.TransactionId &&
                                  c.CommitmentOutput.OutputNumber == output.OutputNumber
                                  select c;

                if (commitments != null && commitments.Count() > 0)
                {
                    foreach (var c in commitments)
                    {
                        if (TransactionsMatch(c, op))
                        {
                            return(new Transaction(c.Punishment));
                        }
                    }
                }
                else
                {
                    // No commitment cosuming the specified output
                    return(null);
                }

                // No commitment found matching the specified transaction, spending multisig output
                return(null);
            }
        }
        public async Task CheckCommitmentBroadcast()
        {
            using (OffchainMonitorContext context = new OffchainMonitorContext())
            {
                var commitmentsToSearchFor = (from c in context.Commitments
                                              where c.Punished == false
                                              select c).ToArray();

                if (commitmentsToSearchFor.Count() > 0)
                {
                    for (int i = 0; i < commitmentsToSearchFor.Count(); i++)
                    {
                        var  c     = commitmentsToSearchFor[i];
                        bool found = false;
                        try
                        {
                            await rpcBitcoinClient.GetTransactionHex(c.CommitmentTxId);

                            found = true;
                        }
                        catch (RPCException exp)
                        {
                            if (!exp.Message.Contains("No such mempool or blockchain transaction."))
                            {
                                throw exp;
                            }
                            else
                            {
                                continue;
                            }
                        }
                        catch (Exception exp)
                        {
                            throw exp;
                        }

                        if (found)
                        {
                            try
                            {
                                await rpcBitcoinClient.BroadcastTransaction(new Transaction(c.Punishment), new Guid());

                                c.Punished = true;
                            }
                            catch (Exception exp)
                            {
                                throw exp;
                            }
                        }
                    }
                }

                await context.SaveChangesAsync();
            }
        }
예제 #3
0
        public async Task <IActionResult> AddCommitmentPunishmentPair([FromQuery] string commitment,
                                                                      [FromQuery] string punishment, [FromQuery] bool overwrite = false)
        {
            if (string.IsNullOrEmpty(commitment) || string.IsNullOrEmpty(punishment))
            {
                return(BadRequest("Passed parameters should not be null or empty"));
            }
            else
            {
                try
                {
                    Transaction cTx = new Transaction(commitment);
                    Transaction pTx = new Transaction(punishment);

                    using (OffchainMonitorContext context = new OffchainMonitorContext())
                    {
                        var matchedCommitment = (from c in context.Commitments
                                                 where c.CommitmentTxId == cTx.GetHash().ToString()
                                                 select c).FirstOrDefault();

                        if (matchedCommitment != null)
                        {
                            if (overwrite == false)
                            {
                                return(BadRequest("To overwrite an existing punishment for existing commitment id, the overwrite flag should bet set to true"));
                            }
                            else
                            {
                                matchedCommitment.Commitment = commitment;
                                matchedCommitment.Punishment = punishment;
                            }
                        }
                        else
                        {
                            var newlyAddedCommitment = new CommitmentEntity
                            {
                                Commitment     = commitment,
                                CommitmentTxId = cTx.GetHash().ToString(),
                                Punishment     = punishment
                            };

                            await context.Commitments.AddAsync(newlyAddedCommitment);
                        }

                        await context.SaveChangesAsync();
                    }
                }
                catch (Exception exp)
                {
                    throw exp;
                }

                return(Ok());
            }
        }
예제 #4
0
        public async Task Set <T>(string key, T value)
        {
            using (OffchainMonitorContext context = new OffchainMonitorContext())
            {
                var settingRecords = from record in context.Settings where record.Key == key select record;
                if (settingRecords.Count() > 0)
                {
                    context.Settings.RemoveRange(settingRecords);
                }

                context.Settings.Add(new SettingsEntity {
                    Key = key.ToString(), Value = value.ToString()
                });

                await context.SaveChangesAsync();
            }
        }
예제 #5
0
        public async Task <IActionResult> SetSettingsValue([FromQuery] string key, [FromQuery] string value)
        {
            key = key.Trim();
            if (string.IsNullOrEmpty(key))
            {
                return(BadRequest("Key should not be null or empty."));
            }

            if (string.IsNullOrEmpty(value))
            {
                return(BadRequest("Value should not be null or empty."));
            }

            if (key.ToLower() == "multisig")
            {
                BitcoinAddress address = null;
                try
                {
                    address = BitcoinAddress.Create(value);
                }
                catch (Exception exp)
                {
                    throw new Exception("Some problem in parsing the provided address.", exp);
                }
            }

            using (OffchainMonitorContext context = new OffchainMonitorContext())
            {
                var settingRecords = from record in context.Settings
                                     where record.Key == key.ToLower()
                                     select record;
                if (settingRecords.Count() > 0)
                {
                    context.Settings.RemoveRange(settingRecords);
                }

                context.Settings.Add(new SettingsEntity {
                    Key = key, Value = value
                });

                await context.SaveChangesAsync();
            }

            return(Ok());
        }
예제 #6
0
        /*
         * private readonly INoSQLTableStorage<LogEntity> _tableStorageError;
         * private readonly INoSQLTableStorage<LogEntity> _tableStorageWarning;
         * private readonly INoSQLTableStorage<LogEntity> _tableStorageInfo;
         *
         * public LogToTable(INoSQLTableStorage<LogEntity> tableStorageError, INoSQLTableStorage<LogEntity> tableStorageWarning, INoSQLTableStorage<LogEntity> tableStorageInfo)
         * {
         *  _tableStorageError = tableStorageError;
         *  _tableStorageInfo = tableStorageInfo;
         *  _tableStorageWarning = tableStorageWarning;
         * }
         */

        private async Task Insert(string level, string component, string process, string context, string type, string stack,
                                  string msg, DateTime?dateTime)
        {
            var dt        = dateTime ?? DateTime.UtcNow;
            var newEntity = new LogEntity
            {
                Level     = level,
                Component = component,
                Context   = context,
                DateTime  = dt,
                Msg       = msg,
                Process   = process,
                Stack     = stack,
                Type      = type
            };

            using (OffchainMonitorContext dbContext = new OffchainMonitorContext())
            {
                dbContext.Add(newEntity);
            }
        }
예제 #7
0
        public async Task <IActionResult> ListMonitoredCommitments([FromQuery] int from, [FromQuery] int to)
        {
            if (from < 0)
            {
                return(BadRequest("From should not be negative."));
            }

            if (to != -1 && to <= from)
            {
                return(BadRequest("To should be bigger than from"));
            }
            try
            {
                using (OffchainMonitorContext context = new OffchainMonitorContext())
                {
                    var records = (from record in context.Commitments
                                   select new { CommtmentTxId = record.CommitmentTxId, Commitment = record.Commitment, Punishment = record.Punishment, Punished = record.Punished }).Skip(from);

                    if (to != -1)
                    {
                        records = records.Take(to - from);
                    }

                    if (records.Count() > 0)
                    {
                        return(Json(records.ToList()));
                    }
                    else
                    {
                        return(BadRequest("No records to return."));
                    }
                }
            }
            catch (Exception exp)
            {
                throw exp;
            }
        }
예제 #8
0
        public async Task <IActionResult> GetSettingsValue([FromQuery] string key)
        {
            key = key.Trim();
            if (string.IsNullOrEmpty(key))
            {
                return(BadRequest("Key should not be null or empty."));
            }

            using (OffchainMonitorContext context = new OffchainMonitorContext())
            {
                var settingRecord = (from record in context.Settings where record.Key == key select record)
                                    .FirstOrDefault();

                if (settingRecord == null)
                {
                    return(BadRequest("Could not find a record for settings"));
                }
                else
                {
                    return(Ok(settingRecord.Value));
                }
            }
        }
예제 #9
0
 // ToDo: Use the DbContext from the caller
 public async Task <T> Get <T>(string key)
 {
     using (OffchainMonitorContext context = new OffchainMonitorContext())
     {
         var settingRecords = await(from record in context.Settings where record.Key == key select record)
                              .FirstOrDefaultAsync();
         if (settingRecords == null)
         {
             throw new Exception("The specified settings was not found.");
         }
         else
         {
             if (typeof(T) == typeof(string))
             {
                 return((T)(object)settingRecords.Value);
             }
             else
             {
                 return(default(T));
             }
         }
     }
 }
        public async Task CheckCommitmentBroadcastOld()
        {
            string  multisig = null;
            Network network  = Network.TestNet;

            try
            {
                multisig = await settingsRepository.Get <string>("multisig");

                network = await Helper.GetNetwork(settingsRepository);
            }
            catch (Exception exp)
            {
                return;
            }

            var outputs = await qBitNinjaApiCaller.GetAddressBalance(multisig, true, true);

            MultisigOutputEntity desiredOutput = null;

            using (OffchainMonitorContext context = new OffchainMonitorContext())
            {
                desiredOutput = (from o in context.MultisigOutputs
                                 orderby o.LastSeen ascending
                                 select o).FirstOrDefault();
            }

            if (desiredOutput == null)
            {
                // There is no commitment
                return;
            }
            else
            {
                foreach (var op in outputs.Operations)
                {
                    var found = op.ReceivedCoins.Where(o => o.Outpoint.Hash.ToString() == desiredOutput.TransactionId && o.Outpoint.N == desiredOutput.OutputNumber).Any();
                    if (found)
                    {
                        // The output is still unspent which means no commitments is spent
                        return;
                    }
                }
            }

            // The output has not been found, which means it has been spent by a commitment
            outputs = await qBitNinjaApiCaller.GetAddressBalance(multisig, true, false);

            foreach (var op in outputs.Operations)
            {
                bool found = op.SpentCoins.
                             Where(sc => sc.Outpoint.Hash.ToString() == desiredOutput.TransactionId && sc.Outpoint.N == desiredOutput.OutputNumber).Any();

                if (found)
                {
                    var respectivePunishment = await FindThePunishment(op, desiredOutput);

                    if (respectivePunishment != null)
                    {
                        await rpcBitcoinClient.BroadcastTransaction(respectivePunishment, new Guid());
                    }
                    else
                    {
                        // The punishment has not been found
                    }
                }
            }
        }
예제 #11
0
        public async Task <IActionResult> AddCommitmentPunishmentPairOldDesign([FromQuery] string commitment,
                                                                               [FromQuery] string punishment)
        {
            if (string.IsNullOrEmpty(commitment) || string.IsNullOrEmpty(punishment))
            {
                return(BadRequest("Passed parameters should not be null or empty"));
            }
            else
            {
                Transaction cTx = new Transaction(commitment);
                Transaction pTx = new Transaction(punishment);

                try
                {
                    using (OffchainMonitorContext context = new OffchainMonitorContext())
                    {
                        var newlyAddedCommitment = new CommitmentEntity
                        {
                            Commitment = commitment,
                            Punishment = punishment
                        };

                        bool found    = false;
                        var  multisig = await settingsRepository.Get <string>("multisig");

                        var netwok = await Helper.GetNetwork(settingsRepository);

                        for (int i = 0; i < cTx.Inputs.Count; i++)
                        {
                            var prevHash = cTx.Inputs[i].PrevOut.Hash.ToString();
                            var prevTx   = await bitcoinTransactionService.GetTransaction(prevHash);

                            var prevOut = cTx.Inputs[i].PrevOut;
                            if (prevTx.Outputs[prevOut.N].ScriptPubKey.GetDestinationAddress(netwok).ToString()
                                == multisig)
                            {
                                found = true;

                                var existingMultisigOutput = (from o in context.MultisigOutputs
                                                              where o.TransactionId == prevOut.Hash.ToString() && o.OutputNumber == prevOut.N
                                                              select o).FirstOrDefault();
                                if (existingMultisigOutput == null)
                                {
                                    var newMultisigOutput = new MultisigOutputEntity();
                                    newMultisigOutput.TransactionId = prevOut.Hash.ToString();
                                    newMultisigOutput.OutputNumber  = (int)prevOut.N;
                                    newMultisigOutput.LastSeen      = DateTime.UtcNow;
                                    await context.MultisigOutputs.AddAsync(newMultisigOutput);

                                    existingMultisigOutput = newMultisigOutput;
                                }

                                existingMultisigOutput.LastSeen = DateTime.UtcNow;
                                existingMultisigOutput.Commitments.Add(newlyAddedCommitment);

                                newlyAddedCommitment.CommitmentOutput = existingMultisigOutput;
                                await context.Commitments.AddAsync(newlyAddedCommitment);
                            }
                        }

                        if (!found)
                        {
                            return(BadRequest(string.Format("The provide transaction does not pay to multisig:{0}", multisig)));
                        }

                        await context.SaveChangesAsync();
                    }
                    return(Ok());
                }
                catch (Exception exp)
                {
                    throw exp;
                }
            }
        }