public async Task <SignedTreeHead> AppendAsync(byte[] hash)
        {
            MerkleNode leafNode = new MerkleNode(_hasher.HashLeaf(hash));
            var        session  = await _client.StartSessionAsync();

            try
            {
                //session.StartTransaction();
                var root = await _roots.Find(session, _ => true)
                           .Sort(new SortDefinitionBuilder <MerkleRoot>()
                                 .Descending(r => r.TreeSize)).Limit(1).SingleOrDefaultAsync();

                if (root is null)
                {
                    MerkleLeaf leaf = new MerkleLeaf(0, _hasher.HashLeaf(hash));
                    await _leaves.InsertOneAsync(session, leaf);

                    await _nodes.InsertOneAsync(session, leafNode);

                    root = new MerkleRoot(leafNode.Level, leafNode.Hash, 1ul, _signer.Sign(leafNode.Hash), "");
                    await _roots.InsertOneAsync(session, root);
                }
                else
                {
                    var existingLeaf = await _leaves.Find(session, n => n.Hash == leafNode.Hash).AnyAsync();

                    if (existingLeaf)
                    {
                        _logger.LogInformation("The leaf {leafHash} already exist in the tree {treeHash}. Nothing was appended.", hash.ByteToHex(), root.Hash.ByteToHex());
                        return(CreateSignedTreeHead(root));
                    }
                    else
                    {
                        var nodesToInsert = new List <MerkleNode>(root.Level + 1)
                        {
                            leafNode
                        };
                        var stack       = new Stack <MerkleNode>(root.Level + 1);
                        var currentNode = await _nodes.Find(session, n => n.Hash == root.Hash).SingleAsync();

                        MerkleNode node;
                        if (currentNode.IsFull)
                        {
                            bool isFullNode = currentNode.Level == leafNode.Level && leafNode.IsFull;
                            node = new MerkleNode(new[] { currentNode.Hash, leafNode.Hash }, currentNode.Level + 1, _hasher.HashNode(currentNode.Hash, leafNode.Hash), isFullNode);
                            nodesToInsert.Add(node);
                        }
                        else
                        {
                            do
                            {
                                var left = await _nodes.Find(session, n => n.Hash == currentNode.Left).SingleAsync();

                                stack.Push(left);
                                var right = await _nodes.Find(session, n => n.Hash == currentNode.Right).SingleAsync();

                                currentNode = right;
                            } while (!currentNode.IsFull);

                            stack.Push(currentNode);
                            stack.Push(leafNode);
                            do
                            {
                                var  right      = stack.Pop();
                                var  left       = stack.Pop();
                                bool isFullNode = left.Level == right.Level && left.IsFull && right.IsFull;
                                node = new MerkleNode(new[] { left.Hash, right.Hash }, left.Level + 1, _hasher.HashNode(left.Hash, right.Hash), isFullNode);

                                nodesToInsert.Add(node);
                                stack.Push(node);
                            } while (stack.Count != 1);
                        }

                        MerkleLeaf leaf = new MerkleLeaf(root.TreeSize, _hasher.HashLeaf(hash));
                        await _leaves.InsertOneAsync(session, leaf);

                        await _nodes.InsertManyAsync(session, nodesToInsert);

                        root = new MerkleRoot(node.Level, node.Hash, root.TreeSize + 1, _signer.Sign(node.Hash), "");
                        await _roots.InsertOneAsync(session, root);
                    }
                }

                //session.CommitTransaction();
                _logger.LogInformation("The leaf {leafHash} was appended to tree {treeHash}.", hash.ByteToHex(), root.Hash.ByteToHex());
                return(CreateSignedTreeHead(root));
            }
            catch (Exception e)
            {
                //session.AbortTransaction();
                _logger.LogError(e, "An error occurred while appending the leaf {leaf}.", hash.ByteToHex());
                throw new MerkleTreeException($"An error occurred while appending the leaf {hash.ByteToHex()}.", e);
            }
        }
 private SignedTreeHead CreateSignedTreeHead(MerkleRoot root)
 {
     return(new SignedTreeHead(root.Hash, root.Signature, root.TreeSize, "bucket"));
 }