#![allow(warnings)]
use sha2::{Sha256, Digest};
use crate::utils::operation::Params;
use crate::encoding::gtv::encode_value as gtv_encode_value;
#[derive(Clone, PartialEq, Debug)]
enum NodeType {
Node,
Leaf,
EmptyLeaf,
DictNode,
ArrayNode,
}
#[derive(Clone, Debug)]
pub enum HashError {
EmptyArray(String),
EmptyDict(String),
}
#[derive(Clone, Debug)]
struct BinaryTreeNode {
left: Option<Box<BinaryTreeNode>>,
right: Option<Box<BinaryTreeNode>>,
value: Option<Box<Params>>,
type_of_node: NodeType
}
impl Default for BinaryTreeNode {
fn default() -> Self {
BinaryTreeNode {
left: None,
right: None,
value: None,
type_of_node: NodeType::EmptyLeaf,
}
}
}
impl BinaryTreeNode {
fn new_node(left: Option<Box<BinaryTreeNode>>, right: Option<Box<BinaryTreeNode>>, value: Option<Box<Params>>, type_of_node: NodeType) -> Self {
BinaryTreeNode {
left, right, value, type_of_node
}
}
fn new_leaf(value: Option<Box<Params>>, is_empty_leaf: bool) -> Box<Self> {
let type_of_node = match is_empty_leaf {
true => NodeType::EmptyLeaf,
false => NodeType::Leaf,
};
Box::new(BinaryTreeNode {
value, type_of_node, ..Default::default()
})
}
}
#[derive(Clone, Debug)]
struct BinaryTreeFactory;
impl BinaryTreeFactory {
fn process_layer(leaves: Vec<Box<BinaryTreeNode>>) -> Result<Box<BinaryTreeNode>, HashError> {
if leaves.is_empty() {
return Err(HashError::EmptyArray("Cannot process empty layer of nodes".to_string()));
}
if leaves.len() == 1 {
return Ok(leaves.into_iter().next().unwrap());
}
let results = leaves.chunks(2)
.map(|chunk| {
if chunk.len() == 2 {
let left = chunk[0].clone();
let right = chunk[1].clone();
BinaryTreeNode::new_node(Some(left), Some(right), None, NodeType::Node)
} else {
*chunk[0].clone()
}
})
.map(Box::new)
.collect::<Vec<_>>();
Self::process_layer(results)
}
fn process_array_node(params: Box<Params>, hash_version: u8) -> Result<Box<BinaryTreeNode>, HashError> {
if let Params::Array(array_value) = &*params {
if array_value.is_empty() {
let left = BinaryTreeNode::new_leaf(None, true);
let right = BinaryTreeNode::new_leaf(None, true);
let value = Box::new(Params::Array(Vec::new()));
return Ok(Box::new(BinaryTreeNode::new_node(Some(left), Some(right), Some(value), NodeType::ArrayNode)));
}
if hash_version == 1 && array_value.len() == 1 {
let av = array_value[0].clone();
if let Params::Array(_) = av {
return Self::build_tree(Box::new(av), hash_version);
}
if let Params::Dict(_) = av {
return Self::build_tree(Box::new(Params::Array(av.dict_to_array())), hash_version);
}
}
let leaves: Result<Vec<_>, _> = array_value
.iter()
.map(|value| Box::new(value.clone()))
.map(|params| Self::build_tree(params, hash_version))
.collect();
let leaves = leaves?;
let value = Box::new(Params::Array(array_value.clone()));
let tree_root = if leaves.len() == 1 {
let left = leaves.into_iter().next().unwrap();
let right = BinaryTreeNode::new_leaf(None, true);
BinaryTreeNode::new_node(Some(left), Some(right), None, NodeType::Node)
} else {
*Self::process_layer(leaves)?
};
let node = BinaryTreeNode::new_node(tree_root.left, tree_root.right, Some(value), NodeType::ArrayNode);
Ok(Box::new(node))
} else {
Err(HashError::EmptyArray("Invalid array parameter provided".to_string()))
}
}
fn process_dict_node(params: Box<Params>, hash_version: u8) -> Result<Box<BinaryTreeNode>, HashError> {
if let Params::Dict(dict_value) = &*params {
if dict_value.is_empty() {
let left = BinaryTreeNode::new_leaf(None, true);
let right = BinaryTreeNode::new_leaf(None, true);
let value = Box::new(Params::Dict(std::collections::BTreeMap::new()));
return Ok(Box::new(BinaryTreeNode::new_node(Some(left), Some(right), Some(value), NodeType::DictNode)));
}
let leaves: Result<Vec<_>, _> = dict_value
.iter()
.flat_map(|(key, value)| {
let key_leaf = BinaryTreeNode::new_leaf(Some(Box::new(Params::Text(key.clone()))), false);
let value_tree = Self::build_tree(Box::new(value.clone()), hash_version);
match value_tree {
Ok(tree) => vec![Ok(key_leaf), Ok(tree)],
Err(err) => vec![Err(err)],
}
})
.collect();
let leaves = leaves?;
let value = Box::new(Params::Dict(dict_value.clone()));
let tree_root = if leaves.len() == 1 {
let left = leaves.into_iter().next().unwrap();
let right = BinaryTreeNode::new_leaf(None, true);
BinaryTreeNode::new_node(Some(left), Some(right), None, NodeType::Node)
} else {
*Self::process_layer(leaves)?
};
let node = BinaryTreeNode::new_node(tree_root.left, tree_root.right, Some(value), NodeType::DictNode);
Ok(Box::new(node))
} else {
Err(HashError::EmptyDict("Invalid dictionary parameter provided".to_string()))
}
}
fn build_tree(params: Box<Params>, hash_version: u8) -> Result<Box<BinaryTreeNode>, HashError> {
match *params {
Params::Array(_) =>
Self::process_array_node(params, hash_version),
Params::Dict(_) =>
Self::process_dict_node(params, hash_version),
_ =>
Ok(BinaryTreeNode::new_leaf(Some(params), false))
}
}
}
struct MerkleHashCalculator;
const HASH_PREFIX_LEAF: u8 = 1;
const HASH_PREFIX_NODE: u8 = 0;
const HASH_PREFIX_NODE_ARRAY: u8 = 7;
const HASH_PREFIX_NODE_DICT: u8 = 8;
impl MerkleHashCalculator {
fn sha256(data: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(data);
hasher.finalize().into()
}
fn calculate_leaf_hash(value: &Params) -> [u8; 32] {
let gev = gtv_encode_value(value);
let mut buffer = Vec::with_capacity(1 + gev.len());
buffer.push(HASH_PREFIX_LEAF);
buffer.extend_from_slice(&gev);
Self::sha256(&buffer)
}
fn calculate_node_hash(has_prefix: u8, left: [u8; 32], right: [u8; 32]) -> [u8; 32] {
let mut buffer = [0u8; 65];
buffer[0] = has_prefix;
buffer[1..33].copy_from_slice(&left);
buffer[33..].copy_from_slice(&right);
Self::sha256(&buffer)
}
fn calculate_merkle_hash(btn: &BinaryTreeNode) -> [u8; 32] {
match &btn.type_of_node {
NodeType::EmptyLeaf => [0; 32],
NodeType::Leaf => Self::calculate_leaf_hash(btn.value.as_ref().unwrap()),
NodeType::ArrayNode | NodeType::DictNode | NodeType::Node => {
let has_prefix = match btn.type_of_node {
NodeType::ArrayNode => HASH_PREFIX_NODE_ARRAY,
NodeType::DictNode => HASH_PREFIX_NODE_DICT,
_ => HASH_PREFIX_NODE,
};
let left_hash = btn.left.as_ref().map(|left| Self::calculate_merkle_hash(left)).unwrap_or([0; 32]);
let right_hash = btn.right.as_ref().map(|right| Self::calculate_merkle_hash(right)).unwrap_or([0; 32]);
Self::calculate_node_hash(has_prefix, left_hash, right_hash)
}
}
}
}
pub fn gtv_hash(value: Params, hash_version: u8) -> Result<[u8; 32], HashError> {
let tree = BinaryTreeFactory::build_tree(Box::new(value), hash_version)?;
Ok(MerkleHashCalculator::calculate_merkle_hash(&tree))
}
#[test]
fn test_gtv_hash() {
use std::collections::BTreeMap;
let data1 = Params::Array(vec![
Params::Text("foo".to_string()), Params::Array(vec![
Params::Text("bar2".to_string()), Params::Text("bar2".to_string())
])
]);
let mut data2_btree: BTreeMap<String, Params> = BTreeMap::new();
data2_btree.insert("foo".to_string(), Params::Integer(-1));
data2_btree.insert("foo1".to_string(), Params::Text("OK".to_string()));
data2_btree.insert("bar".to_string(), Params::BigInteger(i128::MAX.into()));
data2_btree.insert("bar1".to_string(), Params::BigInteger((1000000000000 as i128).into()));
let data2 = Params::Dict(data2_btree);
let result1 = gtv_hash(data1, 2).unwrap();
let result2 = gtv_hash(data2, 2).unwrap();
assert_eq!("6357d3200e0dfb1bce5f3eb789714842747b39810248f83dba6382c7e7020e20", hex::encode(result1));
assert_eq!("9f3d80d08a942b86e20932ad74356703dba7ba78b792f2d6ad93201ab9a71bab", hex::encode(result2));
}
#[test]
fn test_gtv_hash_v1() {
let data1 = Params::Array(vec![Params::Text("a".to_string())]);
let data2 = Params::Array(vec![Params::Array(vec![Params::Text("a".to_string())])]);
let data3 = Params::Array(vec![
Params::Array(vec![
Params::Array(vec![Params::Text("a".to_string())])
])
]);
let result1 = gtv_hash(data1, 1).unwrap();
let result2 = gtv_hash(data2, 1).unwrap();
let result3 = gtv_hash(data3, 1).unwrap();
let expected_hash_result = "5ad2414edcd34b9a8bdc22921b8a1b8cef6cab04115dd0e7eb000b05353b315a";
assert_eq!(hex::encode(result1), expected_hash_result);
assert_eq!(hex::encode(result2), expected_hash_result);
assert_eq!(hex::encode(result3), expected_hash_result);
}
#[test]
fn test_gtv_hash_v2() {
let data1 = Params::Array(vec![Params::Text("a".to_string())]);
let data2 = Params::Array(vec![Params::Array(vec![Params::Text("a".to_string())])]);
let data3 = Params::Array(vec![
Params::Array(vec![
Params::Array(vec![Params::Text("a".to_string())])
])
]);
let result1 = gtv_hash(data1, 2).unwrap();
let result2 = gtv_hash(data2, 2).unwrap();
let result3 = gtv_hash(data3, 2).unwrap();
assert_eq!(hex::encode(result1), "5ad2414edcd34b9a8bdc22921b8a1b8cef6cab04115dd0e7eb000b05353b315a");
assert_eq!(hex::encode(result2), "19605d1044cc20248e315f98f2d4c4aa7adfe6861607a0d000641837c3b962f8");
assert_eq!(hex::encode(result3), "574b45c58e62ff7b786ee644579ffea593c89541498c1692fb8c99d811265166");
}
#[test]
fn test_gtv_hash_v1_and_v2_of_array_of_dicts() {
let data = Params::Array(vec![
Params::Dict(std::collections::BTreeMap::from([
("a".to_string(), Params::Text("b".to_string())),
("c".to_string(), Params::Text("d".to_string()))
]))
]);
let hash_v1_result = "891cdf10ff613a90899ff0ffe1a515d8ed74fe71e36249f0b6dd175eec70805d";
let hash_v2_result = "9d2f6cfa72538e24584363ada5882c2be3f83d75aff598d0009330db22d961ff";
let result = gtv_hash(data.clone(), 1).unwrap();
assert_eq!(hex::encode(result), hash_v1_result);
let result = gtv_hash(data, 2).unwrap();
assert_eq!(hex::encode(result), hash_v2_result);
let a1 = Params::Dict(std::collections::BTreeMap::from([
("a1".to_string(), Params::Text("b".to_string()))
]));
let c1 = Params::Dict(std::collections::BTreeMap::from([
("c1".to_string(), Params::Text("d".to_string()))
]));
let data = Params::Array(vec![
Params::Dict(std::collections::BTreeMap::from([
("a".to_string(), a1),
("c".to_string(), c1)
]))
]);
let hash_v1_result = "132fc201e78c96fc2c563a6cff21fa12e45815871e34a267b72c41c0fe48f410";
let hash_v2_result = "ea56d66de794ad212183de103aca17df8eec177bf299ff203cc0aeb287a76495";
let result = gtv_hash(data.clone(), 1).unwrap();
assert_eq!(hex::encode(result), hash_v1_result);
let result = gtv_hash(data, 2).unwrap();
assert_eq!(hex::encode(result), hash_v2_result);
}