Exemplo n.º 1
0
        public async Task Run(CancellationToken cancel)
        {
            while (!cancel.IsCancellationRequested)
            {
                try
                {
                    if (await this.anchorRecorder.CanRecordAnchor())
                    {
                        LedgerAnchor anchor = await this.anchorBuilder.CreateAnchor();

                        if (anchor != null)
                        {
                            logger.LogInformation($"Recording anchor for {anchor.TransactionCount} transaction(s)");

                            // Record the anchor
                            await this.anchorRecorder.RecordAnchor(anchor);

                            // Commit the anchor if it has been recorded successfully
                            await this.anchorBuilder.CommitAnchor(anchor);
                        }
                    }
                }
                catch (Exception exception)
                {
                    logger.LogError($"Error in the anchor worker:\r\n{exception}");

                    // Wait longer if an error occurred
                    await Task.Delay(TimeSpan.FromMinutes(1), cancel);
                }

                await Task.Delay(TimeSpan.FromSeconds(10), cancel);
            }
        }
        public async Task RecordAnchor_ZeroTransaction()
        {
            LedgerAnchor anchor = await this.anchorBuilder.RecordAnchor();

            Assert.Null(anchor);
            Assert.Equal(0, recorder.Anchors.Count);
            Assert.Null(state.LastAnchor);
        }
Exemplo n.º 3
0
        public async Task <LedgerAnchor> GetLastAnchor()
        {
            var anchor = await Anchors.OrderBy(a => a.Id).Take(1).FirstOrDefaultAsync();

            var ledgerAnchor = new LedgerAnchor(new ByteString(anchor.Position), new ByteString(anchor.FullLedgerHash), anchor.TransactionCount);

            return(ledgerAnchor);
        }
        public async Task CreateAnchor_CannotRecord()
        {
            recorder.Enabled = false;
            LedgerAnchor anchor = await this.anchorBuilder.RecordAnchor();

            Assert.Null(anchor);
            Assert.Equal(0, recorder.Anchors.Count);
            Assert.Null(state.LastAnchor);
        }
 /// <summary>
 /// Marks the anchor as successfully recorded in the anchoring medium.
 /// </summary>
 /// <param name="anchor">The anchor to commit.</param>
 /// <returns>The task object representing the asynchronous operation.</returns>
 public async Task CommitAnchor(LedgerAnchor anchor)
 {
     await AnchorStateCollection.InsertOneAsync(new MongoDbAnchorStateRecord
     {
         Position         = anchor.Position.ToByteArray(),
         FullLedgerHash   = anchor.FullStoreHash.ToByteArray(),
         TransactionCount = anchor.TransactionCount
     });
 }
        public async Task RecordAnchor_OneTransaction()
        {
            ByteString hash = AddRecord("key1");
            ByteString expectedCumulativeHash = CombineHashes(new ByteString(new byte[32]), hash);

            LedgerAnchor anchor = await this.anchorBuilder.RecordAnchor();

            AssertAnchor(anchor, 1, hash, expectedCumulativeHash);
            Assert.Equal(1, recorder.Anchors.Count);
            AssertAnchor(recorder.Anchors[0], 1, hash, expectedCumulativeHash);
            AssertAnchor(state.LastAnchor, 1, hash, expectedCumulativeHash);
        }
Exemplo n.º 7
0
        public async Task GetLastAnchor_Success()
        {
            await this.anchorBuilder.CommitAnchor(new LedgerAnchor(binaryData[0], binaryData[1], 100));

            await this.anchorBuilder.CommitAnchor(new LedgerAnchor(binaryData[2], binaryData[3], 101));

            LedgerAnchor anchor = await this.anchorBuilder.GetLastAnchor();

            Assert.Equal(binaryData[2], anchor.Position);
            Assert.Equal(binaryData[3], anchor.FullStoreHash);
            Assert.Equal(101, anchor.TransactionCount);
        }
