private async Task TransfertInternal(string from, string to, long amount, string asset)
        {
            var lAsset   = LedgerPath.Parse(asset);
            var aFrom    = new AccountKey(LedgerPath.Parse(from), lAsset);
            var aTo      = new AccountKey(LedgerPath.Parse(to), lAsset);
            var accounts = await Engine.GetAccounts(new[] { aFrom, aTo });

            var adFrom = accounts[aFrom];
            var adTo   = accounts[aTo];

            var rFrom = new Record(aFrom.Key.ToBinary(), LongToByteString(adFrom.Balance - amount), adFrom.Version);
            var rTo   = new Record(aTo.Key.ToBinary(), LongToByteString(adTo.Balance + amount), adTo.Version);

            Mutation m = new Mutation(ByteString.Empty, new[] { rFrom, rTo }, ByteString.Empty);

            int c = System.Threading.Interlocked.Increment(ref gcounter);

            Transaction t = new Transaction(
                new ByteString(MessageSerializer.SerializeMutation(m)),
                DateTime.UtcNow,
                new ByteString(BitConverter.GetBytes(c))
                );

            await Engine.AddTransactions(new[] { new ByteString(MessageSerializer.SerializeTransaction(t)) });

            //Output.WriteLine($"{prefix} - {from} ==> {to} Success Retry : {tryCount}");
        }
        public void Mutation_Success()
        {
            Mutation mutation = new Mutation(
                binaryData[0],
                new[]
            {
                new Record(binaryData[1], binaryData[2], binaryData[3]),
                new Record(binaryData[4], null, binaryData[5]),
            },
                binaryData[6]);

            byte[] result = MessageSerializer.SerializeMutation(mutation);

            Mutation finalMutation = MessageSerializer.DeserializeMutation(new ByteString(result));

            Assert.Equal(244, result.Length);
            Assert.Equal(mutation.Records.Count, finalMutation.Records.Count);
            Assert.Equal(mutation.Records[0].Key, finalMutation.Records[0].Key);
            Assert.Equal(mutation.Records[0].Value, finalMutation.Records[0].Value);
            Assert.Equal(mutation.Records[0].Version, finalMutation.Records[0].Version);
            Assert.Equal(mutation.Records[1].Key, finalMutation.Records[1].Key);
            Assert.Equal(mutation.Records[1].Value, finalMutation.Records[1].Value);
            Assert.Equal(mutation.Records[1].Version, finalMutation.Records[1].Version);
            Assert.Equal(mutation.Namespace, finalMutation.Namespace);
            Assert.Equal(mutation.Metadata, finalMutation.Metadata);
        }
예제 #3
0
        public async Task <TransactionInfo> PostMutation(Mutation mutation, ExtKey key)
        {
            var sm   = MessageSerializer.SerializeMutation(mutation).ToByteString();
            var hash = new uint256(NBitcoin.Crypto.Hashes.SHA256(NBitcoin.Crypto.Hashes.SHA256(sm.ToByteArray())));
            var msig = key.PrivateKey.Sign(hash).ToDER().ToByteString();
            var j    = JObject.FromObject(new
            {
                mutation   = sm.ToString(),
                signatures = new[] {
                    new
                    {
                        pub_key   = key.Neuter().PubKey.ToHex(),
                        signature = msig.ToString()
                    }
                }
            });

            using (var cli = new HttpClient())
            {
                cli.Timeout = TimeSpan.FromHours(1);
                var query   = $"{BaseUrl}submit";
                var tresult = await cli.PostAsync(query, new ByteArrayContent(Encoding.UTF8.GetBytes(j.ToString(Formatting.None))));

                var s = await tresult.Content.ReadAsStringAsync();

                var obj = JObject.Parse(s);
                return(new TransactionInfo {
                    MutationHash = ByteString.Parse((string)obj["mutation_hash"]), TransactionHash = ByteString.Parse((string)obj["transaction_hash"])
                });
            }
        }
