4d0122444b
## Proposed Changes I did some gardening 🌳 in our dependency tree: - Remove duplicate versions of `warp` (git vs patch) - Remove duplicate versions of lots of small deps: `cpufeatures`, `ethabi`, `ethereum-types`, `bitvec`, `nix`, `libsecp256k1`. - Update MDBX (should resolve #3028). I tested and Lighthouse compiles on Windows 11 now. - Restore `psutil` back to upstream - Make some progress updating everything to rand 0.8. There are a few crates stuck on 0.7. Hopefully this puts us on a better footing for future `cargo audit` issues, and improves compile times slightly. ## Additional Info Some crates are held back by issues with `zeroize`. libp2p-noise depends on [`chacha20poly1305`](https://crates.io/crates/chacha20poly1305) which depends on zeroize < v1.5, and we can only have one version of zeroize because it's post 1.0 (see https://github.com/rust-lang/cargo/issues/6584). The latest version of `zeroize` is v1.5.4, which is used by the new versions of many other crates (e.g. `num-bigint-dig`). Once a new version of chacha20poly1305 is released we can update libp2p-noise and upgrade everything to the latest `zeroize` version. I've also opened a PR to `blst` related to zeroize: https://github.com/supranational/blst/pull/111
131 lines
4.1 KiB
Rust
131 lines
4.1 KiB
Rust
use ethabi::{Contract, Token};
|
|
use ssz::{Decode, DecodeError as SszDecodeError, Encode};
|
|
use tree_hash::TreeHash;
|
|
use types::{DepositData, Hash256, PublicKeyBytes, SignatureBytes};
|
|
|
|
pub use ethabi::Error;
|
|
|
|
#[derive(Debug)]
|
|
pub enum DecodeError {
|
|
EthabiError(ethabi::Error),
|
|
SszDecodeError(SszDecodeError),
|
|
MissingField,
|
|
UnableToGetBytes,
|
|
MissingToken,
|
|
InadequateBytes,
|
|
}
|
|
|
|
impl From<ethabi::Error> for DecodeError {
|
|
fn from(e: ethabi::Error) -> DecodeError {
|
|
DecodeError::EthabiError(e)
|
|
}
|
|
}
|
|
|
|
pub const CONTRACT_DEPLOY_GAS: usize = 4_000_000;
|
|
pub const DEPOSIT_GAS: usize = 400_000;
|
|
pub const ABI: &[u8] = include_bytes!("../contracts/v0.12.1_validator_registration.json");
|
|
pub const BYTECODE: &[u8] = include_bytes!("../contracts/v0.12.1_validator_registration.bytecode");
|
|
pub const DEPOSIT_DATA_LEN: usize = 420; // lol
|
|
|
|
pub mod testnet {
|
|
pub const ABI: &[u8] =
|
|
include_bytes!("../contracts/v0.12.1_testnet_validator_registration.json");
|
|
pub const BYTECODE: &[u8] =
|
|
include_bytes!("../contracts/v0.12.1_testnet_validator_registration.bytecode");
|
|
}
|
|
|
|
pub fn encode_eth1_tx_data(deposit_data: &DepositData) -> Result<Vec<u8>, Error> {
|
|
let params = vec![
|
|
Token::Bytes(deposit_data.pubkey.as_ssz_bytes()),
|
|
Token::Bytes(deposit_data.withdrawal_credentials.as_ssz_bytes()),
|
|
Token::Bytes(deposit_data.signature.as_ssz_bytes()),
|
|
Token::FixedBytes(deposit_data.tree_hash_root().as_ssz_bytes()),
|
|
];
|
|
|
|
// Here we make an assumption that the `crate::testnet::ABI` has a superset of the features of
|
|
// the crate::ABI`.
|
|
let abi = Contract::load(ABI)?;
|
|
let function = abi.function("deposit")?;
|
|
function.encode_input(¶ms)
|
|
}
|
|
|
|
pub fn decode_eth1_tx_data(
|
|
bytes: &[u8],
|
|
amount: u64,
|
|
) -> Result<(DepositData, Hash256), DecodeError> {
|
|
let abi = Contract::load(ABI)?;
|
|
let function = abi.function("deposit")?;
|
|
let mut tokens = function.decode_input(bytes.get(4..).ok_or(DecodeError::InadequateBytes)?)?;
|
|
|
|
macro_rules! decode_token {
|
|
($type: ty, $to_fn: ident) => {
|
|
<$type>::from_ssz_bytes(
|
|
&tokens
|
|
.pop()
|
|
.ok_or_else(|| DecodeError::MissingToken)?
|
|
.$to_fn()
|
|
.ok_or_else(|| DecodeError::UnableToGetBytes)?,
|
|
)
|
|
.map_err(DecodeError::SszDecodeError)?
|
|
};
|
|
}
|
|
|
|
let root = decode_token!(Hash256, into_fixed_bytes);
|
|
|
|
let deposit_data = DepositData {
|
|
amount,
|
|
signature: decode_token!(SignatureBytes, into_bytes),
|
|
withdrawal_credentials: decode_token!(Hash256, into_bytes),
|
|
pubkey: decode_token!(PublicKeyBytes, into_bytes),
|
|
};
|
|
|
|
Ok((deposit_data, root))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use types::{
|
|
test_utils::generate_deterministic_keypair, ChainSpec, EthSpec, Hash256, Keypair,
|
|
MinimalEthSpec, Signature,
|
|
};
|
|
|
|
type E = MinimalEthSpec;
|
|
|
|
fn get_deposit(keypair: Keypair, spec: &ChainSpec) -> DepositData {
|
|
let mut deposit_data = DepositData {
|
|
pubkey: keypair.pk.into(),
|
|
withdrawal_credentials: Hash256::from_slice(&[42; 32]),
|
|
amount: u64::max_value(),
|
|
signature: Signature::empty().into(),
|
|
};
|
|
deposit_data.signature = deposit_data.create_signature(&keypair.sk, spec);
|
|
deposit_data
|
|
}
|
|
|
|
#[test]
|
|
fn round_trip() {
|
|
let spec = &E::default_spec();
|
|
|
|
let keypair = generate_deterministic_keypair(42);
|
|
let original = get_deposit(keypair, spec);
|
|
|
|
let data = encode_eth1_tx_data(&original).expect("should produce tx data");
|
|
|
|
assert_eq!(
|
|
data.len(),
|
|
DEPOSIT_DATA_LEN,
|
|
"bytes should be correct length"
|
|
);
|
|
|
|
let (decoded, root) = decode_eth1_tx_data(&data, original.amount).expect("should decode");
|
|
|
|
assert_eq!(decoded, original, "decoded should match original");
|
|
assert_eq!(
|
|
root,
|
|
original.tree_hash_root(),
|
|
"decode root should match original root"
|
|
);
|
|
}
|
|
}
|