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); }
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"]) }); } }
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()))); }
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))); }
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); }
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); }