Exemplo n.º 8
0
        public async Task CommitAnchor(LedgerAnchor anchor)
        {
            var newAnchor = new Models.Anchor
            {
                Position         = anchor.Position.ToByteArray(),
                FullLedgerHash   = anchor.FullStoreHash.ToByteArray(),
                TransactionCount = anchor.TransactionCount
            };

            Anchors.Add(newAnchor);

            await Context.SaveChangesAsync();
        }
        public async Task RecordAnchor_OnePlusOneTransaction()
        {
            state.LastAnchor = new LedgerAnchor(binaryData[1], binaryData[2], 1);
            ByteString hash = AddRecord("key2");
            ByteString expectedCumulativeHash = CombineHashes(binaryData[2], hash);

            LedgerAnchor anchor = await this.anchorBuilder.RecordAnchor();

            AssertAnchor(anchor, 2, hash, expectedCumulativeHash);
            Assert.Equal(1, recorder.Anchors.Count);
            AssertAnchor(recorder.Anchors[0], 2, hash, expectedCumulativeHash);
            AssertAnchor(state.LastAnchor, 2, hash, expectedCumulativeHash);
        }
Exemplo n.º 10
0
 /// <summary>
 /// Marks the anchor as successfully recorded in the anchoring medium.
 /// </summary>
 /// <param name="anchor">The anchor to commit.</param>
 /// <returns>The task object representing the asynchronous operation.</returns>
 public async Task CommitAnchor(LedgerAnchor anchor)
 {
     await ExecuteAsync(@"
             INSERT INTO Anchors
             (Position, FullLedgerHash, TransactionCount)
             VALUES (@position, @fullLedgerHash, @transactionCount)",
                        new Dictionary <string, object>()
     {
         ["@position"]         = anchor.Position.ToByteArray(),
         ["@fullLedgerHash"]   = anchor.FullStoreHash.ToByteArray(),
         ["@transactionCount"] = anchor.TransactionCount
     });
 }
Exemplo n.º 11
0
        public async Task Run(CancellationToken cancel)
        {
            IServiceScopeFactory scopeFactory = services.GetService <IServiceScopeFactory>();
            ILogger logger = services.GetRequiredService <ILogger>();

            while (!cancel.IsCancellationRequested)
            {
                using (IServiceScope scope = scopeFactory.CreateScope())
                {
                    IAnchorRecorder anchorRecorder = scope.ServiceProvider.GetService <IAnchorRecorder>();
                    IAnchorState    anchorState    = scope.ServiceProvider.GetService <IAnchorState>();

                    if (anchorRecorder == null || anchorState == null)
                    {
                        logger.LogInformation("Anchoring disabled");
                        return;
                    }

                    IStorageEngine storageEngine = scope.ServiceProvider.GetRequiredService <IStorageEngine>();

                    try
                    {
                        await storageEngine.Initialize();

                        await anchorState.Initialize();

                        AnchorBuilder anchorBuilder = new AnchorBuilder(storageEngine, anchorRecorder, anchorState);

                        while (!cancel.IsCancellationRequested)
                        {
                            LedgerAnchor anchor = await anchorBuilder.RecordAnchor();

                            if (anchor != null)
                            {
                                logger.LogInformation($"Recorded an anchor for {anchor.TransactionCount} transactions: {anchor.FullStoreHash.ToString()}");
                            }

                            await Task.Delay(TimeSpan.FromSeconds(10), cancel);
                        }
                    }
                    catch (Exception exception)
                    {
                        logger.LogError($"Error in the anchor worker:\r\n{exception}");

                        // Wait longer if an error occurred
                        await Task.Delay(TimeSpan.FromMinutes(1), cancel);
                    }
                }
            }
        }
        /// <summary>
        /// Records a database anchor.
        /// </summary>
        /// <param name="anchor">The anchor to be recorded.</param>
        /// <returns>The task object representing the asynchronous operation.</returns>
        public async Task RecordAnchor(LedgerAnchor anchor)
        {
            byte[] anchorPayload =
                anchorMarker
                .Concat(BitConverter.GetBytes((ulong)anchor.TransactionCount).Reverse())
                .Concat(anchor.FullStoreHash.ToByteArray())
                .ToArray();

            using (HttpClient client = new HttpClient())
            {
                BitcoinAddress      address  = this.publishingAddress.ScriptPubKey.GetDestinationAddress(this.network);
                HttpResponseMessage response = await client.GetAsync(new Uri(url, $"addresses/{address.ToString()}/unspents"));

                response.EnsureSuccessStatusCode();

                string body = await response.Content.ReadAsStringAsync();

                JArray outputs = JArray.Parse(body);

                //Changed the builder constructor
                //TODO: make sure transa
                TransactionBuilder builder = Network.Main.CreateTransactionBuilder();
                builder.AddKeys(publishingAddress.GetBitcoinSecret(network));
                foreach (JObject output in outputs)
                {
                    string transactionHash = (string)output["transaction_hash"];
                    uint   outputIndex     = (uint)output["output_index"];
                    long   amount          = (long)output["value"];

                    builder.AddCoins(new Coin(uint256.Parse(transactionHash), outputIndex, new Money(amount), publishingAddress.ScriptPubKey));
                }

                Script opReturn = new Script(OpcodeType.OP_RETURN, Op.GetPushOp(anchorPayload));
                builder.Send(opReturn, 0L);
                builder.SendFees(satoshiFees);
                builder.SetChange(this.publishingAddress.ScriptPubKey, ChangeType.All);

                ByteString seriazliedTransaction = new ByteString(builder.BuildTransaction(true).ToBytes());

                await SubmitTransaction(seriazliedTransaction);
            }
        }
