class MerkleTree implements Serializable {

    public static List<LeafNode> difference(@NotNull MerkleTree one, @Nullable MerkleTree two) {
        checkNotNull(one, "Expected tree is required!");

        if (null == two) {
            return one.getLeafNodes();
        }

        Deque<HashableNode> nodes1 = new ArrayDeque<>();
        Deque<HashableNode> nodes2 = new ArrayDeque<>();

        HashableNode current1 = one.root;
        HashableNode current2 = two.root;

        List<LeafNode> diff = new ArrayList<>();

        while ((!nodes1.isEmpty() || current1 != null) && (!nodes2.isEmpty() || current2 != null)) {
            if (current1 != null && current2 != null && current1 instanceof LeafNode && current2 instanceof LeafNode && !current1.equals(current2)) {
                log.debug("Nodes are diff {} : {}", current1, current2);
                diff.add((LeafNode) current2);
            }

            if (current1 instanceof BranchNode) {
                HashableNode rightNode = ((BranchNode) current1).getRight();
                if (rightNode != null) {
                    nodes1.push(rightNode);
                }
                current1 = ((BranchNode) current1).getLeft();
            } else {
                if (!nodes1.isEmpty()) {
                    current1 = nodes1.pop();
                } else {
                    current1 = null;
                }
            }

            if (current2 instanceof BranchNode) {
                HashableNode rightNode = ((BranchNode) current2).getRight();
                if (rightNode != null) {
                    nodes2.push(rightNode);
                }
                current2 = ((BranchNode) current2).getLeft();
            } else {
                if (!nodes2.isEmpty()) {
                    current2 = nodes2.pop();
                } else {
                    current2 = null;
                }
            }
        }

        return diff;
    }

    public  MerkleTree(Range<Long> fullRange, int maxDepth);

}