Example #1
0
 public ProofDTO(Proof proof)
 {
     ApplicationName = proof.ApplicationName;
     LogName = proof.LogName;
     SnapshotValue = proof.SnapshotValue;
     ProofBlobName = proof.ProofBlobName;
     CoinbaseTransactionID = proof.CoinbaseTransactionID;
     TimeBlock = proof.TimeBlock;
     BitcoinTransactionHash = proof.BitcoinTransactionHash;
     BitcoinBlockNumber = proof.BitcoinBlockNumber;
 }
Example #2
0
        private void ProcessQueueMessages(List<CloudQueueMessage> msgs)
        {
            Trace.TraceInformation("WorkerB (RoleInstance {0}: ProcessQueueMessages start", GetRoleInstance());

            HashTree hashTree = new HashTree(new SHA256Aggregator());
            List<Tuple<CloudQueueMessage, Snapshot>> goodMsgs = new List<Tuple<CloudQueueMessage, Snapshot>>();
            foreach (CloudQueueMessage msg in msgs)
            {
                // Log and delete if this is a "poison" queue message (repeatedly processed
                // and always causes an error that prevents processing from completing).
                // Production applications should move the "poison" message to a "dead message"
                // queue for analysis rather than deleting the message.
                if (msg.DequeueCount > 5)
                {
                    Trace.TraceError(
                        "Deleting poison message: message {0} Role Instance {1}.",
                        msg.ToString(),
                        GetRoleInstance()
                        );
                    snapshotsQueue.DeleteMessage(msg);
                    continue;
                }

                // Parse summarized snapshot retrieved from queue.
                string[] snapshotParts = msg.AsString.Split(new char[] { ',' });
                string partitionKey = snapshotParts[0];
                string rowKey = snapshotParts[1];
                string restartFlag = snapshotParts[2];

                var retrieveOperation = TableOperation.Retrieve<Snapshot>(partitionKey, rowKey);
                var retrievedResult = snapshotsTable.Execute(retrieveOperation);
                var snapshot = retrievedResult.Result as Snapshot;

                if (snapshot == null)
                {
                    Trace.TraceError("WorkerB: Snapshot does not exist for RK {0}", rowKey);
                    continue;
                }

                // If this is a restart, verify that the shapshot has not already been logged
                if (restartFlag == "1")
                {
                    /*if (snapshot.Status == "Complete")
                    {
                    }*/
                }

                // Add snapshot value into history tree
                hashTree.Append(snapshot.SnapshotValue);
                goodMsgs.Add(new Tuple<CloudQueueMessage, Snapshot>(msg, snapshot));
            }

            // Snapshot commitment into bitcoin
            Transaction transaction = SnapshotCommitmentIntoBitcoin(
                hashTree.RootCommitmentString
                );

            if (transaction == null)
            {
                Trace.TraceError("Snapshot into Bitcoin failed, unable to continue.");
                return;
            }

            for (int i = 0; i < goodMsgs.Count; ++i)
            {
                Snapshot snapshot = goodMsgs[i].Item2;
                string proofText = hashTree.GenerateMembershipProof(i).ToString();

                // Save proof
                string proofName = snapshot.RowKey + ".proof";
                SaveBlob(proofName, proofText);

                var proof = new Proof
                {
                    ApplicationName = snapshot.ApplicationName, // Sets partition key
                    RowKey = snapshot.RowKey,
                    LogName = snapshot.LogName,
                    SnapshotValue = snapshot.SnapshotValue,
                    ProofBlobName = proofName,
                    CoinbaseTransactionID = transaction.ID
                };

                // Save in archive
                var upsertOperation = TableOperation.InsertOrReplace(proof);
                proofsArchiveTable.Execute(upsertOperation);

                // TODO: Decide if need to mark as complete

                var deleteOperation = TableOperation.Delete(snapshot);
                snapshotsTable.Execute(deleteOperation);

                // Delete the associated queue message
                snapshotsQueue.DeleteMessage(goodMsgs[i].Item1);
            }

            Trace.TraceInformation("WorkerB (RoleInstance {0}: ProcessQueueMessages complete",
               GetRoleInstance()
               );
        }
        public ActionResult Audit(Proof proof)
        {
            ViewData["BlobURL"] = blobContainer.Uri.AbsoluteUri;
            ViewBag.ApplicationName = proof.ApplicationName;
            ViewBag.LogName = proof.LogName;
            ViewBag.LatestBlockNumber = BlockchainAPI.GetLatestBlock().BlockHeight;
            if (ModelState.IsValid)
            {
                DateTime dt;
                DateTime.TryParse(proof.TimeBlock, out dt);
                // Validate Query
                if (string.IsNullOrWhiteSpace(proof.ApplicationName))
                {
                    return View("Proofs", model:new List<Proof>());
                }
                else if (string.IsNullOrWhiteSpace(proof.LogName))
                {
                    return View("Proofs", model:new List<Proof>());
                }
                else if (dt.Ticks <= 0)
                {
                    dt = DateTime.Now;
                }

                Subscription subscriber = FindSubscription(proof.ApplicationName, proof.LogName);

                if (subscriber == null)
                {
                    return View("Proofs", model: new List<Proof>());
                }
                else if (subscriber.Verified != true)
                {
                    return View("Proofs", model: new List<Proof>());
                }

                TableRequestOptions reqOptions = new TableRequestOptions()
                {
                    MaximumExecutionTime = TimeSpan.FromSeconds(10),
                    RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(3), 3)
                };

                List<Proof> proofs;
                try
                {
                    Snapshot snapshot = new Snapshot()
                    {
                        ApplicationName = proof.ApplicationName,
                        LogName = proof.LogName,
                        TimeBlock = dt
                    };

                    var tableQuery = new TableQuery<Proof>().Where(
                        TableQuery.CombineFilters(
                            TableQuery.CombineFilters(
                                TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, proof.ApplicationName),
                                TableOperators.And,
                                TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThanOrEqual, snapshot.RowKey)
                                ),
                            TableOperators.And,
                            TableQuery.GenerateFilterCondition("LogName", QueryComparisons.Equal, proof.LogName)
                            )
                        );

                    proofs = proofsArchiveTable.ExecuteQuery(tableQuery, reqOptions).ToList();
                    if (proofs.Count == 0)
                    {
                        return View("Proofs", model: new List<Proof>());
                    }

                    Proof proofToAudit = null;
                    long maxTicks = 0;
                    foreach (Proof singleProof in proofs)
                    {
                        long ticks = DateTime.Parse(singleProof.TimeBlock).Ticks;
                        if (ticks > maxTicks)
                        {
                            maxTicks = ticks;
                            proofToAudit = singleProof;
                        }
                    }

                    //
                    // TODO: Make API Call, Update Database!
                    //
                    if (proofToAudit.BitcoinBlockNumber == null
                        || proofToAudit.BitcoinTransactionHash == null)
                    {
                        if (PopulateBitcoinInformation(proofToAudit))
                        {
                            var replaceOperation = TableOperation.Replace(proofToAudit);
                            proofsArchiveTable.Execute(replaceOperation);
                        }
                    }

                    return View("Proofs", model: new List<Proof>() { proofToAudit });
                }
                catch (StorageException se)
                {
                    ViewBag.errorMessage = "Timeout error, try again.";
                    Trace.TraceError(se.Message);
                    return View("Error: " + se.Message);
                }
            }

            return View("Proofs", model: new List<Proof>());
        }
        private bool PopulateBitcoinInformation(Proof proof)
        {
            APIKey apiKey = new APIKey(RoleEnvironment.GetConfigurationSettingValue(
                "CoinbaseAccountKey1"
                ));

            Transaction coinbaseTransaction = API.GetTransaction(proof.CoinbaseTransactionID, apiKey);

            if (coinbaseTransaction.Hash != null)
            {
                proof.BitcoinTransactionHash = coinbaseTransaction.Hash;
                BitcoinTransaction bitcoinTransaction =
                    BlockchainAPI.GetTransaction(coinbaseTransaction.Hash);
                if (bitcoinTransaction.BlockHeight > 0)
                {
                    proof.BitcoinBlockNumber = bitcoinTransaction.BlockHeight;
                    return true;
                }
            }

            return false;
        }