Exemplo n.º 13
0
        /// <summary>
        /// Records a database anchor.
        /// </summary>
        /// <param name="anchor">The anchor to be recorded.</param>
        /// <returns>The task object representing the asynchronous operation.</returns>
        public async Task RecordAnchor(LedgerAnchor anchor)
        {
            byte[] anchorPayload =
                anchorMarker
                .Concat(BitConverter.GetBytes((ulong)anchor.TransactionCount).Reverse())
                .Concat(anchor.FullStoreHash.ToByteArray())
                .ToArray();

            using (HttpClient client = new HttpClient())
            {
                BitcoinAddress address = this.publishingAddress.ScriptPubKey.GetDestinationAddress(this.network);
                HttpResponseMessage response = await client.GetAsync(new Uri(url, $"addresses/{address.ToString()}/unspents"));

                response.EnsureSuccessStatusCode();

                string body = await response.Content.ReadAsStringAsync();

                JArray outputs = JArray.Parse(body);

                TransactionBuilder builder = new TransactionBuilder();
                builder.AddKeys(publishingAddress.GetBitcoinSecret(network));
                foreach (JObject output in outputs)
                {
                    string transactionHash = (string)output["transaction_hash"];
                    uint outputIndex = (uint)output["output_index"];
                    long amount = (long)output["value"];

                    builder.AddCoins(new Coin(uint256.Parse(transactionHash), outputIndex, new Money(amount), publishingAddress.ScriptPubKey));
                }

                Script opReturn = new Script(OpcodeType.OP_RETURN, Op.GetPushOp(anchorPayload));
                builder.Send(opReturn, 0);
                builder.SendFees(satoshiFees);
                builder.SetChange(this.publishingAddress.ScriptPubKey, ChangeType.All);

                ByteString seriazliedTransaction = new ByteString(builder.BuildTransaction(true).ToBytes());

                await SubmitTransaction(seriazliedTransaction);
            }
        }
Exemplo n.º 14
0
 public Task CommitAnchor(LedgerAnchor anchor)
 {
     this.LastAnchor = anchor;
     return Task.FromResult(0);
 }
