Add interop-spec genesis procedure
This commit is contained in:
parent
e154b30232
commit
6234adc0d6
@ -6,6 +6,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
eth2_config = { path = "../../eth2/utils/eth2_config" }
|
||||
merkle_proof = { path = "../../eth2/utils/merkle_proof" }
|
||||
store = { path = "../store" }
|
||||
parking_lot = "0.7"
|
||||
lazy_static = "1.3.0"
|
||||
@ -21,6 +22,7 @@ eth2-libp2p = { path = "../eth2-libp2p" }
|
||||
slog = { version = "^2.2.3" , features = ["max_level_trace"] }
|
||||
sloggers = { version = "^0.3" }
|
||||
slot_clock = { path = "../../eth2/utils/slot_clock" }
|
||||
eth2_hashing = { path = "../../eth2/utils/eth2_hashing" }
|
||||
eth2_ssz = "0.1"
|
||||
eth2_ssz_derive = "0.1"
|
||||
state_processing = { path = "../../eth2/state_processing" }
|
||||
|
@ -1,11 +1,20 @@
|
||||
use super::bootstrapper::Bootstrapper;
|
||||
use crate::{BeaconChain, BeaconChainTypes};
|
||||
use eth2_hashing::hash;
|
||||
use merkle_proof::MerkleTree;
|
||||
use rayon::prelude::*;
|
||||
use slog::Logger;
|
||||
use ssz::Encode;
|
||||
use state_processing::initialize_beacon_state_from_eth1;
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::SystemTime;
|
||||
use types::{test_utils::TestingBeaconStateBuilder, BeaconBlock, BeaconState, ChainSpec, EthSpec};
|
||||
use tree_hash::{SignedRoot, TreeHash};
|
||||
use types::{
|
||||
test_utils::generate_deterministic_keypairs, BeaconBlock, BeaconState, ChainSpec, Deposit,
|
||||
DepositData, Domain, EthSpec, Fork, Hash256, PublicKey, Signature,
|
||||
};
|
||||
|
||||
enum BuildStrategy<T: BeaconChainTypes> {
|
||||
FromGenesis {
|
||||
@ -27,7 +36,7 @@ impl<T: BeaconChainTypes> BeaconChainBuilder<T> {
|
||||
minutes: u64,
|
||||
spec: ChainSpec,
|
||||
log: Logger,
|
||||
) -> Self {
|
||||
) -> Result<Self, String> {
|
||||
Self::quick_start(recent_genesis_time(minutes), validator_count, spec, log)
|
||||
}
|
||||
|
||||
@ -36,14 +45,10 @@ impl<T: BeaconChainTypes> BeaconChainBuilder<T> {
|
||||
validator_count: usize,
|
||||
spec: ChainSpec,
|
||||
log: Logger,
|
||||
) -> Self {
|
||||
let (mut genesis_state, _keypairs) =
|
||||
TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(validator_count, &spec)
|
||||
.build();
|
||||
) -> Result<Self, String> {
|
||||
let genesis_state = interop_genesis_state(validator_count, genesis_time, &spec)?;
|
||||
|
||||
genesis_state.genesis_time = genesis_time;
|
||||
|
||||
Self::from_genesis_state(genesis_state, spec, log)
|
||||
Ok(Self::from_genesis_state(genesis_state, spec, log))
|
||||
}
|
||||
|
||||
pub fn yaml_state(file: &PathBuf, spec: ChainSpec, log: Logger) -> Result<Self, String> {
|
||||
@ -125,6 +130,95 @@ fn genesis_block<T: EthSpec>(genesis_state: &BeaconState<T>, spec: &ChainSpec) -
|
||||
genesis_block
|
||||
}
|
||||
|
||||
fn interop_genesis_state<T: EthSpec>(
|
||||
validator_count: usize,
|
||||
genesis_time: u64,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<BeaconState<T>, String> {
|
||||
let keypairs = generate_deterministic_keypairs(validator_count);
|
||||
let eth1_block_hash = Hash256::from_slice(&[42; 32]);
|
||||
let eth1_timestamp = 2_u64.pow(40);
|
||||
let amount = spec.max_effective_balance;
|
||||
dbg!(amount);
|
||||
|
||||
let withdrawal_credentials = |pubkey: &PublicKey| {
|
||||
let mut credentials = hash(&pubkey.as_ssz_bytes());
|
||||
credentials[0] = spec.bls_withdrawal_prefix_byte;
|
||||
Hash256::from_slice(&credentials)
|
||||
};
|
||||
|
||||
let datas = keypairs
|
||||
.into_par_iter()
|
||||
.map(|keypair| {
|
||||
let mut data = DepositData {
|
||||
withdrawal_credentials: withdrawal_credentials(&keypair.pk),
|
||||
pubkey: keypair.pk.into(),
|
||||
amount,
|
||||
signature: Signature::empty_signature().into(),
|
||||
};
|
||||
|
||||
let domain = spec.get_domain(
|
||||
spec.genesis_slot.epoch(T::slots_per_epoch()),
|
||||
Domain::Deposit,
|
||||
&Fork::default(),
|
||||
);
|
||||
data.signature = Signature::new(&data.signed_root()[..], domain, &keypair.sk).into();
|
||||
|
||||
data
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let deposit_root_leaves = datas
|
||||
.par_iter()
|
||||
.map(|data| Hash256::from_slice(&data.tree_hash_root()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut proofs = vec![];
|
||||
for i in 1..=deposit_root_leaves.len() {
|
||||
// Note: this implementation is not so efficient.
|
||||
//
|
||||
// If `MerkleTree` had a push method, we could just build one tree and sample it instead of
|
||||
// rebuilding the tree for each deposit.
|
||||
let tree = MerkleTree::create(
|
||||
&deposit_root_leaves[0..i],
|
||||
spec.deposit_contract_tree_depth as usize,
|
||||
);
|
||||
|
||||
let (_, mut proof) = tree.generate_proof(i - 1, spec.deposit_contract_tree_depth as usize);
|
||||
proof.push(Hash256::from_slice(&int_to_bytes32(i)));
|
||||
|
||||
assert_eq!(
|
||||
proof.len(),
|
||||
spec.deposit_contract_tree_depth as usize + 1,
|
||||
"Deposit proof should be correct len"
|
||||
);
|
||||
|
||||
proofs.push(proof);
|
||||
}
|
||||
|
||||
let deposits = datas
|
||||
.into_par_iter()
|
||||
.zip(proofs.into_par_iter())
|
||||
.map(|(data, proof)| (data, proof.into()))
|
||||
.map(|(data, proof)| Deposit { proof, data })
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut state =
|
||||
initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits, spec)
|
||||
.map_err(|e| format!("Unable to initialize genesis state: {:?}", e))?;
|
||||
|
||||
state.genesis_time = genesis_time;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
/// Returns `int` as little-endian bytes with a length of 32.
|
||||
fn int_to_bytes32(int: usize) -> Vec<u8> {
|
||||
let mut vec = int.to_le_bytes().to_vec();
|
||||
vec.resize(32, 0);
|
||||
vec
|
||||
}
|
||||
|
||||
/// Returns the system time, mod 30 minutes.
|
||||
///
|
||||
/// Used for easily creating testnets.
|
||||
@ -134,6 +228,66 @@ fn recent_genesis_time(minutes: u64) -> u64 {
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
let secs_after_last_period = now.checked_rem(minutes * 60).unwrap_or(0);
|
||||
// genesis is now the last 15 minute block.
|
||||
now - secs_after_last_period
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use types::{EthSpec, MinimalEthSpec};
|
||||
|
||||
type TestEthSpec = MinimalEthSpec;
|
||||
|
||||
#[test]
|
||||
fn interop_state() {
|
||||
let validator_count = 16;
|
||||
let genesis_time = 42;
|
||||
let spec = &TestEthSpec::default_spec();
|
||||
|
||||
let state = interop_genesis_state::<TestEthSpec>(validator_count, genesis_time, spec)
|
||||
.expect("should build state");
|
||||
|
||||
assert_eq!(
|
||||
state.eth1_data.block_hash,
|
||||
Hash256::from_slice(&[42; 32]),
|
||||
"eth1 block hash should be co-ordinated junk"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
state.genesis_time, genesis_time,
|
||||
"genesis time should be as specified"
|
||||
);
|
||||
|
||||
for b in &state.balances {
|
||||
assert_eq!(
|
||||
*b, spec.max_effective_balance,
|
||||
"validator balances should be max effective balance"
|
||||
);
|
||||
}
|
||||
|
||||
for v in &state.validators {
|
||||
let creds = v.withdrawal_credentials.as_bytes();
|
||||
assert_eq!(
|
||||
creds[0], spec.bls_withdrawal_prefix_byte,
|
||||
"first byte of withdrawal creds should be bls prefix"
|
||||
);
|
||||
assert_eq!(
|
||||
&creds[1..],
|
||||
&hash(&v.pubkey.as_ssz_bytes())[1..],
|
||||
"rest of withdrawal creds should be pubkey hash"
|
||||
)
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
state.balances.len(),
|
||||
validator_count,
|
||||
"validator balances len should be correct"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
state.validators.len(),
|
||||
validator_count,
|
||||
"validator count should be correct"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ where
|
||||
*minutes,
|
||||
spec.clone(),
|
||||
log.clone(),
|
||||
),
|
||||
)?,
|
||||
BeaconChainStartMethod::Generated {
|
||||
validator_count,
|
||||
genesis_time,
|
||||
@ -105,7 +105,7 @@ where
|
||||
*validator_count,
|
||||
spec.clone(),
|
||||
log.clone(),
|
||||
),
|
||||
)?,
|
||||
BeaconChainStartMethod::Yaml { file } => {
|
||||
BeaconChainBuilder::yaml_state(file, spec.clone(), log.clone())?
|
||||
}
|
||||
|
@ -16,9 +16,9 @@ use state_processing::per_block_processing::errors::{
|
||||
};
|
||||
use state_processing::per_block_processing::{
|
||||
get_slashable_indices_modular, verify_attestation_for_block_inclusion,
|
||||
verify_attestation_for_state, verify_attester_slashing, verify_exit,
|
||||
verify_exit_time_independent_only, verify_proposer_slashing, verify_transfer,
|
||||
verify_transfer_time_independent_only, VerifySignatures,
|
||||
verify_attester_slashing, verify_exit, verify_exit_time_independent_only,
|
||||
verify_proposer_slashing, verify_transfer, verify_transfer_time_independent_only,
|
||||
VerifySignatures,
|
||||
};
|
||||
use std::collections::{btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet};
|
||||
use std::marker::PhantomData;
|
||||
|
@ -182,7 +182,7 @@ macro_rules! impl_display {
|
||||
&self,
|
||||
record: &slog::Record,
|
||||
key: slog::Key,
|
||||
serializer: &mut slog::Serializer,
|
||||
serializer: &mut dyn slog::Serializer,
|
||||
) -> slog::Result {
|
||||
slog::Value::serialize(&self.0, record, key, serializer)
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ impl<T: EthSpec> TestingBeaconStateBuilder<T> {
|
||||
/// Creates the builder from an existing set of keypairs.
|
||||
pub fn from_keypairs(keypairs: Vec<Keypair>, spec: &ChainSpec) -> Self {
|
||||
let validator_count = keypairs.len();
|
||||
let starting_balance = 32_000_000_000;
|
||||
let starting_balance = spec.max_effective_balance;
|
||||
|
||||
debug!(
|
||||
"Building {} Validator objects from keypairs...",
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::{SecretKey, BLS_PUBLIC_KEY_BYTE_SIZE};
|
||||
use milagro_bls::G1Point;
|
||||
use milagro_bls::PublicKey as RawPublicKey;
|
||||
use serde::de::{Deserialize, Deserializer};
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
use serde_hex::{encode as hex_encode, HexVisitor};
|
||||
@ -24,6 +25,13 @@ impl FakePublicKey {
|
||||
Self::zero()
|
||||
}
|
||||
|
||||
pub fn from_raw(raw: RawPublicKey) -> Self {
|
||||
Self {
|
||||
bytes: raw.clone().as_bytes(),
|
||||
point: G1Point::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new all-zero's public key
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
|
Loading…
Reference in New Issue
Block a user