From f254ac427917d29a5227cd9b417c221cb6edcd24 Mon Sep 17 00:00:00 2001 From: Sylvain Ribstein Date: Wed, 21 Feb 2024 10:37:41 +0100 Subject: [PATCH] etherlink: add sequencer_pool_address to kernel and node --- etherlink/CHANGES_KERNEL.md | 11 ++--- .../lib_dev/encodings/ethereum_types.ml | 30 ++++++++----- etherlink/bin_node/main.ml | 35 +++++++++------ .../kernel_evm/ethereum/src/rlp_helpers.rs | 44 ++++++++++++++++++- etherlink/kernel_evm/kernel/src/storage.rs | 1 - etherlink/kernel_evm/kernel/src/upgrade.rs | 25 ++++++++++- etherlink/tezt/lib/evm_node.ml | 6 ++- etherlink/tezt/lib/evm_node.mli | 8 ++-- etherlink/tezt/lib/helpers.ml | 4 +- etherlink/tezt/lib/helpers.mli | 1 + etherlink/tezt/tests/evm_rollup.ml | 2 + etherlink/tezt/tests/evm_sequencer.ml | 1 + 12 files changed, 131 insertions(+), 37 deletions(-) diff --git a/etherlink/CHANGES_KERNEL.md b/etherlink/CHANGES_KERNEL.md index b2346dff29d5..b8a38510b25a 100644 --- a/etherlink/CHANGES_KERNEL.md +++ b/etherlink/CHANGES_KERNEL.md @@ -15,11 +15,12 @@ ### Breaking changes -- Sequencer upgrade expect an activation timestamp attached to the new - public key. The new sequencer is activated when the rollup sees a l1 - block with a timestamp greater than or equal to the activation - timestamp. Blueprint in the storage are deleted during the sequencer - upgrade as they can be trusted anymore. (!12038) +- Sequencer upgrade expect an activation timestamp and an etherlink + pool address attached to the new public key. The new sequencer is + activated when the rollup sees a l1 block with a timestamp greater + than or equal to the activation timestamp. Blueprint in the storage + are deleted during the sequencer upgrade as they can be trusted + anymore. (!12038, !12046) ### Internal diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml index a3da347e84ff..c9d57a0240df 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml @@ -1283,23 +1283,29 @@ module Upgrade = struct end module Sequencer_upgrade = struct - type t = {sequencer : Signature.public_key; timestamp : Time.Protocol.t} + type t = { + sequencer : Signature.public_key; + pool_address : address; + timestamp : Time.Protocol.t; + } let of_rlp = function - | Rlp.List [Value sequencer; Value timestamp] -> + | Rlp.List [Value sequencer; Value pool_address; Value timestamp] -> let sequencer = Signature.Public_key.of_b58check_exn (String.of_bytes sequencer) in let timestamp = timestamp_of_bytes timestamp in - Some {sequencer; timestamp} + let pool_address = decode_address pool_address in + Some {sequencer; pool_address; timestamp} | _ -> None - let to_rlp {sequencer; timestamp} = + let to_rlp {sequencer; pool_address; timestamp} = let sequencer = Signature.Public_key.to_b58check sequencer |> String.to_bytes in let timestamp = timestamp_to_bytes timestamp in - Rlp.List [Value sequencer; Value timestamp] + let pool_address = encode_address pool_address in + Rlp.List [Value sequencer; Value pool_address; Value timestamp] let of_bytes bytes = match bytes |> Rlp.decode with Ok rlp -> of_rlp rlp | _ -> None @@ -1309,9 +1315,11 @@ module Sequencer_upgrade = struct let encoding = let open Data_encoding in conv - (fun {sequencer; timestamp} -> (sequencer, timestamp)) - (fun (sequencer, timestamp) -> {sequencer; timestamp}) - (tup2 Signature.Public_key.encoding Time.Protocol.encoding) + (fun {sequencer; pool_address = Address (Hex pool_address); timestamp} -> + (sequencer, pool_address, timestamp)) + (fun (sequencer, pool_address, timestamp) -> + {sequencer; pool_address = Address (Hex pool_address); timestamp}) + (tup3 Signature.Public_key.encoding string Time.Protocol.encoding) end module Evm_events = struct @@ -1341,12 +1349,14 @@ module Evm_events = struct hash Time.Protocol.pp_hum timestamp - | Sequencer_upgrade_event {sequencer; timestamp} -> + | Sequencer_upgrade_event + {sequencer; pool_address = Address (Hex address); timestamp} -> Format.fprintf fmt - "Sequencer_upgrade:@ sequencer:@ %a,@ timestamp %a" + "SequencerUpgrade:@ sequencer:@ %a,pool_address %s,@ timestamp: %a" Signature.Public_key.pp sequencer + address Time.Protocol.pp_hum timestamp diff --git a/etherlink/bin_node/main.ml b/etherlink/bin_node/main.ml index 84ef5ceafab3..e0575a123c48 100644 --- a/etherlink/bin_node/main.ml +++ b/etherlink/bin_node/main.ml @@ -325,6 +325,14 @@ module Params = struct "Timestamp must be either in RFC3399 format (e.g., \ [\"1970-01-01T00:00:00Z\"]) or in number of seconds since \ the {!Time.Protocol.epoch}.")) + + let l2_address = + Tezos_clic.parameter (fun _ s -> + let hex_addr = + Option.value ~default:s @@ String.remove_prefix ~prefix:"0x" s + in + Lwt.return_ok + @@ Evm_node_lib_dev_encoding.Ethereum_types.(Address (Hex hex_addr))) end let wallet_dir_arg = @@ -1056,23 +1064,24 @@ let make_sequencer_upgrade_command = command ~desc:"Create bytes payload for the sequencer upgrade entrypoint" (args2 wallet_dir_arg devmode_arg) - (prefixes - [ - "make"; - "sequencer"; - "upgrade"; - "payload"; - "at"; - "activation"; - "timestamp"; - ] + (prefixes ["make"; "sequencer"; "upgrade"; "payload"] + @@ prefixes ["with"; "pool"; "address"] + @@ Tezos_clic.param + ~name:"pool_address" + ~desc:"pool address of the sequencer" + Params.l2_address + @@ prefixes ["at"; "activation"; "timestamp"] @@ param ~name:"activation_timestamp" ~desc: "After activation timestamp, the kernel will upgrade to this value" Params.timestamp @@ prefix "for" @@ Params.sequencer_key @@ stop) - (fun (wallet_dir, devmode) activation_timestamp sequencer_str () -> + (fun (wallet_dir, devmode) + pool_address + activation_timestamp + sequencer_str + () -> let wallet_ctxt = register_wallet ~wallet_dir in let* _pk_uri, sequencer_pk_opt = Client_keys.Public_key.parse_source_string wallet_ctxt sequencer_str @@ -1085,8 +1094,8 @@ let make_sequencer_upgrade_command = let* payload = if devmode then let open Evm_node_lib_dev_encoding.Ethereum_types in - let sequencer_upgrade = - Sequencer_upgrade.{sequencer; timestamp = activation_timestamp} + let sequencer_upgrade : Sequencer_upgrade.t = + {sequencer; pool_address; timestamp = activation_timestamp} in return @@ Sequencer_upgrade.to_bytes sequencer_upgrade else diff --git a/etherlink/kernel_evm/ethereum/src/rlp_helpers.rs b/etherlink/kernel_evm/ethereum/src/rlp_helpers.rs index b03e08c3e36d..74f29b691b2a 100644 --- a/etherlink/kernel_evm/ethereum/src/rlp_helpers.rs +++ b/etherlink/kernel_evm/ethereum/src/rlp_helpers.rs @@ -8,7 +8,7 @@ use crate::transaction::{ TransactionHash, TransactionStatus, TransactionType, TRANSACTION_HASH_SIZE, }; -use primitive_types::{H256, U256}; +use primitive_types::{H160, H256, U256}; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpIterator, RlpStream}; use tezos_smart_rollup_encoding::{public_key::PublicKey, timestamp::Timestamp}; @@ -60,6 +60,23 @@ pub fn decode_field_h256( decode_h256(decoder).map_err(custom_err) } +pub fn decode_h160(decoder: &Rlp<'_>) -> Result { + let bytes = decoder.data()?; + const H160_EXPECTED_LENGTH: usize = std::mem::size_of::(); + let length = bytes.len(); + if length == H160_EXPECTED_LENGTH { + Ok(H160::from_slice(bytes)) + } else if length < H160_EXPECTED_LENGTH && length > 0 { + // there were missing 0 that encoding deleted + let missing = H160_EXPECTED_LENGTH - length; + let mut full = [0u8; H160_EXPECTED_LENGTH]; + full[missing..].copy_from_slice(bytes); + Ok(H160::from(full)) + } else { + Err(DecoderError::RlpInvalidLength) + } +} + pub fn decode_option( decoder: &Rlp<'_>, field_name: &'static str, @@ -330,3 +347,28 @@ pub fn decode_public_key(decoder: &Rlp<'_>) -> Result { })?; Ok(pk) } + +#[cfg(test)] +mod tests { + use crate::rlp_helpers::decode_h160; + use primitive_types::H160; + use rlp::{Rlp, RlpStream}; + + #[test] + fn roundtrip_h160() { + let partial_bytes: [u8; 16] = [1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0]; + let full_bytes: [u8; 20] = + [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0]; + let h160 = H160::from(full_bytes); + + let mut stream = RlpStream::new(); + stream.encoder().encode_value(&partial_bytes); + let encoded_bytes = stream.out(); + let decoder = Rlp::new(&encoded_bytes); + let result_h160 = decode_h160(&decoder).unwrap(); + let result_bytes = result_h160.as_fixed_bytes(); + + assert!(result_h160.eq(&h160)); + assert!(result_bytes.eq(&full_bytes)); + } +} diff --git a/etherlink/kernel_evm/kernel/src/storage.rs b/etherlink/kernel_evm/kernel/src/storage.rs index a0b29be17eb9..c075b4077526 100644 --- a/etherlink/kernel_evm/kernel/src/storage.rs +++ b/etherlink/kernel_evm/kernel/src/storage.rs @@ -655,7 +655,6 @@ pub fn read_sequencer_pool_address(host: &impl Runtime) -> Option { Some(bytes.into()) } -#[cfg(test)] pub fn store_sequencer_pool_address( host: &mut impl Runtime, address: H160, diff --git a/etherlink/kernel_evm/kernel/src/upgrade.rs b/etherlink/kernel_evm/kernel/src/upgrade.rs index 01e005b881dd..2cf32ce47b72 100644 --- a/etherlink/kernel_evm/kernel/src/upgrade.rs +++ b/etherlink/kernel_evm/kernel/src/upgrade.rs @@ -5,19 +5,24 @@ // SPDX-License-Identifier: MIT use crate::blueprint_storage; +use core::fmt; + use crate::error::UpgradeProcessError; use crate::event::Event; use crate::safe_storage::KernelRuntime; use crate::storage; use crate::storage::read_optional_rlp; use crate::storage::store_sequencer; +use crate::storage::store_sequencer_pool_address; use anyhow::Context; +use primitive_types::H160; use rlp::Decodable; use rlp::DecoderError; use rlp::Encodable; use tezos_ethereum::rlp_helpers::append_public_key; use tezos_ethereum::rlp_helpers::append_timestamp; use tezos_ethereum::rlp_helpers::decode_field; +use tezos_ethereum::rlp_helpers::decode_h160; use tezos_ethereum::rlp_helpers::decode_public_key; use tezos_ethereum::rlp_helpers::decode_timestamp; use tezos_ethereum::rlp_helpers::next; @@ -129,11 +134,22 @@ pub fn upgrade( #[derive(Debug, PartialEq, Clone)] pub struct SequencerUpgrade { pub sequencer: PublicKey, + pub pool_address: H160, pub activation_timestamp: Timestamp, } impl SequencerUpgrade { - const RLP_LIST_SIZE: usize = 2; + const RLP_LIST_SIZE: usize = 3; +} + +impl fmt::Display for SequencerUpgrade { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "sequencer: {}, pool_address: {}, activation_timestamp: {}", + self.sequencer, self.pool_address, self.activation_timestamp + ) + } } impl Decodable for SequencerUpgrade { @@ -147,10 +163,12 @@ impl Decodable for SequencerUpgrade { let mut it = decoder.iter(); let sequencer = decode_public_key(&next(&mut it)?)?; + let pool_address = decode_h160(&next(&mut it)?)?; let activation_timestamp = decode_timestamp(&next(&mut it)?)?; Ok(Self { sequencer, + pool_address, activation_timestamp, }) } @@ -160,6 +178,7 @@ impl Encodable for SequencerUpgrade { fn rlp_append(&self, stream: &mut rlp::RlpStream) { stream.begin_list(SequencerUpgrade::RLP_LIST_SIZE); append_public_key(stream, &self.sequencer); + stream.append(&self.pool_address); append_timestamp(stream, self.activation_timestamp); } } @@ -196,11 +215,13 @@ fn delete_sequencer_upgrade(host: &mut Host) -> anyhow::Result<() fn sequencer_upgrade( host: &mut Host, + pool_address: H160, sequencer: &PublicKey, ) -> anyhow::Result<()> { log!(host, Info, "sequencer upgrade initialisation."); store_sequencer(host, sequencer)?; + store_sequencer_pool_address(host, pool_address)?; delete_sequencer_upgrade(host)?; log!(host, Info, "Sequencer has been updated."); Ok(()) @@ -213,7 +234,7 @@ pub fn possible_sequencer_upgrade( if let Some(upgrade) = upgrade { let ipl_timestamp = storage::read_last_info_per_level_timestamp(host)?; if ipl_timestamp >= upgrade.activation_timestamp { - sequencer_upgrade(host, &upgrade.sequencer)?; + sequencer_upgrade(host, upgrade.pool_address, &upgrade.sequencer)?; blueprint_storage::clear_all_blueprint(host)?; } } diff --git a/etherlink/tezt/lib/evm_node.ml b/etherlink/tezt/lib/evm_node.ml index 44ea3a10622a..df110c8fe860 100644 --- a/etherlink/tezt/lib/evm_node.ml +++ b/etherlink/tezt/lib/evm_node.ml @@ -503,13 +503,17 @@ let transform_dump ~dump_json ~dump_rlp = Process.check process let sequencer_upgrade_payload ?(devmode = true) ?client ~public_key - ~activation_timestamp () = + ~pool_address ~activation_timestamp () = let args = [ "make"; "sequencer"; "upgrade"; "payload"; + "with"; + "pool"; + "address"; + pool_address; "at"; "activation"; "timestamp"; diff --git a/etherlink/tezt/lib/evm_node.mli b/etherlink/tezt/lib/evm_node.mli index e77002096bce..54829d615be9 100644 --- a/etherlink/tezt/lib/evm_node.mli +++ b/etherlink/tezt/lib/evm_node.mli @@ -106,8 +106,9 @@ val wait_for_blueprint_applied : timeout:float -> t -> int -> unit Lwt.t [evm_node] has injected a blueprint for level [level] to its rollup node. *) val wait_for_blueprint_injected : timeout:float -> t -> int -> unit Lwt.t -(** [init ?runner ?mode ?data_dir ?rpc_addr ?rpc_port rollup_node_endpoint] - creates an EVM node server with {!create} and runs it with {!run}. *) +(** [init ?name ?runner ?mode ?data_dir ?rpc_addr ?rpc_port + rollup_node_endpoint] creates an EVM node server with {!create} + and runs it with {!run}. *) val init : ?name:string -> ?runner:Runner.t -> @@ -180,7 +181,7 @@ val txpool_content : t -> (txpool_slot list * txpool_slot list) Lwt.t val upgrade_payload : root_hash:string -> activation_timestamp:string -> string Lwt.t -(** [sequencer_upgrade_payload ?devmode ?client ~public_key +(** [sequencer_upgrade_payload ?devmode ?client ~public_key ~pool_address ~activation_timestamp ()] gives the sequencer upgrade payload to put in a upgrade message, it will upgrade the sequencer to [public_key] at the first l1 block after [activation_timestamp] @@ -189,6 +190,7 @@ val sequencer_upgrade_payload : ?devmode:bool -> ?client:Client.t -> public_key:string -> + pool_address:string -> activation_timestamp:string -> unit -> string Lwt.t diff --git a/etherlink/tezt/lib/helpers.ml b/etherlink/tezt/lib/helpers.ml index 59349acdd8c0..d83ce427e232 100644 --- a/etherlink/tezt/lib/helpers.ml +++ b/etherlink/tezt/lib/helpers.ml @@ -138,11 +138,13 @@ let check_head_consistency ~left ~right ?error_msg () = unit let sequencer_upgrade ~sc_rollup_address ~sequencer_admin - ~sequencer_admin_contract ~client ~upgrade_to ~activation_timestamp = + ~sequencer_admin_contract ~client ~upgrade_to ~pool_address + ~activation_timestamp = let* payload = Evm_node.sequencer_upgrade_payload ~client ~public_key:upgrade_to + ~pool_address ~activation_timestamp () in diff --git a/etherlink/tezt/lib/helpers.mli b/etherlink/tezt/lib/helpers.mli index 80f976d8a672..2cd09b1c8b15 100644 --- a/etherlink/tezt/lib/helpers.mli +++ b/etherlink/tezt/lib/helpers.mli @@ -112,5 +112,6 @@ val sequencer_upgrade : sequencer_admin_contract:string -> client:Client.t -> upgrade_to:string -> + pool_address:string -> activation_timestamp:string -> unit Lwt.t diff --git a/etherlink/tezt/tests/evm_rollup.ml b/etherlink/tezt/tests/evm_rollup.ml index b2e6525be6dd..050420da9463 100644 --- a/etherlink/tezt/tests/evm_rollup.ml +++ b/etherlink/tezt/tests/evm_rollup.ml @@ -4488,6 +4488,7 @@ let test_migrate_proxy_to_sequencer_future = ~client ~upgrade_to:sequencer_key.alias ~activation_timestamp + ~pool_address:Eth_account.bootstrap_accounts.(0).address in let sequencer_node = let mode = @@ -4626,6 +4627,7 @@ let test_migrate_proxy_to_sequencer_past = ~client ~upgrade_to:sequencer_key.alias ~activation_timestamp:"0" + ~pool_address:Eth_account.bootstrap_accounts.(0).address in let* () = (* We need to bake 3 blocks, because otherwise the sequencer upgrade event diff --git a/etherlink/tezt/tests/evm_sequencer.ml b/etherlink/tezt/tests/evm_sequencer.ml index 3e78909eeeb7..e10782e0e081 100644 --- a/etherlink/tezt/tests/evm_sequencer.ml +++ b/etherlink/tezt/tests/evm_sequencer.ml @@ -1770,6 +1770,7 @@ let test_sequencer_upgrade = ~sc_rollup_address ~sequencer_admin:Constant.bootstrap2.alias ~sequencer_admin_contract:l1_contracts.sequencer_admin + ~pool_address:Eth_account.bootstrap_accounts.(0).address ~client ~upgrade_to:new_sequencer_key ~activation_timestamp:"0" -- GitLab