public void Parse_Error() { ArgumentNullException exception = Assert.Throws <ArgumentNullException>(() => RecordKey.Parse(null)); Assert.Equal("keyData", exception.ParamName); // Invalid structure Assert.Throws <ArgumentOutOfRangeException>(() => RecordKey.Parse(new ByteString(Encoding.UTF8.GetBytes("/account/name/")))); // Unknown record type Assert.Throws <ArgumentOutOfRangeException>(() => RecordKey.Parse(new ByteString(Encoding.UTF8.GetBytes("/account/name/:DOESNOTEXIST:")))); // Incorrect number of additional components Assert.Throws <ArgumentOutOfRangeException>(() => RecordKey.Parse(new ByteString(Encoding.UTF8.GetBytes("/asset/name/:ACC:/other/:other")))); Assert.Throws <ArgumentOutOfRangeException>(() => RecordKey.Parse(new ByteString(Encoding.UTF8.GetBytes("/asset/name/:ACC")))); // Invalid path Assert.Throws <ArgumentOutOfRangeException>(() => RecordKey.Parse(new ByteString(Encoding.UTF8.GetBytes("account/name/:ACC:/")))); Assert.Throws <ArgumentOutOfRangeException>(() => RecordKey.Parse(new ByteString(Encoding.UTF8.GetBytes("/account/name/:ACC:account")))); }
protected override async Task AddTransaction(long transactionId, byte[] mutationHash, Mutation mutation) { foreach (Record record in mutation.Records) { RecordKey key = RecordKey.Parse(record.Key); var dbRecord = await Records.Where(r => r.Key == record.Key.ToByteArray()).FirstOrDefaultAsync(); //TODO: check if dbrecord is null dbRecord.Type = key.RecordType; dbRecord.Name = key.Name; Context.Update(dbRecord); await Context.SaveChangesAsync(); var newMutation = new Models.RecordMutation { RecordKey = record.Key.ToByteArray(), TransactionId = transactionId, MutationHash = mutationHash }; RecordMutations.Add(newMutation); await Context.SaveChangesAsync(); } }
public async Task <ActionResult> GetTransactionsByPath( [FromQuery(Name = "path")] string path) { if (!LedgerPath.TryParse(path, out LedgerPath ledgerPath)) { return(BadRequest()); } var directory = LedgerPath.FromSegments(ledgerPath.Segments.ToArray()); var accounts = await this.store.GetSubaccounts(directory.FullPath); var keys = accounts.Where(x => RecordKey.Parse(x.Key).RecordType == RecordType.Account).Select(x => x.Key); var transactionsData = await this.storageEngine.GetTransactionByRecordKeys(keys, new TransactionFilter()); var transactions = transactionsData.Select(x => new ExtTransaction(x)).ToList(); var hashtable = new Hashtable(); foreach (var transaction in transactions) { foreach (var record in transaction.Mutation.Records) { var val = BitConverter.ToInt64(record.Value.Value.Reverse().ToArray(), 0); hashtable.Add(transaction.MutationHash + record.Key.ToString(), val); } } var res = transactions.Select(x => TransactionToJsonExt(x, hashtable).Value).ToArray(); return(Json(res)); }
public Task <IList <Record> > GetRecords(IEnumerable <ByteString> keys) { return(Task.FromResult <IList <Record> >(keys.Select(key => { RecordKey recordKey = RecordKey.Parse(key); if (recordKey.Name == "acl") { if (recordKey.Path.FullPath == "/root/subitem/") { return new Record(key, GetValidAcl(), ByteString.Empty); } else if (recordKey.Path.FullPath == "/root/invalid/") { return new Record(key, GetInvalidAcl(), ByteString.Empty); } else if (recordKey.Path.FullPath == "/root/comment/") { return new Record(key, GetCommentedAcl(), ByteString.Empty); } } return new Record(key, ByteString.Empty, ByteString.Empty); }) .ToList())); }
protected override async Task AddTransaction(long transactionId, byte[] mutationHash, Mutation mutation) { foreach (Record record in mutation.Records) { RecordKey key = RecordKey.Parse(record.Key); await ExecuteAsync(@" UPDATE Records SET Type = @type, Name = @name WHERE Key = @key", new Dictionary <string, object>() { ["@key"] = record.Key.ToByteArray(), ["@type"] = (int)key.RecordType, ["@name"] = key.Name }); await ExecuteAsync(@" INSERT INTO RecordMutations (RecordKey, TransactionId, MutationHash) VALUES (@recordKey, @transactionId, @mutationHash)", new Dictionary <string, object>() { ["@recordKey"] = record.Key.ToByteArray(), ["@transactionId"] = transactionId, ["@mutationHash"] = mutationHash }); } }
public void Parse_Data() { ByteString data = new ByteString(Encoding.UTF8.GetBytes("/aka/name/:DATA:record:name")); RecordKey key = RecordKey.Parse(data); Assert.Equal(RecordType.Data, key.RecordType); Assert.Equal("/aka/name/", key.Path.FullPath); Assert.Equal("record:name", key.Name); }
public void Parse_Account() { ByteString data = new ByteString(Encoding.UTF8.GetBytes("/account/name/:ACC:/asset/name/")); RecordKey key = RecordKey.Parse(data); Assert.Equal(RecordType.Account, key.RecordType); Assert.Equal("/account/name/", key.Path.FullPath); Assert.Equal("/asset/name/", key.Name); }
protected override MongoDbRecord BuildMongoDbRecord(Record rec) { RecordKey key = RecordKey.Parse(rec.Key); var r = new MongoDbRecord { Key = rec.Key.ToByteArray(), KeyS = Encoding.UTF8.GetString(rec.Key.ToByteArray()), Value = rec.Value?.ToByteArray(), Version = rec.Version.ToByteArray(), Path = key.Path.Segments.ToArray(), Type = key.RecordType, Name = key.Name }; return(r); }
public Task <IReadOnlyList <Record> > GetRecords(IEnumerable <ByteString> keys) { return(Task.FromResult <IReadOnlyList <Record> >(keys.Select(key => { RecordKey recordKey = RecordKey.Parse(key); return new Record( key, new ByteString(BitConverter.GetBytes(this.accounts[recordKey.Path.FullPath]).Reverse()), ByteString.Empty); }) .ToList())); }
private object RecordToJson(Record record, string key, Hashtable hashtable) { var value = BitConverter.ToInt64(record.Value.Value.Reverse().ToArray(), 0); var prevVal = hashtable.ContainsKey(key) ? (long)hashtable[key] : 0; return(new { key = RecordKey.Parse(record.Key), value = value, version = record.Version.ToString(), delta = value - prevVal }); }
public static ParsedMutation Parse(Mutation mutation) { List <AccountStatus> accountMutations = new List <AccountStatus>(); List <KeyValuePair <RecordKey, ByteString> > dataRecords = new List <KeyValuePair <RecordKey, ByteString> >(); foreach (Record record in mutation.Records) { // This is used for optimistic concurrency and does not participate in the validation if (record.Value == null) { continue; } try { RecordKey key = RecordKey.Parse(record.Key); switch (key.RecordType) { case RecordType.Account: accountMutations.Add(AccountStatus.FromRecord(key, record)); break; case RecordType.Data: dataRecords.Add(new KeyValuePair <RecordKey, ByteString>(key, record.Value)); break; } } catch (ArgumentOutOfRangeException ex) when(ex.ParamName == "keyData") { // Deserializing and re-serializing the record gives a different result throw new TransactionInvalidException("NonCanonicalSerialization"); } catch (ArgumentOutOfRangeException ex) when(ex.ParamName == "path") { // The path is invalid throw new TransactionInvalidException("InvalidPath"); } catch (ArgumentOutOfRangeException ex) when(ex.ParamName == "recordType") { // The specified record type is unknown throw new TransactionInvalidException("InvalidRecord"); } catch (ArgumentOutOfRangeException ex) when(ex.ParamName == "record") { // The value of an ACC record could not be deserialized throw new TransactionInvalidException("InvalidRecord"); } } return(new ParsedMutation(accountMutations, dataRecords)); }
public void FromRecord_Set() { Record record = new Record( AccountKey.Parse("/the/account/", "/the/asset/").Key.ToBinary(), SerializeInt(100), binaryData[1]); AccountStatus status = AccountStatus.FromRecord(RecordKey.Parse(record.Key), record); Assert.Equal("/the/account/", status.AccountKey.Account.FullPath); Assert.Equal("/the/asset/", status.AccountKey.Asset.FullPath); Assert.Equal(100, status.Balance); Assert.Equal(binaryData[1], status.Version); }
public void FromRecord_Unset() { Record record = new Record( AccountKey.Parse("/the/account/", "/the/asset/").Key.ToBinary(), ByteString.Empty, binaryData[1]); AccountStatus status = AccountStatus.FromRecord(RecordKey.Parse(record.Key), record); Assert.Equal("/the/account/", status.AccountKey.Account.FullPath); Assert.Equal("/the/asset/", status.AccountKey.Asset.FullPath); Assert.Equal(0, status.Balance); Assert.Equal(binaryData[1], status.Version); }
public async Task <IList <OutboundTransaction> > GetUnprocessedTransactions() { string account = $"/asset/{assetName}/out/"; string asset = $"/asset/{assetName}/"; HttpClient client = new HttpClient(); HttpResponseMessage accountsResponse = await client.GetAsync(new Uri(tedChainUri, $"query/subaccounts?account={account}")); JArray records = JArray.Parse(await accountsResponse.EnsureSuccessStatusCode().Content.ReadAsStringAsync()); List <OutboundTransaction> result = new List <OutboundTransaction>(); foreach (JObject record in records) { ByteString mutationHash = ByteString.Parse((string)record["version"]); ByteString key = ByteString.Parse((string)record["key"]); RecordKey recordKey = RecordKey.Parse(key); if (recordKey.RecordType != RecordType.Account || recordKey.Name != $"/asset/{assetName}/") { continue; } HttpResponseMessage transactionResponse = await client.GetAsync(new Uri(tedChainUri, $"query/transaction?mutation_hash={mutationHash}")); JObject rawTransaction = JObject.Parse(await transactionResponse.EnsureSuccessStatusCode().Content.ReadAsStringAsync()); Transaction transaction = MessageSerializer.DeserializeTransaction(ByteString.Parse((string)rawTransaction["raw"])); Mutation mutation = MessageSerializer.DeserializeMutation(transaction.Mutation); // TODO: Validate that the record mutation has an empty version string target = GetPayingAddress(mutation); if (target != null) { long value = ParseInt(ByteString.Parse((string)record["value"])); result.Add(new OutboundTransaction(key, value, mutationHash, target)); } } return(result); }
public async Task GetAllRecords_Success() { await AddRecords("/a/:DATA:name1"); await AddRecords("/b/:DATA:name2"); await AddRecords("/c/:DATA:name3"); await AddRecords("/d/:DATA:name3"); await AddRecords("/e/:DATA:/path/1/"); await AddRecords("/f/:ACC:/path/1/"); await AddRecords("/g/:ACC:/path/2/"); IReadOnlyList <Record> result1 = await Indexes.GetAllRecords(RecordType.Data, "/path/1/"); IReadOnlyList <Record> result2 = await Indexes.GetAllRecords(RecordType.Data, "name3"); IReadOnlyList <Record> result3 = await Indexes.GetAllRecords(RecordType.Account, "/path/1/"); Assert.Equal(1, result1.Count); Assert.Equal("/e/", RecordKey.Parse(result1[0].Key).Path.FullPath); Assert.Equal(2, result2.Count); Assert.Equal("/c/", RecordKey.Parse(result2[0].Key).Path.FullPath); Assert.Equal("/d/", RecordKey.Parse(result2[1].Key).Path.FullPath); Assert.Equal(1, result3.Count); Assert.Equal("/f/", RecordKey.Parse(result3[0].Key).Path.FullPath); }
public async Task <ActionResult> GetFilteredTransactions() { string path; TransactionFilter filter; JObject body; try { string bodyContent; using (StreamReader streamReader = new StreamReader(Request.Body)) bodyContent = await streamReader.ReadToEndAsync(); body = JObject.Parse(bodyContent); path = body["path"].ToString(); var jFilter = (JObject)body["filter"]; filter = new TransactionFilter() { StartDate = (DateTime)jFilter["start"], EndDate = (DateTime)jFilter["end"] }; } catch (JsonReaderException) { return(BadRequest()); } if (!LedgerPath.TryParse(path, out LedgerPath ledgerPath)) { return(BadRequest()); } var directory = LedgerPath.FromSegments(ledgerPath.Segments.ToArray()); var accounts = await this.store.GetSubaccounts(directory.FullPath); var keys = accounts.Where(x => RecordKey.Parse(x.Key).RecordType == RecordType.Account).Select(x => x.Key); var transactionsData = await this.storageEngine.GetTransactionByRecordKeys(keys, filter); var transactions = transactionsData.Select(x => new ExtTransaction(x)).ToList(); var hash = new List <ByteString>(); foreach (var transaction in transactions) { hash.AddRange(transaction.Mutation.Records.Select(x => x.Version)); } var prevTransactionsData = await this.storageEngine.GetTransactionsByMutationHash(hash.Distinct()); var prevTransactions = prevTransactionsData.Select(x => new ExtTransaction(x)).ToList(); var hashtable = new Hashtable(); foreach (var transaction in prevTransactions) { foreach (var record in transaction.Mutation.Records) { var val = BitConverter.ToInt64(record.Value.Value.Reverse().ToArray(), 0); hashtable.Add(transaction.MutationHash + record.Key.ToString(), val); } } var res = transactions.Select(x => TransactionToJsonExt(x, hashtable).Value).ToArray(); return(Json(res)); }
protected override RecordKey ParseRecordKey(ByteString key) { return(RecordKey.Parse(key)); }