Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.1.5 merge spec tests #2781

Merged
merged 12 commits into from
Nov 10, 2021
31 changes: 12 additions & 19 deletions beacon_node/execution_layer/src/engine_api/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,11 +433,10 @@ pub mod serde_transactions {

while let Some(val) = seq.next_element::<String>()? {
let inner_vec = hex::decode(&val).map_err(de::Error::custom)?;
let opaque_transaction = VariableList::new(inner_vec).map_err(|e| {
let transaction = VariableList::new(inner_vec).map_err(|e| {
serde::de::Error::custom(format!("transaction too large: {:?}", e))
})?;
let transaction = Transaction::OpaqueTransaction(opaque_transaction);
outer.push(transaction).map_err(|e| {
outer.push(Transaction::new(transaction)).map_err(|e| {
serde::de::Error::custom(format!("too many transactions: {:?}", e))
})?;
}
Expand All @@ -458,9 +457,7 @@ pub mod serde_transactions {
// It's important to match on the inner values of the transaction. Serializing the
// entire `Transaction` will result in appending the SSZ union prefix byte. The
// execution node does not want that.
let hex = match transaction {
Transaction::OpaqueTransaction(val) => hex::encode(&val[..]),
};
let hex = hex::encode(transaction.as_bytes());
seq.serialize_element(&hex)?;
}
seq.end()
Expand Down Expand Up @@ -611,7 +608,7 @@ mod test {
}

/// Example: if `spec == &[1, 1]`, then two one-byte transactions will be created.
fn generate_opaque_transactions<E: EthSpec>(
fn generate_transactions<E: EthSpec>(
spec: &[usize],
) -> VariableList<Transaction<E>, E::MaxTransactionsPerPayload> {
let mut txs = VariableList::default();
Expand All @@ -621,42 +618,38 @@ mod test {
for _ in 0..num_bytes {
tx.push(0).unwrap();
}
txs.push(Transaction::OpaqueTransaction(tx)).unwrap();
txs.push(Transaction::new(tx)).unwrap();
}

txs
}

#[test]
fn transaction_serde() {
assert_transactions_serde::<MainnetEthSpec>(
"empty",
generate_opaque_transactions(&[]),
json!([]),
);
assert_transactions_serde::<MainnetEthSpec>("empty", generate_transactions(&[]), json!([]));
assert_transactions_serde::<MainnetEthSpec>(
"one empty tx",
generate_opaque_transactions(&[0]),
generate_transactions(&[0]),
json!(["0x"]),
);
assert_transactions_serde::<MainnetEthSpec>(
"two empty txs",
generate_opaque_transactions(&[0, 0]),
generate_transactions(&[0, 0]),
json!(["0x", "0x"]),
);
assert_transactions_serde::<MainnetEthSpec>(
"one one-byte tx",
generate_opaque_transactions(&[1]),
generate_transactions(&[1]),
json!(["0x00"]),
);
assert_transactions_serde::<MainnetEthSpec>(
"two one-byte txs",
generate_opaque_transactions(&[1, 1]),
generate_transactions(&[1, 1]),
json!(["0x00", "0x00"]),
);
assert_transactions_serde::<MainnetEthSpec>(
"mixed bag",
generate_opaque_transactions(&[0, 1, 3, 0]),
generate_transactions(&[0, 1, 3, 0]),
json!(["0x", "0x00", "0x000000", "0x"]),
);

Expand All @@ -680,7 +673,7 @@ mod test {

use eth2_serde_utils::hex;

let num_max_bytes = <MainnetEthSpec as EthSpec>::MaxBytesPerOpaqueTransaction::to_usize();
let num_max_bytes = <MainnetEthSpec as EthSpec>::MaxBytesPerTransaction::to_usize();
let max_bytes = (0..num_max_bytes).map(|_| 0_u8).collect::<Vec<_>>();
let too_many_bytes = (0..=num_max_bytes).map(|_| 0_u8).collect::<Vec<_>>();
decode_transactions::<MainnetEthSpec>(
Expand Down
7 changes: 2 additions & 5 deletions consensus/state_processing/src/common/slash_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,11 @@ pub fn slash_validator<T: EthSpec>(
.safe_add(validator_effective_balance)?,
)?;

let min_slashing_penalty_quotient = match state {
BeaconState::Base(_) => spec.min_slashing_penalty_quotient,
BeaconState::Altair(_) | BeaconState::Merge(_) => spec.min_slashing_penalty_quotient_altair,
};
decrease_balance(
state,
slashed_index,
validator_effective_balance.safe_div(min_slashing_penalty_quotient)?,
validator_effective_balance
.safe_div(spec.min_slashing_penalty_quotient_for_state(state))?,
)?;

// Apply proposer and whistleblower rewards
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ pub fn process_epoch<T: EthSpec>(
process_slashings(
state,
participation_cache.current_epoch_total_active_balance(),
spec.proportional_slashing_multiplier_altair,
spec,
)?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub fn get_inactivity_penalty_deltas<T: EthSpec>(
.safe_mul(state.get_inactivity_score(index)?)?;
let penalty_denominator = spec
.inactivity_score_bias
.safe_mul(spec.inactivity_penalty_quotient_altair)?;
paulhauner marked this conversation as resolved.
Show resolved Hide resolved
.safe_mul(spec.inactivity_penalty_quotient_for_state(state))?;
delta.penalize(penalty_numerator.safe_div(penalty_denominator)?)?;
}
deltas
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ pub fn process_epoch<T: EthSpec>(
process_slashings(
state,
validator_statuses.total_balances.current_epoch(),
spec.proportional_slashing_multiplier,
spec,
)?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use types::{BeaconState, BeaconStateError, ChainSpec, EthSpec, Unsigned};
pub fn process_slashings<T: EthSpec>(
state: &mut BeaconState<T>,
total_balance: u64,
slashing_multiplier: u64,
spec: &ChainSpec,
) -> Result<(), Error> {
let epoch = state.current_epoch();
let sum_slashings = state.get_all_slashings().iter().copied().safe_sum()?;

let adjusted_total_slashing_balance =
std::cmp::min(sum_slashings.safe_mul(slashing_multiplier)?, total_balance);
let adjusted_total_slashing_balance = std::cmp::min(
sum_slashings.safe_mul(spec.proportional_slashing_multiplier_for_state(state))?,
total_balance,
);

let (validators, balances) = state.validators_and_balances_mut();
for (index, validator) in validators.iter().enumerate() {
Expand Down
49 changes: 49 additions & 0 deletions consensus/types/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ pub struct ChainSpec {
pub altair_fork_version: [u8; 4],
/// The Altair fork epoch is optional, with `None` representing "Altair never happens".
pub altair_fork_epoch: Option<Epoch>,

/*
* Merge hard fork params
*/
pub inactivity_penalty_quotient_merge: u64,
pub min_slashing_penalty_quotient_merge: u64,
pub proportional_slashing_multiplier_merge: u64,
pub merge_fork_version: [u8; 4],
/// The Merge fork epoch is optional, with `None` representing "Merge never happens".
pub merge_fork_epoch: Option<Epoch>,
Expand Down Expand Up @@ -235,6 +242,39 @@ impl ChainSpec {
}
}

/// For a given `BeaconState`, return the inactivity penalty quotient associated with its variant.
pub fn inactivity_penalty_quotient_for_state<T: EthSpec>(&self, state: &BeaconState<T>) -> u64 {
match state {
BeaconState::Base(_) => self.inactivity_penalty_quotient,
BeaconState::Altair(_) => self.inactivity_penalty_quotient_altair,
BeaconState::Merge(_) => self.inactivity_penalty_quotient_merge,
}
}

/// For a given `BeaconState`, return the proportional slashing multiplier associated with its variant.
pub fn proportional_slashing_multiplier_for_state<T: EthSpec>(
&self,
state: &BeaconState<T>,
) -> u64 {
match state {
BeaconState::Base(_) => self.proportional_slashing_multiplier,
BeaconState::Altair(_) => self.proportional_slashing_multiplier_altair,
BeaconState::Merge(_) => self.proportional_slashing_multiplier_merge,
}
}

/// For a given `BeaconState`, return the minimum slashing penalty quotient associated with its variant.
pub fn min_slashing_penalty_quotient_for_state<T: EthSpec>(
&self,
state: &BeaconState<T>,
) -> u64 {
match state {
BeaconState::Base(_) => self.min_slashing_penalty_quotient,
BeaconState::Altair(_) => self.min_slashing_penalty_quotient_altair,
BeaconState::Merge(_) => self.min_slashing_penalty_quotient_merge,
}
}

/// Returns a full `Fork` struct for a given epoch.
pub fn fork_at_epoch(&self, epoch: Epoch) -> Fork {
let current_fork_name = self.fork_name_at_epoch(epoch);
Expand Down Expand Up @@ -479,6 +519,15 @@ impl ChainSpec {
domain_contribution_and_proof: 9,
altair_fork_version: [0x01, 0x00, 0x00, 0x00],
altair_fork_epoch: Some(Epoch::new(74240)),

/*
* Merge hard fork params
*/
inactivity_penalty_quotient_merge: u64::checked_pow(2, 24)
.expect("pow does not overflow"),
min_slashing_penalty_quotient_merge: u64::checked_pow(2, 5)
.expect("pow does not overflow"),
proportional_slashing_multiplier_merge: 3,
merge_fork_version: [0x02, 0x00, 0x00, 0x00],
merge_fork_epoch: None,
terminal_total_difficulty: Uint256::MAX
Expand Down
20 changes: 10 additions & 10 deletions consensus/types/src/eth_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ use crate::*;
use safe_arith::SafeArith;
use serde_derive::{Deserialize, Serialize};
use ssz_types::typenum::{
Unsigned, U0, U1024, U1099511627776, U128, U16, U16777216, U2, U2048, U32, U4, U4096, U512,
U64, U65536, U8, U8192,
Unsigned, U0, U1024, U1073741824, U1099511627776, U128, U16, U16777216, U2, U2048, U32, U4,
U4096, U512, U64, U65536, U8, U8192,
};
use std::fmt::{self, Debug};
use std::str::FromStr;

use ssz_types::typenum::{bit::B0, UInt, U1048576, U16384, U256, U625};
use ssz_types::typenum::{bit::B0, UInt, U1048576, U256, U625};
pub type U5000 = UInt<UInt<UInt<U625, B0>, B0>, B0>; // 625 * 8 = 5000

const MAINNET: &str = "mainnet";
Expand Down Expand Up @@ -86,7 +86,7 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq +
/*
* New in Merge
*/
type MaxBytesPerOpaqueTransaction: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type MaxBytesPerTransaction: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type MaxTransactionsPerPayload: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type BytesPerLogsBloom: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type GasLimitDenominator: Unsigned + Clone + Sync + Send + Debug + PartialEq;
Expand Down Expand Up @@ -200,9 +200,9 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq +
Self::SyncSubcommitteeSize::to_usize()
}

/// Returns the `MAX_BYTES_PER_OPAQUE_TRANSACTION` constant for this specification.
fn max_bytes_per_opaque_transaction() -> usize {
Self::MaxBytesPerOpaqueTransaction::to_usize()
/// Returns the `MAX_BYTES_PER_TRANSACTION` constant for this specification.
fn max_bytes_per_transaction() -> usize {
Self::MaxBytesPerTransaction::to_usize()
}

/// Returns the `MAX_TRANSACTIONS_PER_PAYLOAD` constant for this specification.
Expand Down Expand Up @@ -258,8 +258,8 @@ impl EthSpec for MainnetEthSpec {
type MaxVoluntaryExits = U16;
type SyncCommitteeSize = U512;
type SyncCommitteeSubnetCount = U4;
type MaxBytesPerOpaqueTransaction = U1048576;
type MaxTransactionsPerPayload = U16384;
type MaxBytesPerTransaction = U1073741824; // 1,073,741,824
type MaxTransactionsPerPayload = U1048576; // 1,048,576
type BytesPerLogsBloom = U256;
type GasLimitDenominator = U1024;
type MinGasLimit = U5000;
Expand Down Expand Up @@ -306,7 +306,7 @@ impl EthSpec for MinimalEthSpec {
MaxAttestations,
MaxDeposits,
MaxVoluntaryExits,
MaxBytesPerOpaqueTransaction,
MaxBytesPerTransaction,
MaxTransactionsPerPayload,
BytesPerLogsBloom,
GasLimitDenominator,
Expand Down
91 changes: 69 additions & 22 deletions consensus/types/src/execution_payload.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,85 @@
use crate::{test_utils::TestRandom, *};
use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz::{Decode, DecodeError, Encode};
use ssz_derive::{Decode, Encode};
use std::{ops::Index, slice::SliceIndex};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash)]
#[ssz(enum_behaviour = "union")]
#[tree_hash(enum_behaviour = "union")]
#[serde(tag = "selector", content = "value")]
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
#[serde(bound = "T: EthSpec")]
pub enum Transaction<T: EthSpec> {
// FIXME(merge): renaming this enum variant to 0 is a bit of a hack...
#[serde(rename = "0")]
OpaqueTransaction(
#[serde(with = "ssz_types::serde_utils::hex_var_list")]
VariableList<u8, T::MaxBytesPerOpaqueTransaction>,
),
pub struct Transaction<T: EthSpec>(
#[serde(with = "ssz_types::serde_utils::hex_var_list")]
VariableList<u8, T::MaxBytesPerTransaction>,
);

impl<T: EthSpec> Transaction<T> {
pub fn new(tx: VariableList<u8, T::MaxBytesPerTransaction>) -> Transaction<T> {
Self(tx)
}

pub fn as_bytes(&self) -> &[u8] {
&self.0[..]
}
}

impl<T: EthSpec, I: SliceIndex<[u8]>> Index<I> for Transaction<T> {
type Output = I::Output;
impl<T: EthSpec> Encode for Transaction<T> {
fn is_ssz_fixed_len() -> bool {
<VariableList<u8, T::MaxBytesPerTransaction> as Encode>::is_ssz_fixed_len()
}

#[inline]
fn index(&self, index: I) -> &Self::Output {
match self {
Self::OpaqueTransaction(v) => Index::index(v, index),
}
fn ssz_append(&self, buf: &mut Vec<u8>) {
self.0.ssz_append(buf)
}

fn ssz_fixed_len() -> usize {
<VariableList<u8, T::MaxBytesPerTransaction> as Encode>::ssz_fixed_len()
}

fn ssz_bytes_len(&self) -> usize {
self.0.ssz_bytes_len()
}
}

impl<T: EthSpec> From<VariableList<u8, T::MaxBytesPerOpaqueTransaction>> for Transaction<T> {
fn from(list: VariableList<u8, <T as EthSpec>::MaxBytesPerOpaqueTransaction>) -> Self {
Self::OpaqueTransaction(list)
impl<T: EthSpec> Decode for Transaction<T> {
fn is_ssz_fixed_len() -> bool {
<VariableList<u8, T::MaxBytesPerTransaction> as Decode>::is_ssz_fixed_len()
}

fn ssz_fixed_len() -> usize {
<VariableList<u8, T::MaxBytesPerTransaction> as Decode>::ssz_fixed_len()
}

fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
Ok(Transaction(VariableList::from_ssz_bytes(bytes)?))
}
}

impl<T: EthSpec> tree_hash::TreeHash for Transaction<T> {
fn tree_hash_type() -> tree_hash::TreeHashType {
tree_hash::TreeHashType::Container
}

fn tree_hash_packed_encoding(&self) -> Vec<u8> {
unreachable!("List should never be packed.")
}

fn tree_hash_packing_factor() -> usize {
unreachable!("List should never be packed.")
}

fn tree_hash_root(&self) -> tree_hash::Hash256 {
self.0.tree_hash_root()
}
}

impl<T: EthSpec> SignedRoot for Transaction<T> {}

impl<T: EthSpec> TestRandom for Transaction<T> {
fn random_for_test(rng: &mut impl RngCore) -> Self {
Transaction(VariableList::random_for_test(rng))
}
}

Expand Down
2 changes: 1 addition & 1 deletion testing/ef_tests/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
TESTS_TAG := v1.1.3
TESTS_TAG := v1.1.4
TESTS = general minimal mainnet
TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS))

Expand Down
Loading