예제 #4
0
        public async Task <ByteString> PostTransaction(ByteString rawMutation, IReadOnlyList <SignatureEvidence> authentication)
        {
            Mutation mutation;

            try
            {
                // Verify that the mutation can be deserialized
                mutation = MessageSerializer.DeserializeMutation(rawMutation);
            }
            catch (InvalidProtocolBufferException)
            {
                throw new TransactionInvalidException("InvalidMutation");
            }

            ParsedMutation parsedMutation = ParsedMutation.Parse(mutation);

            IReadOnlyDictionary <AccountKey, AccountStatus> accounts = await ValidateMutation(mutation, parsedMutation);

            ValidateAuthentication(authentication, MessageSerializer.ComputeHash(rawMutation.ToByteArray()));

            DateTime date = DateTime.UtcNow;

            IList <Mutation> generatedMutations = await this.validator.Validate(parsedMutation, authentication, accounts);

            TransactionMetadata metadata = new TransactionMetadata(authentication);

            byte[] rawMetadata = SerializeMetadata(metadata);

            Transaction transaction = new Transaction(rawMutation, date, new ByteString(rawMetadata));

            byte[] serializedTransaction = MessageSerializer.SerializeTransaction(transaction);

            List <ByteString> transactions = new List <ByteString>()
            {
                new ByteString(serializedTransaction)
            };

            transactions.AddRange(await Task.WhenAll(generatedMutations.Select(async generatedMutation =>
            {
                await ValidateMutation(generatedMutation, ParsedMutation.Parse(generatedMutation));
                Transaction generatedTransaction = new Transaction(new ByteString(MessageSerializer.SerializeMutation(generatedMutation)), date, ByteString.Empty);
                return(new ByteString(MessageSerializer.SerializeTransaction(generatedTransaction)));
            })));

            try
            {
                await this.store.AddTransactions(transactions);
            }
            catch (ConcurrentMutationException)
            {
                throw new TransactionInvalidException("OptimisticConcurrency");
            }

            return(new ByteString(MessageSerializer.ComputeHash(serializedTransaction)));
        }
        private async Task <ByteString> AddTransaction(params Record[] records)
        {
            Mutation    mutation           = new Mutation(ByteString.Parse("0123"), records, ByteString.Parse("4567"));
            ByteString  serializedMutation = new ByteString(MessageSerializer.SerializeMutation(mutation));
            Transaction transaction        = new Transaction(
                serializedMutation,
                new DateTime(1, 2, 3, 4, 5, 6),
                ByteString.Parse("abcdef"));

            await this.Store.AddTransactions(new[] { new ByteString(MessageSerializer.SerializeTransaction(transaction)) });

            return(new ByteString(MessageSerializer.ComputeHash(serializedMutation.ToByteArray())));
        }
