ethereumvm 0.11.0

EthereumVM - a Portable Blockchain Virtual Machine
//! Environment instructions

use bigint::{H256, M256};
use sha3::{Digest, Keccak256};

use super::State;
use crate::{Address, Memory, Patch};

pub fn calldataload<M: Memory, P: Patch>(state: &mut State<M, P>) {
    pop!(state, index);
    let index: Option<usize> = if index > usize::max_value().into() {
        None
    } else {
        Some(index.as_usize())
    };
    let data = state.context.data.as_slice();
    let mut load: [u8; 32] = [0u8; 32];
    for i in 0..32 {
        if index.is_some() && index.unwrap() + i < data.len() {
            load[i] = data[index.unwrap() + i];
        }
    }
    push!(state, load.as_ref().into());
}

pub fn extcodehash<M: Memory, P: Patch>(state: &mut State<M, P>) {
    pop!(state, address: Address);

    if let Some(code) = state.account_state.code_opt_nonexist(address).unwrap() {
        let hash = extcodehash_impl(&code[..]);
        push!(state, hash.into());
    } else {
        push!(state, M256::zero())
    }
}

fn extcodehash_impl(code: &[u8]) -> H256 {
    let mut hasher = Keccak256::default();
    hasher.input(code);
    let output = hasher.result();
    H256::from(&output[..])
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn extcodehash_empty_code() {
        let code = &[];
        let hash = extcodehash_impl(code);
        assert_eq!(
            hash,
            H256::from("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
        );
    }

    #[test]
    fn extcodehash_hash() {
        let code = &[
            0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x68, 0x61, 0x73, 0x68,
        ];
        let hash = extcodehash_impl(code);
        assert_eq!(
            hash,
            H256::from("0x854a9ae2c913e6cef584ecaf9cbb52a38b59fb923a09beccee9d17c17d15cf7a")
        );
    }
}