示例#1
0
        /// <summary>
        /// Parses a <see cref="ByteString"/> into an instance of a <see cref="RecordKey"/> object.
        /// </summary>
        /// <param name="keyData">The <see cref="ByteString"/> to parse.</param>
        /// <returns>The parsed <see cref="RecordKey"/>.</returns>
        public static RecordKey Parse(ByteString keyData)
        {
            if (keyData == null)
            {
                throw new ArgumentNullException(nameof(keyData));
            }

            byte[] key = keyData.ToByteArray();

            string[] parts = Encoding.UTF8.GetString(key, 0, key.Length).Split(new[] { ':' }, 3);
            if (parts.Length != 3)
            {
                throw new ArgumentOutOfRangeException(nameof(keyData));
            }

            RecordKey result = ParseRecord(
                parts[1],
                LedgerPath.Parse(parts[0]),
                parts[2]);

            // The byte representation of reencoded value must match the input
            if (!result.ToBinary().Equals(keyData))
            {
                throw new ArgumentOutOfRangeException(nameof(keyData));
            }

            return(result);
        }
示例#2
0
        public static async Task <IReadOnlyList <AccountStatus> > GetAccount(this ILedgerQueries queries, string account)
        {
            ByteString             prefix  = new ByteString(Encoding.UTF8.GetBytes(account + ":ACC:"));
            IReadOnlyList <Record> records = await queries.GetKeyStartingFrom(prefix);

            return(records
                   .Where(record => !record.Value.Equals(ByteString.Empty))
                   .Select(record => AccountStatus.FromRecord(RecordKey.Parse(record.Key), record))
                   .ToList()
                   .AsReadOnly());
        }
示例#3
0
        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));
        }
        /// <summary>
        /// Creates an instance of the <see cref="AccountStatus"/> class from an unparsed record.
        /// </summary>
        /// <param name="key">The key of the record.</param>
        /// <param name="record">The record to create the object from.</param>
        /// <returns>A new instance of the <see cref="AccountStatus"/> class.</returns>
        public static AccountStatus FromRecord(RecordKey key, Record record)
        {
            if (key.RecordType != RecordType.Account)
            {
                throw new ArgumentOutOfRangeException(nameof(key));
            }

            long amount;

            if (record.Value.Value.Count == 0)
            {
                amount = 0;
            }
            else if (record.Value.Value.Count == 8)
            {
                amount = BitConverter.ToInt64(record.Value.Value.Reverse().ToArray(), 0);
            }
            else
            {
                throw new ArgumentOutOfRangeException(nameof(record));
            }

            return(new AccountStatus(new AccountKey(key.Path, LedgerPath.Parse(key.Name)), amount, record.Version));
        }
        public static async Task <IReadOnlyDictionary <AccountKey, AccountStatus> > GetAccounts(this IStorageEngine store, IEnumerable <AccountKey> accounts)
        {
            IReadOnlyList <Record> records = await store.GetRecords(accounts.Select(account => account.Key.ToBinary()));

            return(records.Select(record => AccountStatus.FromRecord(RecordKey.Parse(record.Key), record)).ToDictionary(account => account.AccountKey, account => account));
        }
        public static async Task <Record> GetRecord(this IStorageEngine store, RecordKey key)
        {
            IReadOnlyList <Record> result = await store.GetRecords(new[] { key.ToBinary() });

            return(result[0]);
        }