예제 #6
0
        public async Task PostTransaction_EmptyMutation()
        {
            Dictionary <string, long> accounts = new Dictionary <string, long>();

            TransactionValidator validator = CreateValidator(accounts);
            Mutation             mutation  = new Mutation(
                validNamespace,
                new Record[0],
                ByteString.Empty);

            TransactionInvalidException exception = await Assert.ThrowsAsync <TransactionInvalidException>(
                () => validator.PostTransaction(new ByteString(MessageSerializer.SerializeMutation(mutation)), new SignatureEvidence[0]));

            Assert.Equal("InvalidMutation", exception.Reason);
        }
        private ByteString AddRecord(string key)
        {
            Mutation mutation = new Mutation(
                ByteString.Empty,
                new Record[] { new Record(new ByteString(Encoding.UTF8.GetBytes(key)), ByteString.Empty, ByteString.Empty) },
                ByteString.Empty);

            Transaction transaction = new Transaction(
                new ByteString(MessageSerializer.SerializeMutation(mutation)),
                new DateTime(),
                ByteString.Empty);

            this.transactions.Add(new ByteString(MessageSerializer.SerializeTransaction(transaction)));

            return(new ByteString(MessageSerializer.ComputeHash(MessageSerializer.SerializeTransaction(transaction))));
        }
        private async Task <byte[]> CreateTransaction(InboundTransaction transaction)
        {
            List <Record> records = new List <Record>();

            string issuanceAccount = $"/asset/{assetName}/in/{transaction.TransactionHash}/{transaction.OutputIndex}/";
            string asset           = $"/asset/{assetName}/";
            string toAddress       = transaction.Address;

            HttpClient          client           = new HttpClient();
            ByteString          issuanceKey      = Encode($"{issuanceAccount}:ACC:{asset}");
            HttpResponseMessage getValueResponse = await client.GetAsync(new Uri(tedChainUri, $"record?key={issuanceKey.ToString()}"));

            string stringResponse = await getValueResponse.EnsureSuccessStatusCode().Content.ReadAsStringAsync();

            ByteString issuanceVersion = ByteString.Parse((string)JObject.Parse(stringResponse)["version"]);

            // The transaction has already been submitted
            if (issuanceVersion.Value.Count != 0)
            {
                return(null);
            }

            ByteString key = Encode($"{toAddress}:ACC:{asset}");

            getValueResponse = await client.GetAsync(new Uri(tedChainUri, $"record?key={key.ToString()}"));

            JObject    toAccount        = JObject.Parse(await getValueResponse.EnsureSuccessStatusCode().Content.ReadAsStringAsync());
            ByteString version          = ByteString.Parse((string)toAccount["version"]);
            long       currentToBalance = ParseInt(ByteString.Parse((string)toAccount["value"]));

            records.Add(new Record(
                            key: issuanceKey,
                            value: new ByteString(BitConverter.GetBytes(-transaction.Amount).Reverse().ToArray()),
                            version: ByteString.Empty));

            records.Add(new Record(
                            key: key,
                            value: new ByteString(BitConverter.GetBytes(currentToBalance + transaction.Amount).Reverse().ToArray()),
                            version: version));

            Mutation mutation = new Mutation(
                Encode(this.tedChainUri.ToString()),
                records,
                ByteString.Empty);

            return(MessageSerializer.SerializeMutation(mutation));
        }
        private async Task AddRecords(params string[] keys)
        {
            Mutation mutation = new Mutation(
                ByteString.Empty,
                keys.Select(key => new Record(
                                new ByteString(Encoding.UTF8.GetBytes(key)),
                                ByteString.Empty,
                                ByteString.Empty)),
                ByteString.Empty);

            Transaction transaction = new Transaction(
                new ByteString(MessageSerializer.SerializeMutation(mutation)),
                new DateTime(),
                ByteString.Empty);

            await store.AddTransactions(new[] { new ByteString(MessageSerializer.SerializeTransaction(transaction)) });
        }
        private ByteString CreateMutation(ByteString @namespace)
        {
            Mutation mutation = new Mutation(
                @namespace,
                new Record[]
            {
                new Record(
                    new AccountKey(LedgerPath.Parse("/account/1/"), LedgerPath.Parse("/a/")).Key.ToBinary(),
                    new ByteString(BitConverter.GetBytes(100L).Reverse()),
                    ByteString.Empty),
                new Record(
                    new AccountKey(LedgerPath.Parse("/account/2/"), LedgerPath.Parse("/a/")).Key.ToBinary(),
                    new ByteString(BitConverter.GetBytes(100L).Reverse()),
                    ByteString.Empty),
            },
                ByteString.Empty);

            return(new ByteString(MessageSerializer.SerializeMutation(mutation)));
        }
        private ByteString CreateTransaction(params string[] keys)
        {
            Mutation mutation = new Mutation(
                ByteString.Empty,
                keys.Select(key => new Record(
                                new ByteString(Encoding.UTF8.GetBytes(key)),
                                ByteString.Parse("ab"),
                                ByteString.Parse("cd"))),
                ByteString.Empty);

            byte[] serializedMutation = MessageSerializer.SerializeMutation(mutation);

            Transaction transaction = new Transaction(
                new ByteString(MessageSerializer.SerializeMutation(mutation)),
                new DateTime(),
                ByteString.Empty);

            return(new ByteString(MessageSerializer.SerializeTransaction(transaction)));
        }
