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

feat: canyon support #191

Merged
merged 11 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ services:
<<: *logging

op-geth:
image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:v1.101304.1
image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:v1.101304.2
container_name: op-geth
profiles:
- op-geth
Expand Down
12 changes: 12 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ pub struct ChainConfig {
pub max_seq_drift: u64,
/// Timestamp of the regolith hardfork
pub regolith_time: u64,
/// Timestamp of the canyon hardfork
pub canyon_time: u64,
/// Network blocktime
#[serde(default = "default_blocktime")]
pub blocktime: u64,
Expand Down Expand Up @@ -252,6 +254,7 @@ impl ChainConfig {
max_seq_drift: 600,
blocktime: 2,
regolith_time: 0,
canyon_time: u64::MAX,
}
}

Expand Down Expand Up @@ -289,6 +292,7 @@ impl ChainConfig {
seq_window_size: 3600,
max_seq_drift: 600,
regolith_time: 1679079600,
canyon_time: 1699981200,
blocktime: 2,
}
}
Expand Down Expand Up @@ -326,6 +330,7 @@ impl ChainConfig {
seq_window_size: 3600,
max_seq_drift: 600,
regolith_time: 0,
canyon_time: 1699981200,
blocktime: 2,
}
}
Expand Down Expand Up @@ -363,6 +368,7 @@ impl ChainConfig {
max_seq_drift: 600,
blocktime: 2,
regolith_time: 0,
canyon_time: u64::MAX,
}
}