Exemplo n.º 15
0
 public Task RecordAnchor(LedgerAnchor anchor)
 {
     Anchors.Add(anchor);
     return Task.FromResult(0);
 }
Exemplo n.º 16
0
 private void AssertAnchor(LedgerAnchor anchor, long transactionCount, ByteString position, ByteString fullStoreHash)
 {
     Assert.Equal(transactionCount, anchor.TransactionCount);
     Assert.Equal(position, anchor.Position);
     Assert.Equal(fullStoreHash, anchor.FullStoreHash);
 }
Exemplo n.º 17
0
 private void AssertAnchor(LedgerAnchor anchor, long transactionCount, ByteString position, ByteString fullStoreHash)
 {
     Assert.Equal(transactionCount, anchor.TransactionCount);
     Assert.Equal(position, anchor.Position);
     Assert.Equal(fullStoreHash, anchor.FullStoreHash);
 }
Exemplo n.º 18
0
        public async Task GetLastAnchor_NoAnchor()
        {
            LedgerAnchor anchor = await this.anchorBuilder.GetLastAnchor();

            Assert.Null(anchor);
        }
Exemplo n.º 19
0
 public Task RecordAnchor(LedgerAnchor anchor)
 {
     Anchors.Add(anchor);
     return(Task.FromResult(0));
 }
Exemplo n.º 20
0
 public Task CommitAnchor(LedgerAnchor anchor)
 {
     this.LastAnchor = anchor;
     return(Task.FromResult(0));
 }
Exemplo n.º 21
0
        /// <summary>
        /// Creates a database anchor for the current state of the database.
        /// </summary>
        /// <returns>The task object representing the asynchronous operation.</returns>
        public async Task <LedgerAnchor> CreateAnchor()
        {
            IEnumerable <LedgerAnchor> anchors = await ExecuteAsync(@"
                    SELECT  Position, FullLedgerHash, TransactionCount
                    FROM    Anchors
                    ORDER BY Id DESC
                    LIMIT 1",
                                                                    reader => new LedgerAnchor(
                                                                        new ByteString((byte[])reader.GetValue(0)),
                                                                        new ByteString((byte[])reader.GetValue(1)),
                                                                        reader.GetInt64(2)),
                                                                    new Dictionary <string, object>());

            LedgerAnchor lastAnchor = anchors.FirstOrDefault();

            IReadOnlyList <ByteString> newTransactions;

            byte[] currentHash;
            if (lastAnchor != null)
            {
                newTransactions = await ExecuteAsync(@"
                        SELECT  Hash
                        FROM    Transactions
                        WHERE   Id > (SELECT Id FROM Transactions WHERE Hash = @hash)
                        ORDER BY Id",
                                                     reader => new ByteString((byte[])reader.GetValue(0)),
                                                     new Dictionary <string, object>()
                {
                    ["@hash"] = lastAnchor.Position.ToByteArray()
                });

                currentHash = lastAnchor.FullStoreHash.ToByteArray();
            }
            else
            {
                newTransactions = await ExecuteAsync(@"
                        SELECT  Hash
                        FROM    Transactions
                        ORDER BY Id",
                                                     reader => new ByteString((byte[])reader.GetValue(0)),
                                                     new Dictionary <string, object>());

                currentHash = new byte[32];
            }

            if (newTransactions.Count == 0)
            {
                return(null);
            }

            byte[] buffer = new byte[64];
            using (SHA256 sha = SHA256.Create())
            {
                foreach (ByteString transactionHash in newTransactions)
                {
                    currentHash.CopyTo(buffer, 0);
                    transactionHash.CopyTo(buffer, 32);

                    currentHash = sha.ComputeHash(sha.ComputeHash(buffer));
                }
            }

            LedgerAnchor result = new LedgerAnchor(
                newTransactions[newTransactions.Count - 1],
                new ByteString(currentHash),
                newTransactions.Count + (lastAnchor != null ? lastAnchor.TransactionCount : 0));

            return(result);
        }