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 byte[] SerializeMetadata(TransactionMetadata metadata)
        {
            Messages.TransactionMetadata transactionMetadataBuilder = new Messages.TransactionMetadata();
            transactionMetadataBuilder.Signatures.Add(metadata.Signatures.Select(
                                                          signature => new Messages.TransactionMetadata.Types.SignatureEvidence()
            {
                PublicKey = Google.Protobuf.ByteString.CopyFrom(signature.PublicKey.ToByteArray()),
                Signature = Google.Protobuf.ByteString.CopyFrom(signature.Signature.ToByteArray())
            }));

            return(transactionMetadataBuilder.ToByteArray());
        }