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