Expand Down Expand Up @@ -398,6 +404,7 @@ impl ChainConfig {
seq_window_size: 3600,
max_seq_drift: 600,
regolith_time: 1683219600,
canyon_time: 1699981200,
blocktime: 2,
}
}
Expand Down Expand Up @@ -440,6 +447,7 @@ pub struct ExternalChainConfig {
l1_chain_id: u64,
l2_chain_id: u64,
regolith_time: u64,
canyon_time: u64,
batch_inbox_address: Address,
deposit_contract_address: Address,
l1_system_config_address: Address,
Expand Down Expand Up @@ -501,6 +509,7 @@ impl From<ExternalChainConfig> for ChainConfig {
seq_window_size: external.seq_window_size,
max_seq_drift: external.max_sequencer_drift,
regolith_time: external.regolith_time,
canyon_time: external.canyon_time,
blocktime: external.block_time,
l2_to_l1_message_passer: addr("0x4200000000000000000000000000000000000016"),
}
Expand Down Expand Up @@ -546,6 +555,7 @@ impl From<ChainConfig> for ExternalChainConfig {
l1_chain_id: chain_config.l1_chain_id,
l2_chain_id: chain_config.l2_chain_id,
regolith_time: chain_config.regolith_time,
canyon_time: chain_config.canyon_time,
batch_inbox_address: chain_config.batch_inbox,
deposit_contract_address: chain_config.deposit_contract,
l1_system_config_address: chain_config.system_config_contract,
Expand Down Expand Up @@ -672,6 +682,7 @@ mod test {
"l1_chain_id": 900,
"l2_chain_id": 901,
"regolith_time": 0,
"canyon_time": 0,
"batch_inbox_address": "0xff00000000000000000000000000000000000000",
"deposit_contract_address": "0x6900000000000000000000000000000000000001",
"l1_system_config_address": "0x6900000000000000000000000000000000000009"
Expand Down Expand Up @@ -718,6 +729,7 @@ mod test {
assert_eq!(chain.seq_window_size, 200);
assert_eq!(chain.max_seq_drift, 300);
assert_eq!(chain.regolith_time, 0);
assert_eq!(chain.canyon_time, 0);
assert_eq!(chain.blocktime, 2);
assert_eq!(
chain.l2_to_l1_message_passer,
Expand Down
11 changes: 9 additions & 2 deletions src/derive/stages/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ impl Attributes {
timestamp: l1_info.block_info.timestamp,
});

let withdrawals = if batch.timestamp >= self.config.chain.canyon_time {
Some(Vec::new())
} else {
None
};

let timestamp = U64([batch.timestamp]);
let l1_inclusion_block = Some(batch.l1_inclusion_block);
let seq_number = Some(self.sequence_number);
Expand All @@ -88,6 +94,7 @@ impl Attributes {
transactions,
no_tx_pool: true,
gas_limit: U64([l1_info.system_config.gas_limit.as_u64()]),
withdrawals,
epoch,
l1_inclusion_block,
seq_number,
Expand Down Expand Up @@ -317,8 +324,8 @@ impl TryFrom<Log> for UserDeposited {
.into_bytes()
.unwrap();

let from = Address::try_from(log.topics[1])?;
let to = Address::try_from(log.topics[2])?;
let from = Address::from(log.topics[1]);
let to = Address::from(log.topics[2]);
let mint = U256::from_big_endian(&opaque_data[0..32]);
let value = U256::from_big_endian(&opaque_data[32..64]);
let gas = u64::from_be_bytes(opaque_data[64..72].try_into()?);
Expand Down
20 changes: 14 additions & 6 deletions src/engine/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::engine::DEFAULT_AUTH_PORT;
use crate::engine::ENGINE_GET_PAYLOAD_V1;

use super::{
Engine, ExecutionPayload, ForkChoiceUpdate, ForkchoiceState, JwtSecret, PayloadAttributes,
PayloadId, PayloadStatus, ENGINE_FORKCHOICE_UPDATED_V1, ENGINE_NEW_PAYLOAD_V1,
PayloadId, PayloadStatus, ENGINE_FORKCHOICE_UPDATED_V2, ENGINE_GET_PAYLOAD_V2,
ENGINE_NEW_PAYLOAD_V2,
};

use super::{JSONRPC_VERSION, STATIC_ID};
Expand Down Expand Up @@ -217,25 +217,33 @@ impl Engine for EngineApi {
};
let forkchoice_state_param = serde_json::to_value(forkchoice_state)?;
let params = vec![forkchoice_state_param, payload_attributes_param];
let res = self.post(ENGINE_FORKCHOICE_UPDATED_V1, params).await?;
let res = self.post(ENGINE_FORKCHOICE_UPDATED_V2, params).await?;
Ok(res)
}

async fn new_payload(&self, execution_payload: ExecutionPayload) -> Result<PayloadStatus> {
let params = vec![serde_json::to_value(execution_payload)?];
let res = self.post(ENGINE_NEW_PAYLOAD_V1, params).await?;
let res = self.post(ENGINE_NEW_PAYLOAD_V2, params).await?;
Ok(res)
}

async fn get_payload(&self, payload_id: PayloadId) -> Result<ExecutionPayload> {
let encoded = format!("{:x}", payload_id);
let padded = format!("0x{:0>16}", encoded);
let params = vec![Value::String(padded)];
let res = self.post(ENGINE_GET_PAYLOAD_V1, params).await?;
Ok(res)
let res = self
.post::<GetPayloadResponse>(ENGINE_GET_PAYLOAD_V2, params)
.await?;
Ok(res.execution_payload)
}
}

#[derive(Debug, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
struct GetPayloadResponse {
execution_payload: ExecutionPayload,
}

#[cfg(test)]
mod tests {
use std::time::SystemTime;
Expand Down
8 changes: 8 additions & 0 deletions src/engine/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ pub struct ExecutionPayload {
pub block_hash: H256,
/// An array of transaction objects where each object is a byte list
pub transactions: Vec<RawTransaction>,
/// An array of beaconchain withdrawals. Always empty as this exists only for L1 compatibility
#[serde(skip_serializing_if = "Option::is_none")]
pub withdrawals: Option<Vec<()>>,
}

impl TryFrom<Block<Transaction>> for ExecutionPayload {
Expand Down Expand Up @@ -71,6 +74,7 @@ impl TryFrom<Block<Transaction>> for ExecutionPayload {
.into(),
block_hash: value.hash.unwrap(),
transactions: encoded_txs,
withdrawals: Some(Vec::new()),
})
}
}
Expand All @@ -97,6 +101,10 @@ pub struct PayloadAttributes {
/// This field overrides the gas limit used during block-building.
/// If not specified as rollup, a STATUS_INVALID is returned.
pub gas_limit: U64,
/// Beaconchain withdrawals. This exists only for compatibility with L1, and is not used. Prior
/// to Canyon, this value is always None. After Canyon it is an empty array. Note that we use
/// the () type here since we never have a non empty array.
pub withdrawals: Option<Vec<()>>,
/// The batch epoch number from derivation. This value is not expected by the engine is skipped
/// during serialization and deserialization.
#[serde(skip)]
Expand Down
9 changes: 3 additions & 6 deletions src/engine/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,19 @@ pub const STATIC_ID: u32 = 1;
pub const JSONRPC_VERSION: &str = "2.0";

/// The new payload method string
pub const ENGINE_NEW_PAYLOAD_V1: &str = "engine_newPayloadV1";
// pub const ENGINE_NEW_PAYLOAD_V2: &str = "engine_newPayloadV2";
pub const ENGINE_NEW_PAYLOAD_V2: &str = "engine_newPayloadV2";

/// The new payload timeout
pub const ENGINE_NEW_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(8);

/// The get payload method string
pub const ENGINE_GET_PAYLOAD_V1: &str = "engine_getPayloadV1";
// pub const ENGINE_GET_PAYLOAD_V2: &str = "engine_getPayloadV2";
pub const ENGINE_GET_PAYLOAD_V2: &str = "engine_getPayloadV2";

/// The get payload timeout
pub const ENGINE_GET_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(2);

/// The forkchoice updated method string
pub const ENGINE_FORKCHOICE_UPDATED_V1: &str = "engine_forkchoiceUpdatedV1";
// pub const ENGINE_FORKCHOICE_UPDATED_V2: &str = "engine_forkchoiceUpdatedV2";
pub const ENGINE_FORKCHOICE_UPDATED_V2: &str = "engine_forkchoiceUpdatedV2";

/// The forkchoice updated timeout
pub const ENGINE_FORKCHOICE_UPDATED_TIMEOUT: Duration = Duration::from_secs(8);
82 changes: 74 additions & 8 deletions src/network/handlers/block_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,23 @@ pub struct BlockHandler {
chain_id: u64,
block_sender: Sender<ExecutionPayload>,
unsafe_signer_recv: watch::Receiver<Address>,
blocks_v1_topic: IdentTopic,
blocks_v2_topic: IdentTopic,
}

impl Handler for BlockHandler {
fn handle(&self, msg: Message) -> MessageAcceptance {
tracing::debug!("received block");

match decode_block_msg(msg.data) {
let decoded = if msg.topic == self.blocks_v1_topic.hash() {
decode_block_msg::<ExecutionPayloadV1SSZ>(msg.data)
} else if msg.topic == self.blocks_v2_topic.hash() {
decode_block_msg::<ExecutionPayloadV2SSZ>(msg.data)
} else {
return MessageAcceptance::Reject;
};

match decoded {
Ok((payload, signature, payload_hash)) => {
if self.block_valid(&payload, signature, payload_hash) {
_ = self.block_sender.send(payload);
Expand All @@ -39,8 +49,8 @@ impl Handler for BlockHandler {
}
}

fn topic(&self) -> TopicHash {
IdentTopic::new(format!("/optimism/{}/0/blocks", self.chain_id)).into()
fn topics(&self) -> Vec<TopicHash> {
vec![self.blocks_v1_topic.hash(), self.blocks_v2_topic.hash()]
}
}

Expand All @@ -55,6 +65,8 @@ impl BlockHandler {
chain_id,
block_sender: sender,
unsafe_signer_recv: unsafe_recv,
blocks_v1_topic: IdentTopic::new(format!("/optimism/{}/0/blocks", chain_id)),
blocks_v2_topic: IdentTopic::new(format!("/optimism/{}/1/blocks", chain_id)),
};

(handler, recv)
Expand Down Expand Up @@ -83,15 +95,19 @@ impl BlockHandler {
}
}

fn decode_block_msg(data: Vec<u8>) -> Result<(ExecutionPayload, Signature, PayloadHash)> {
fn decode_block_msg<T>(data: Vec<u8>) -> Result<(ExecutionPayload, Signature, PayloadHash)>
where
T: SimpleSerialize,
ExecutionPayload: From<T>,
{
let mut decoder = snap::raw::Decoder::new();
let decompressed = decoder.decompress_vec(&data)?;
let sig_data = &decompressed[..65];
let block_data = &decompressed[65..];

let signature = Signature::try_from(sig_data)?;

let payload: ExecutionPayloadSSZ = deserialize(block_data)?;
let payload: T = deserialize(block_data)?;
let payload: ExecutionPayload = ExecutionPayload::from(payload);

let payload_hash = PayloadHash::from(block_data);
Expand Down Expand Up @@ -129,7 +145,7 @@ type VecAddress = Vector<u8, 20>;
type Transaction = List<u8, 1073741824>;

#[derive(SimpleSerialize, Default)]
struct ExecutionPayloadSSZ {
struct ExecutionPayloadV1SSZ {
pub parent_hash: Bytes32,
pub fee_recipient: VecAddress,
pub state_root: Bytes32,
Expand All @@ -146,8 +162,57 @@ struct ExecutionPayloadSSZ {
pub transactions: List<Transaction, 1048576>,
}

impl From<ExecutionPayloadSSZ> for ExecutionPayload {
fn from(value: ExecutionPayloadSSZ) -> Self {
impl From<ExecutionPayloadV1SSZ> for ExecutionPayload {
fn from(value: ExecutionPayloadV1SSZ) -> Self {
Self {
parent_hash: convert_hash(value.parent_hash),
fee_recipient: convert_address(value.fee_recipient),
state_root: convert_hash(value.state_root),
receipts_root: convert_hash(value.receipts_root),
logs_bloom: convert_byte_vector(value.logs_bloom),
prev_randao: convert_hash(value.prev_randao),
block_number: value.block_number.into(),
gas_limit: value.gas_limit.into(),
gas_used: value.gas_used.into(),
timestamp: value.timestamp.into(),
extra_data: convert_byte_list(value.extra_data),
base_fee_per_gas: convert_uint(value.base_fee_per_gas),
block_hash: convert_hash(value.block_hash),
transactions: convert_tx_list(value.transactions),
withdrawals: None,
}
}
}

#[derive(SimpleSerialize, Default)]
struct ExecutionPayloadV2SSZ {
pub parent_hash: Bytes32,
pub fee_recipient: VecAddress,
pub state_root: Bytes32,
pub receipts_root: Bytes32,
pub logs_bloom: Vector<u8, 256>,
pub prev_randao: Bytes32,
pub block_number: u64,
pub gas_limit: u64,
pub gas_used: u64,
pub timestamp: u64,
pub extra_data: List<u8, 32>,
pub base_fee_per_gas: U256,
pub block_hash: Bytes32,
pub transactions: List<Transaction, 1048576>,
pub withdrawals: List<Withdrawal, 16>,
}

#[derive(SimpleSerialize, Default)]
struct Withdrawal {
index: u64,
validator_index: u64,
address: VecAddress,
amount: u64,
}

impl From<ExecutionPayloadV2SSZ> for ExecutionPayload {
fn from(value: ExecutionPayloadV2SSZ) -> Self {
Self {
parent_hash: convert_hash(value.parent_hash),
fee_recipient: convert_address(value.fee_recipient),
Expand All @@ -163,6 +228,7 @@ impl From<ExecutionPayloadSSZ> for ExecutionPayload {
base_fee_per_gas: convert_uint(value.base_fee_per_gas),
block_hash: convert_hash(value.block_hash),
transactions: convert_tx_list(value.transactions),
withdrawals: Some(Vec::new()),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/network/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ pub mod block_handler;

pub trait Handler: Send {
fn handle(&self, msg: Message) -> MessageAcceptance;
fn topic(&self) -> TopicHash;
fn topics(&self) -> Vec<TopicHash>;
}
2 changes: 1 addition & 1 deletion src/network/service/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub fn start(addr: NetworkAddress, chain_id: u64) -> Result<Receiver<Peer>> {
}
}

sleep(Duration::from_secs(30)).await;
sleep(Duration::from_secs(10)).await;
}
});

Expand Down
Loading
Loading