Update engine_api to latest version (#4223)

* Update Engine API to Latest

* Get Mock EE Working

* Fix Mock EE

* Update Engine API Again

* Rip out get_blobs_bundle Stuff

* Fix Test Harness

* Fix Clippy Complaints

* Fix Beacon Chain Tests
This commit is contained in:
ethDreamer
2023-04-27 13:18:21 -05:00
committed by GitHub
parent aa34339298
commit c1d47da02d
24 changed files with 449 additions and 159 deletions

View File

@@ -6,15 +6,21 @@ use crate::{
},
ExecutionBlock, PayloadAttributes, PayloadId, PayloadStatusV1, PayloadStatusV1Status,
},
ExecutionBlockWithTransactions,
BlobsBundleV1, ExecutionBlockWithTransactions,
};
use kzg::{Kzg, BYTES_PER_BLOB, BYTES_PER_FIELD_ELEMENT, FIELD_ELEMENTS_PER_BLOB};
use rand::RngCore;
use serde::{Deserialize, Serialize};
use ssz::Encode;
use std::collections::HashMap;
use std::sync::Arc;
use tree_hash::TreeHash;
use tree_hash_derive::TreeHash;
use types::transaction::{BlobTransaction, EcdsaSignature, SignedBlobTransaction};
use types::{
EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadDeneb,
ExecutionPayloadMerge, ForkName, Hash256, Uint256,
Blob, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella,
ExecutionPayloadDeneb, ExecutionPayloadMerge, ForkName, Hash256, Transaction, Transactions,
Uint256,
};
const GAS_LIMIT: u64 = 16384;
@@ -119,6 +125,11 @@ pub struct ExecutionBlockGenerator<T: EthSpec> {
*/
pub shanghai_time: Option<u64>, // withdrawals
pub deneb_time: Option<u64>, // 4844
/*
* deneb stuff
*/
pub blobs_bundles: HashMap<PayloadId, BlobsBundleV1<T>>,
pub kzg: Option<Arc<Kzg>>,
}
impl<T: EthSpec> ExecutionBlockGenerator<T> {
@@ -128,6 +139,7 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
terminal_block_hash: ExecutionBlockHash,
shanghai_time: Option<u64>,
deneb_time: Option<u64>,
kzg: Option<Kzg>,
) -> Self {
let mut gen = Self {
head_block: <_>::default(),
@@ -142,6 +154,8 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
payload_ids: <_>::default(),
shanghai_time,
deneb_time,
blobs_bundles: <_>::default(),
kzg: kzg.map(Arc::new),
};
gen.insert_pow_block(0).unwrap();
@@ -394,6 +408,11 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
self.payload_ids.get(id).cloned()
}
pub fn get_blobs_bundle(&mut self, id: &PayloadId) -> Option<BlobsBundleV1<T>> {
// remove it to free memory
self.blobs_bundles.remove(id)
}
pub fn new_payload(&mut self, payload: ExecutionPayload<T>) -> PayloadStatusV1 {
let parent = if let Some(parent) = self.blocks.get(&payload.parent_hash()) {
parent
@@ -561,6 +580,22 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
}
};
match execution_payload.fork_name() {
ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => {}
ForkName::Deneb => {
// get random number between 0 and Max Blobs
let num_blobs = rand::random::<usize>() % T::max_blobs_per_block();
let (bundle, transactions) = self.generate_random_blobs(num_blobs)?;
for tx in Vec::from(transactions) {
execution_payload
.transactions_mut()
.push(tx)
.map_err(|_| "transactions are full".to_string())?;
}
self.blobs_bundles.insert(id, bundle);
}
}
*execution_payload.block_hash_mut() =
ExecutionBlockHash::from_root(execution_payload.tree_hash_root());
@@ -590,6 +625,88 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
payload_id: id.map(Into::into),
})
}
fn generate_random_blobs(
&self,
n_blobs: usize,
) -> Result<(BlobsBundleV1<T>, Transactions<T>), String> {
let mut bundle = BlobsBundleV1::<T>::default();
let mut transactions = vec![];
for blob_index in 0..n_blobs {
// fill a vector with random bytes
let mut blob_bytes = [0u8; BYTES_PER_BLOB];
rand::thread_rng().fill_bytes(&mut blob_bytes);
// Ensure that the blob is canonical by ensuring that
// each field element contained in the blob is < BLS_MODULUS
for i in 0..FIELD_ELEMENTS_PER_BLOB {
blob_bytes[i * BYTES_PER_FIELD_ELEMENT + BYTES_PER_FIELD_ELEMENT - 1] = 0;
}
let blob = Blob::<T>::new(Vec::from(blob_bytes))
.map_err(|e| format!("error constructing random blob: {:?}", e))?;
let commitment = self
.kzg
.as_ref()
.ok_or("kzg not initialized")?
.blob_to_kzg_commitment(blob_bytes.into())
.map_err(|e| format!("error computing kzg commitment: {:?}", e))?;
let proof = self
.kzg
.as_ref()
.ok_or("kzg not initialized")?
.compute_blob_kzg_proof(blob_bytes.into(), commitment)
.map_err(|e| format!("error computing kzg proof: {:?}", e))?;
let versioned_hash = commitment.calculate_versioned_hash();
let blob_transaction = BlobTransaction {
chain_id: Default::default(),
nonce: 0,
max_priority_fee_per_gas: Default::default(),
max_fee_per_gas: Default::default(),
gas: 100000,
to: None,
value: Default::default(),
data: Default::default(),
access_list: Default::default(),
max_fee_per_data_gas: Default::default(),
versioned_hashes: vec![versioned_hash].into(),
};
let bad_signature = EcdsaSignature {
y_parity: false,
r: Uint256::from(0),
s: Uint256::from(0),
};
let signed_blob_transaction = SignedBlobTransaction {
message: blob_transaction,
signature: bad_signature,
};
// calculate transaction bytes
let tx_bytes = [0x05u8]
.into_iter()
.chain(signed_blob_transaction.as_ssz_bytes().into_iter())
.collect::<Vec<_>>();
let tx = Transaction::<T::MaxBytesPerTransaction>::from(tx_bytes);
transactions.push(tx);
bundle
.blobs
.push(blob)
.map_err(|_| format!("blobs are full, blob index: {:?}", blob_index))?;
bundle
.commitments
.push(commitment)
.map_err(|_| format!("blobs are full, blob index: {:?}", blob_index))?;
bundle
.proofs
.push(proof)
.map_err(|_| format!("blobs are full, blob index: {:?}", blob_index))?;
}
Ok((bundle, transactions.into()))
}
}
fn payload_id_from_u64(n: u64) -> PayloadId {
@@ -650,6 +767,7 @@ mod test {
ExecutionBlockHash::zero(),
None,
None,
None,
);
for i in 0..=TERMINAL_BLOCK {

View File

@@ -224,6 +224,8 @@ pub async fn handle_rpc<T: EthSpec>(
)
})?;
let maybe_blobs = ctx.execution_block_generator.write().get_blobs_bundle(&id);
// validate method called correctly according to shanghai fork time
if ctx
.execution_block_generator
@@ -291,6 +293,12 @@ pub async fn handle_rpc<T: EthSpec>(
serde_json::to_value(JsonGetPayloadResponseV3 {
execution_payload,
block_value: DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI.into(),
blobs_bundle: maybe_blobs
.ok_or((
"No blobs returned despite V3 Payload".to_string(),
GENERIC_ERROR_CODE,
))?
.into(),
})
.unwrap()
}
@@ -324,7 +332,7 @@ pub async fn handle_rpc<T: EthSpec>(
.map(|opt| opt.map(JsonPayloadAttributes::V1))
.transpose()
}
ForkName::Capella => {
ForkName::Capella | ForkName::Deneb => {
get_param::<Option<JsonPayloadAttributesV2>>(params, 1)
.map(|opt| opt.map(JsonPayloadAttributes::V2))
.transpose()

View File

@@ -5,6 +5,7 @@ use crate::{
},
Config, *,
};
use kzg::Kzg;
use sensitive_url::SensitiveUrl;
use task_executor::TaskExecutor;
use tempfile::NamedTempFile;
@@ -33,6 +34,7 @@ impl<T: EthSpec> MockExecutionLayer<T> {
Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()),
spec,
None,
None,
)
}
@@ -46,6 +48,7 @@ impl<T: EthSpec> MockExecutionLayer<T> {
jwt_key: Option<JwtKey>,
spec: ChainSpec,
builder_url: Option<SensitiveUrl>,
kzg: Option<Kzg>,
) -> Self {
let handle = executor.handle().unwrap();
@@ -58,6 +61,7 @@ impl<T: EthSpec> MockExecutionLayer<T> {
spec.terminal_block_hash,
shanghai_time,
deneb_time,
kzg,
);
let url = SensitiveUrl::parse(&server.url()).unwrap();

View File

@@ -8,6 +8,7 @@ use bytes::Bytes;
use environment::null_logger;
use execution_block_generator::PoWBlock;
use handle_rpc::handle_rpc;
use kzg::Kzg;
use parking_lot::{Mutex, RwLock, RwLockWriteGuard};
use serde::{Deserialize, Serialize};
use serde_json::json;
@@ -96,10 +97,15 @@ impl<T: EthSpec> MockServer<T> {
ExecutionBlockHash::zero(),
None, // FIXME(capella): should this be the default?
None, // FIXME(deneb): should this be the default?
None, // FIXME(deneb): should this be the default?
)
}
pub fn new_with_config(handle: &runtime::Handle, config: MockExecutionConfig) -> Self {
pub fn new_with_config(
handle: &runtime::Handle,
config: MockExecutionConfig,
kzg: Option<Kzg>,
) -> Self {
let MockExecutionConfig {
jwt_key,
terminal_difficulty,
@@ -117,6 +123,7 @@ impl<T: EthSpec> MockServer<T> {
terminal_block_hash,
shanghai_time,
deneb_time,
kzg,
);
let ctx: Arc<Context<T>> = Arc::new(Context {
@@ -168,6 +175,7 @@ impl<T: EthSpec> MockServer<T> {
*self.ctx.engine_capabilities.write() = engine_capabilities;
}
#[allow(clippy::too_many_arguments)]
pub fn new(
handle: &runtime::Handle,
jwt_key: JwtKey,
@@ -176,6 +184,7 @@ impl<T: EthSpec> MockServer<T> {
terminal_block_hash: ExecutionBlockHash,
shanghai_time: Option<u64>,
deneb_time: Option<u64>,
kzg: Option<Kzg>,
) -> Self {
Self::new_with_config(
handle,
@@ -188,6 +197,7 @@ impl<T: EthSpec> MockServer<T> {
shanghai_time,
deneb_time,
},
kzg,
)
}