예제 #12
0
        public async Task PostTransaction_MaxKeySize()
        {
            Dictionary <string, long> accounts = new Dictionary <string, long>();

            TransactionValidator validator = CreateValidator(accounts);
            Mutation             mutation  = new Mutation(
                new ByteString(Encoding.UTF8.GetBytes("http://root/")),
                new Record[]
            {
                new Record(
                    ByteString.Parse(new string('a', 1025 * 2)),
                    new ByteString(BitConverter.GetBytes(100L).Reverse()),
                    ByteString.Empty)
            },
                ByteString.Empty);

            TransactionInvalidException exception = await Assert.ThrowsAsync <TransactionInvalidException>(
                () => validator.PostTransaction(new ByteString(MessageSerializer.SerializeMutation(mutation)), new SignatureEvidence[0]));

            Assert.Equal("InvalidMutation", exception.Reason);
        }
예제 #13
0
        private async Task <ByteString> AddRecords(ByteString version, ByteString value, params string[] keys)
        {
            Mutation mutation = new Mutation(
                ByteString.Empty,
                keys.Select(key => new Record(
                                new ByteString(Encoding.UTF8.GetBytes(key)),
                                value,
                                version)),
                ByteString.Empty);

            byte[] serializedMutation = MessageSerializer.SerializeMutation(mutation);

            Transaction transaction = new Transaction(
                new ByteString(MessageSerializer.SerializeMutation(mutation)),
                new DateTime(),
                ByteString.Empty);

            await Engine.AddTransactions(new[] { new ByteString(MessageSerializer.SerializeTransaction(transaction)) });

            return(new ByteString(MessageSerializer.ComputeHash(serializedMutation)));
        }
        public async Task PostTransaction_MaxKeySize()
        {
            Dictionary <string, long> accounts = new Dictionary <string, long>();

            TransactionValidator validator = CreateValidator(accounts);
            Mutation             mutation  = new Mutation(
                validNamespace,
                new Record[]
            {
                new Record(
                    new AccountKey(LedgerPath.Parse("/"), LedgerPath.Parse($"/{new string('a', 512)}/")).Key.ToBinary(),
                    new ByteString(BitConverter.GetBytes(100L).Reverse()),
                    ByteString.Empty)
            },
                ByteString.Empty);

            TransactionInvalidException exception = await Assert.ThrowsAsync <TransactionInvalidException>(
                () => validator.PostTransaction(new ByteString(MessageSerializer.SerializeMutation(mutation)), new SignatureEvidence[0]));

            Assert.Equal("InvalidMutation", exception.Reason);
            Assert.Equal(null, store.AddedTransactions);
        }
        public async Task MoveToRedemption(IList <OutboundTransaction> transactions, ByteString btcTransaction)
        {
            List <Record> records = new List <Record>();

            foreach (OutboundTransaction transaction in transactions)
            {
                // TODO: Allow double spending
                records.Add(new Record(
                                key: Encode($"/asset/{assetName}/tx/:DATA:{transaction.Version.ToString()}"),
                                value: Encode(JObject.FromObject(new { transactions = new[] { btcTransaction.ToString() } }).ToString()),
                                version: ByteString.Empty));

                records.Add(new Record(
                                key: transaction.RecordKey,
                                value: ByteString.Empty,
                                version: transaction.Version));
            }

            HttpClient          client           = new HttpClient();
            ByteString          finalKey         = Encode($"/asset/{assetName}/final/:ACC:/asset/{assetName}/");
            HttpResponseMessage getValueResponse = await client.GetAsync(new Uri(tedChainUri, $"record?key={finalKey.ToString()}"));

            string stringResponse = await getValueResponse.EnsureSuccessStatusCode().Content.ReadAsStringAsync();

            ByteString finalVersion = ByteString.Parse((string)JObject.Parse(stringResponse)["version"]);
            long       currentValue = ParseInt(ByteString.Parse((string)JObject.Parse(stringResponse)["value"]));

            records.Add(new Record(
                            key: finalKey,
                            value: Encode(currentValue + transactions.Sum(transaction => transaction.Amount)),
                            version: finalVersion));

            Mutation mutation = new Mutation(Encode(this.tedChainUri.ToString()), records, ByteString.Empty);

            byte[] serializedMutation = MessageSerializer.SerializeMutation(mutation);

            await SignAndSubmit(serializedMutation);
        }
        public async Task AddTransaction_MultipleTransactionsSuccess()
        {
            IList <Record> records1 = new Record[]
            {
                new Record(binaryData[0], binaryData[1], ByteString.Empty),
                new Record(binaryData[2], binaryData[3], ByteString.Empty),
            };

            ByteString mutation1     = new ByteString(MessageSerializer.SerializeMutation(new Mutation(ByteString.Empty, records1, ByteString.Empty)));
            ByteString mutationHash1 = new ByteString(MessageSerializer.ComputeHash(mutation1.ToByteArray()));

            IList <Record> records2 = new Record[]
            {
                new Record(binaryData[2], binaryData[5], mutationHash1),
                new Record(binaryData[6], binaryData[7], ByteString.Empty),
            };

            ByteString mutation2     = new ByteString(MessageSerializer.SerializeMutation(new Mutation(ByteString.Empty, records2, ByteString.Empty)));
            ByteString mutationHash2 = new ByteString(MessageSerializer.ComputeHash(mutation2.ToByteArray()));

            // Submit both transactions at once
            await this.Store.AddTransactions(new[]
            {
                new ByteString(MessageSerializer.SerializeTransaction(new Transaction(mutation1, new DateTime(), ByteString.Empty))),
                new ByteString(MessageSerializer.SerializeTransaction(new Transaction(mutation2, new DateTime(), ByteString.Empty)))
            });

            IReadOnlyList <Record> result1 = await this.Store.GetRecords(new[] { binaryData[0] });

            IReadOnlyList <Record> result2 = await this.Store.GetRecords(new[] { binaryData[2] });

            IReadOnlyList <Record> result3 = await this.Store.GetRecords(new[] { binaryData[6] });

            AssertRecord(result1[0], binaryData[0], binaryData[1], mutationHash1);
            AssertRecord(result2[0], binaryData[2], binaryData[5], mutationHash2);
            AssertRecord(result3[0], binaryData[6], binaryData[7], mutationHash2);
        }
        public async Task AddTransaction_MultipleTransactionsError()
        {
            IList <Record> records1 = new Record[]
            {
                new Record(binaryData[0], binaryData[1], ByteString.Empty),
                new Record(binaryData[2], binaryData[3], ByteString.Empty),
            };

            ByteString mutation1 = new ByteString(MessageSerializer.SerializeMutation(new Mutation(ByteString.Empty, records1, ByteString.Empty)));

            IList <Record> records2 = new Record[]
            {
                new Record(binaryData[2], binaryData[5], ByteString.Empty),
                new Record(binaryData[6], binaryData[7], ByteString.Empty),
            };

            ByteString mutation2 = new ByteString(MessageSerializer.SerializeMutation(new Mutation(ByteString.Empty, records2, ByteString.Empty)));

            // Submit both transactions at once
            ConcurrentMutationException exception = await Assert.ThrowsAsync <ConcurrentMutationException>(() => this.Store.AddTransactions(new[]
            {
                new ByteString(MessageSerializer.SerializeTransaction(new Transaction(mutation1, new DateTime(), ByteString.Empty))),
                new ByteString(MessageSerializer.SerializeTransaction(new Transaction(mutation2, new DateTime(), ByteString.Empty)))
            }));

            IReadOnlyList <Record> result1 = await this.Store.GetRecords(new[] { binaryData[0] });

            IReadOnlyList <Record> result2 = await this.Store.GetRecords(new[] { binaryData[2] });

            IReadOnlyList <Record> result3 = await this.Store.GetRecords(new[] { binaryData[6] });

            AssertRecord(exception.FailedMutation, binaryData[2], binaryData[5], ByteString.Empty);
            AssertRecord(result1[0], binaryData[0], ByteString.Empty, ByteString.Empty);
            AssertRecord(result2[0], binaryData[2], ByteString.Empty, ByteString.Empty);
            AssertRecord(result3[0], binaryData[6], ByteString.Empty, ByteString.Empty);
        }