//! Helper function for calculating Merkle proofs and hashes.
pub use alloy_trie::root::ordered_trie_root_with_encoder;

pub use alloy_consensus::proofs::calculate_receipt_root;

/// Calculate a transaction root.
///
/// `(rlp(index), encoded(tx))` pairs.
#[doc(inline)]
pub use alloy_consensus::proofs::calculate_transaction_root;

/// Calculates the root hash of the withdrawals.
#[doc(inline)]
pub use alloy_consensus::proofs::calculate_withdrawals_root;

/// Calculates the root hash for ommer/uncle headers.
#[doc(inline)]
pub use alloy_consensus::proofs::calculate_ommers_root;

#[cfg(all(test, feature = "std"))]
mod tests {
    use alloy_consensus::EMPTY_ROOT_HASH;
    use alloy_genesis::GenesisAccount;
    use alloy_primitives::{hex_literal::hex, Address, B256, U256};
    use alloy_trie::root::state_root_unhashed;
    use std::collections::HashMap;

    #[test]
    fn check_empty_state_root() {
        let genesis_alloc = HashMap::<Address, GenesisAccount>::new();
        let root = state_root_unhashed(genesis_alloc);
        assert_eq!(root, EMPTY_ROOT_HASH);
    }

    #[test]
    fn test_simple_account_state_root() {
        // each fixture specifies an address and expected root hash - the address is initialized
        // with a maximum balance, and is the only account in the state.
        // these test cases are generated by using geth with a custom genesis.json (with a single
        // account that has max balance)
        let fixtures: Vec<(Address, B256)> = vec![
            (
                hex!("9fe4abd71ad081f091bd06dd1c16f7e92927561e").into(),
                hex!("4b35be4231841d212ce2fa43aedbddeadd6eb7d420195664f9f0d55629db8c32").into(),
            ),
            (
                hex!("c2ba9d87f8be0ade00c60d3656c1188e008fbfa2").into(),
                hex!("e1389256c47d63df8856d7729dec9dc2dae074a7f0cbc49acad1cf7b29f7fe94").into(),
            ),
        ];

        for (test_addr, expected_root) in fixtures {
            let mut genesis_alloc = HashMap::new();
            genesis_alloc
                .insert(test_addr, GenesisAccount { balance: U256::MAX, ..Default::default() });

            let root = state_root_unhashed(genesis_alloc);

            assert_eq!(root, expected_root);
        }
    }
}
