diff --git a/src/bin_evm_proxy/lib_dev/mockup.ml b/src/bin_evm_proxy/lib_dev/mockup.ml index b0c3511d5861adcdc7c5bf4f24a3686610b63037..408a3496a80e72e056cad731ebe9a51317bd51c5 100644 --- a/src/bin_evm_proxy/lib_dev/mockup.ml +++ b/src/bin_evm_proxy/lib_dev/mockup.ml @@ -3,6 +3,7 @@ (* Open Source License *) (* Copyright (c) 2023 Nomadic Labs *) (* Copyright (c) 2023 Functori *) +(* Copyright (c) 2023 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -230,3 +231,5 @@ let txpool _ = (NonceMap.add Z.zero tx_queued NonceMap.empty) AddressMap.empty; } + +let is_tx_valid _ = Ok () |> return diff --git a/src/bin_evm_proxy/lib_dev/rollup_node.ml b/src/bin_evm_proxy/lib_dev/rollup_node.ml index 03bfe517c0605454e32ac5354aaf3a6e970e8785..3ff006567d068817ba6e7580f3f59c17f52ffd8c 100644 --- a/src/bin_evm_proxy/lib_dev/rollup_node.ml +++ b/src/bin_evm_proxy/lib_dev/rollup_node.ml @@ -430,6 +430,26 @@ module RPC = struct {messages; reveal_pages = None; insight_requests} in Simulation.gas_estimation r + + let is_tx_valid base tx_raw = + let (Hash tx_raw) = tx_raw in + let open Lwt_result_syntax in + let*? messages = Simulation.encode_tx tx_raw in + let insight_requests = + [ + Simulation.Encodings.Durable_storage_key ["evm"; "simulation_status"]; + Simulation.Encodings.Durable_storage_key ["evm"; "simulation_result"]; + ] + in + let* r = + call_service + ~base + simulation + () + () + {messages; reveal_pages = None; insight_requests} + in + Simulation.is_tx_valid r end module type S = sig @@ -472,6 +492,8 @@ module type S = sig val estimate_gas : Ethereum_types.call -> Ethereum_types.quantity tzresult Lwt.t + + val is_tx_valid : Ethereum_types.hash -> (unit, string) result tzresult Lwt.t end module Make (Base : sig @@ -508,4 +530,6 @@ end) : S = struct let simulate_call = RPC.simulate_call Base.base let estimate_gas = RPC.estimate_gas Base.base + + let is_tx_valid = RPC.is_tx_valid Base.base end diff --git a/src/bin_evm_proxy/lib_dev/rollup_node.mli b/src/bin_evm_proxy/lib_dev/rollup_node.mli index 81ca3f0d4819f18051a5980da93a3ebc45bc04f3..838dac685efec463a30c98bc7fd1dfb1b667421f 100644 --- a/src/bin_evm_proxy/lib_dev/rollup_node.mli +++ b/src/bin_evm_proxy/lib_dev/rollup_node.mli @@ -114,6 +114,9 @@ module type S = sig gas used to execute the call. *) val estimate_gas : Ethereum_types.call -> Ethereum_types.quantity tzresult Lwt.t + + (** [is_tx_valid tx_raw] checks if the transaction is valid. Checks if the nonce is correct. *) + val is_tx_valid : Ethereum_types.hash -> (unit, string) result tzresult Lwt.t end (** Instantiate a module of type {!S} that communicates with a rollup diff --git a/src/bin_evm_proxy/lib_dev/services.ml b/src/bin_evm_proxy/lib_dev/services.ml index 43e8879d7814e6303324da842cdf465b53aeaa67..18c6b911bcabc2870a779e475586ff4be81555cf 100644 --- a/src/bin_evm_proxy/lib_dev/services.ml +++ b/src/bin_evm_proxy/lib_dev/services.ml @@ -142,11 +142,22 @@ let dispatch_input | Get_transaction_by_hash.Input (Some tx_hash) -> let* transaction_object = Rollup_node_rpc.transaction_object tx_hash in return (Get_transaction_by_hash.Output (Ok transaction_object)) - | Send_raw_transaction.Input (Some tx_raw) -> - let* tx_hash = - Rollup_node_rpc.inject_raw_transaction ~smart_rollup_address tx_raw - in - return (Send_raw_transaction.Output (Ok tx_hash)) + | Send_raw_transaction.Input (Some tx_raw) -> ( + let* is_valid = Rollup_node_rpc.is_tx_valid tx_raw in + match is_valid with + | Ok () -> + let* tx_hash = + Rollup_node_rpc.inject_raw_transaction + ~smart_rollup_address + tx_raw + in + return (Send_raw_transaction.Output (Ok tx_hash)) + | Error reason -> + (* TODO: https://gitlab.com/tezos/tezos/-/issues/6229 *) + return + (Send_raw_transaction.Output + (Error {code = -32000; message = reason; data = None})) + (* By default, the current dispatch handles the inputs *)) | Send_transaction.Input _ -> return (Send_transaction.Output (Ok Mockup.transaction_hash)) | Eth_call.Input (Some (call, _)) -> diff --git a/src/bin_evm_proxy/lib_dev/simulation.ml b/src/bin_evm_proxy/lib_dev/simulation.ml index 28e703eb439b59700fee9c68297ecc706cc4f0aa..38bff242fd700b421fbd93a1e96749454999ac0c 100644 --- a/src/bin_evm_proxy/lib_dev/simulation.ml +++ b/src/bin_evm_proxy/lib_dev/simulation.ml @@ -52,6 +52,8 @@ let rlp_encode call = (* we aim to use [String.chunk_bytes] *) Rlp.encode rlp_form +let tx_rlp_encode tx_raw = `Hex tx_raw |> Hex.to_bytes_exn + type simulation_message = | Start | Simple of string @@ -104,6 +106,11 @@ let encode call = let* messages = call |> rlp_encode |> split_in_messages in return @@ List.map encode_message messages +let encode_tx tx = + let open Result_syntax in + let* messages = tx |> tx_rlp_encode |> split_in_messages in + return @@ List.map encode_message messages + module Encodings = struct open Data_encoding @@ -206,22 +213,30 @@ end let parse_insights decode (r : Data_encoding.json) = let s = Data_encoding.Json.destruct Encodings.eval_result r in - match s.insights with - | Some b :: _ -> Lwt.return_ok (decode b) - | _ -> + match decode s.insights with + | Some insight -> Lwt.return_ok insight + | None -> Error_monad.failwith "Couldn't parse insights: %s" (Data_encoding.Json.to_string r) -let call_result = - parse_insights (fun b -> +let decode_call_result bytes = + match bytes with + | Some b :: _ -> let v = b |> Hex.of_bytes |> Hex.show in - Hash v) + Some (Hash v) + | _ -> None + +let call_result json = parse_insights decode_call_result json + +let decode_gas_estimation bytes = + match bytes with + | Some b :: _ -> b |> Bytes.to_string |> Z.of_bits |> Option.some + | _ -> None let gas_estimation json = let open Lwt_result_syntax in - let decode b = b |> Bytes.to_string |> Z.of_bits in - let* simulated_amount = parse_insights decode json in + let* simulated_amount = parse_insights decode_gas_estimation json in (* TODO: https://gitlab.com/tezos/tezos/-/issues/5977 remove this once the gas is accounted correctly *) (* minimum gas for any Ethereum transaction *) @@ -232,3 +247,21 @@ let gas_estimation json = else simulated_amount) in return @@ quantity_of_z @@ Z.max simulated_amount amount + +let decode_is_valid bytes = + match bytes with + | [Some b; error_msg] -> ( + let is_valid = + b |> Data_encoding.Binary.of_bytes_exn Data_encoding.bool + in + let error_msg = error_msg |> Option.map Bytes.to_string in + match (is_valid, error_msg) with + | true, None -> Some (Ok ()) + | false, Some reason -> Some (Error reason) + | _, _ -> None) + | _ -> None + +let is_tx_valid json = + let open Lwt_result_syntax in + let* result = parse_insights decode_is_valid json in + return result diff --git a/src/kernel_evm/CHANGES.md b/src/kernel_evm/CHANGES.md index 77256296ebf4c055edee4ebcdb3c2e179c131cee..bd951ea58f552acdfde1dddcbc333ff856909711 100644 --- a/src/kernel_evm/CHANGES.md +++ b/src/kernel_evm/CHANGES.md @@ -11,6 +11,7 @@ - The kernel can no longer be administrated by a L2 dictator key, instead by a L1 smart contract. It will consider upgrades messages coming from a specific address defined in its storage. (!9927) +- Adds a new type of message in simulation mode, to verify that a transaction is valid by checking if the nonce is neither too low nor too high. (!9679) ### EVM Node @@ -18,6 +19,7 @@ - Add arguments to enable CORS headers. (!9753) - Add an optional `mode` argument to switch from the proxy on production to the one on development. (!9940) +- `eth_sendRawTransaction` checks that the nonce of the transaction is neither too low nor too high. (!9679) ### Bug fixes diff --git a/src/kernel_evm/kernel/src/blueprint.rs b/src/kernel_evm/kernel/src/blueprint.rs index 5b1e8bad4956d82f936791cb5f32118e1b760c00..bd8fe68e168ec54c973113f6644bed86d116fb00 100644 --- a/src/kernel_evm/kernel/src/blueprint.rs +++ b/src/kernel_evm/kernel/src/blueprint.rs @@ -1,12 +1,12 @@ // SPDX-FileCopyrightText: 2022-2023 TriliTech // SPDX-FileCopyrightText: 2023 Nomadic Labs // SPDX-FileCopyrightText: 2023 Functori +// SPDX-FileCopyrightText: 2023 Marigold // // SPDX-License-Identifier: MIT use crate::block_in_progress::BlockInProgress; use crate::inbox::{read_inbox, KernelUpgrade, Transaction, TransactionContent}; -use crate::Error; use primitive_types::U256; use tezos_crypto_rs::hash::ContractKt1Hash; use tezos_smart_rollup_host::runtime::Runtime; @@ -64,7 +64,7 @@ pub fn fetch( chain_id: U256, ticketer: Option, admin: Option, -) -> Result { +) -> Result { let inbox_content = read_inbox(host, smart_rollup_address, ticketer, admin)?; let transactions = filter_invalid_chain_id(inbox_content.transactions, chain_id); let blueprint = QueueElement::Blueprint(Blueprint { transactions }); diff --git a/src/kernel_evm/kernel/src/inbox.rs b/src/kernel_evm/kernel/src/inbox.rs index 6d72c608a44a24f2903798e4283baa195e47014d..aa86e3851f000e37b65998fed68b2db372de11be 100644 --- a/src/kernel_evm/kernel/src/inbox.rs +++ b/src/kernel_evm/kernel/src/inbox.rs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022-2023 TriliTech // SPDX-FileCopyrightText: 2023 Nomadic Labs // SPDX-FileCopyrightText: 2023 Functori +// SPDX-FileCopyrightText: 2023 Marigold // // SPDX-License-Identifier: MIT @@ -274,7 +275,7 @@ pub fn read_inbox( smart_rollup_address: [u8; 20], ticketer: Option, admin: Option, -) -> Result { +) -> Result { let mut res = InboxContent { kernel_upgrade: None, transactions: vec![], diff --git a/src/kernel_evm/kernel/src/lib.rs b/src/kernel_evm/kernel/src/lib.rs index 9df36f9461a350ccf778a0bb374e5b8839cb108b..6bd9793e3a4e5ce98d62f45a813615a033783ed4 100644 --- a/src/kernel_evm/kernel/src/lib.rs +++ b/src/kernel_evm/kernel/src/lib.rs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2023 Nomadic Labs // SPDX-FileCopyrightText: 2023 TriliTech // SPDX-FileCopyrightText: 2023 Functori +// SPDX-FileCopyrightText: 2023 Marigold // // SPDX-License-Identifier: MIT @@ -82,7 +83,7 @@ pub fn stage_one( chain_id: U256, ticketer: Option, admin: Option, -) -> Result { +) -> Result { log!(host, Info, "Entering stage one."); log!( host, diff --git a/src/kernel_evm/kernel/src/simulation.rs b/src/kernel_evm/kernel/src/simulation.rs index 6dae4511d0b9b27d9e43625ab8db755a94c59abe..63a981a931f425066aae2b7c5b9e73131a9a3686 100644 --- a/src/kernel_evm/kernel/src/simulation.rs +++ b/src/kernel_evm/kernel/src/simulation.rs @@ -16,6 +16,7 @@ use primitive_types::{H160, U256}; use rlp::{Decodable, DecoderError, Rlp}; use tezos_ethereum::block::BlockConstants; use tezos_ethereum::rlp_helpers::{decode_field, decode_option, next}; +use tezos_ethereum::tx_common::EthereumTransactionCommon; use tezos_evm_logging::{log, Level::*}; use tezos_smart_rollup_host::runtime::Runtime; @@ -25,15 +26,15 @@ pub const SIMULATION_SIMPLE_TAG: u8 = 1; pub const SIMULATION_CREATE_TAG: u8 = 2; // SIMULATION/CHUNK/NUM 2B/CHUNK pub const SIMULATION_CHUNK_TAG: u8 = 3; -/// Maximum gas used by the simulation. Bounded to limit DOS on the rollup node +/// Maximum gas used by the evaluation. Bounded to limit DOS on the rollup node /// Is used as default value if no gas is set. -pub const MAX_SIMULATION_GAS: u64 = 1_000_000_000u64; +pub const MAX_EVALUATION_GAS: u64 = 1_000_000_000u64; /// Container for eth_call data, used in messages sent by the rollup node /// simulation. /// /// They are transmitted in RLP encoded form, in messages of the form\ -/// `\parsing::SIMULATION_TAG \SIMULATION_SIMPLE_TAG \`\ +/// `\parsing::SIMULATION_TAG \SIMULATION_SIMPLE_TAG \`\ /// or in chunks if they are bigger than what the inbox can receive, with a /// first message giving the number of chunks\ /// `\parsing::SIMULATION_TAG \SIMULATION_CREATE_TAG \XXXX` @@ -41,11 +42,11 @@ pub const MAX_SIMULATION_GAS: u64 = 1_000_000_000u64; /// chunks:\ /// `\parsing::SIMULATION_TAG \SIMULATION_CHUNK_TAG \XXXX \`\ /// where `XXXX` is the number of the chunk over 2 bytes, and the rest is a -/// chunk of the rlp encoded simulation. +/// chunk of the rlp encoded evaluation. /// /// Ethereum doc: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call #[derive(Debug, PartialEq, Eq, Clone)] -pub struct Simulation { +pub struct Evaluation { /// (optional) The address the transaction is sent from.\ /// Encoding: 20 bytes or empty (0x80) pub from: Option, @@ -68,14 +69,14 @@ pub struct Simulation { pub data: Vec, } -impl Simulation { +impl Evaluation { /// Unserialize bytes as RLP encoded data. - pub fn from_rlp_bytes(bytes: &[u8]) -> Result { + pub fn from_rlp_bytes(bytes: &[u8]) -> Result { let decoder = Rlp::new(bytes); - Simulation::decode(&decoder) + Evaluation::decode(&decoder) } - /// Execute the simulation + /// Execute the evaluation pub fn run(&self, host: &mut Host) -> Result { let timestamp = current_timestamp(host); let timestamp = U256::from(timestamp.as_u64()); @@ -94,8 +95,8 @@ impl Simulation { self.from.unwrap_or(default_caller), self.data.clone(), self.gas - .map(|gas| u64::max(gas, MAX_SIMULATION_GAS)) - .or(Some(MAX_SIMULATION_GAS)), // gas could be omitted + .map(|gas| u64::max(gas, MAX_EVALUATION_GAS)) + .or(Some(MAX_EVALUATION_GAS)), // gas could be omitted self.value, ) .map_err(Error::Simulation)?; @@ -103,7 +104,7 @@ impl Simulation { } } -impl Decodable for Simulation { +impl Decodable for Evaluation { fn decode(decoder: &Rlp<'_>) -> Result { // the proxynode works preferably with little endian let u64_from_le = |v: Vec| u64::from_le_bytes(parsable!(v.try_into().ok())); @@ -137,7 +138,7 @@ impl Decodable for Simulation { } } -impl TryFrom<&[u8]> for Simulation { +impl TryFrom<&[u8]> for Evaluation { type Error = DecoderError; fn try_from(bytes: &[u8]) -> Result { @@ -145,13 +146,86 @@ impl TryFrom<&[u8]> for Simulation { } } +#[derive(Debug, PartialEq)] +struct TxValidation { + transaction: EthereumTransactionCommon, +} + +enum TxValidationOutcome { + Valid, + NonceTooLow, + NonceTooHigh, + NotCorrectSignature, +} + +impl TxValidation { + /// Execute the simulation + pub fn run( + &self, + host: &mut Host, + ) -> Result { + let tx = &self.transaction; + let evm_account_storage = account_storage::init_account_storage()?; + // Get the caller + let Ok(caller) = tx.caller() else {return Ok(TxValidationOutcome::NotCorrectSignature)}; + // Get the caller account + let caller_account_path = evm_execution::account_storage::account_path(&caller)?; + let caller_account = evm_account_storage.get(host, &caller_account_path)?; + // Get the nonce of the caller + let caller_nonce = match &caller_account { + Some(account) => account.nonce(host)?, + None => U256::zero(), + }; + // Check if nonce is too low + if tx.nonce < caller_nonce { + return Ok(TxValidationOutcome::NonceTooLow); + } + // Check if the nonce is too high + if tx.nonce > caller_nonce { + return Ok(TxValidationOutcome::NonceTooHigh); + } + Ok(TxValidationOutcome::Valid) + } +} + +impl TryFrom<&[u8]> for TxValidation { + type Error = DecoderError; + + fn try_from(bytes: &[u8]) -> Result { + let transaction = EthereumTransactionCommon::from_bytes(bytes)?; + Ok(Self { transaction }) + } +} + +#[derive(Debug, PartialEq)] +enum Message { + Evaluation(Evaluation), + TxValidation(TxValidation), +} + +impl TryFrom<&[u8]> for Message { + type Error = DecoderError; + + fn try_from(bytes: &[u8]) -> Result { + if let Ok(simulation) = Evaluation::try_from(bytes) { + return Ok(Message::Evaluation(simulation)); + } + + if let Ok(tx_validation) = TxValidation::try_from(bytes) { + return Ok(Message::TxValidation(tx_validation)); + } + + Err(DecoderError::Custom("Unknown message to simulate")) + } +} + #[derive(Default, Debug, PartialEq)] enum Input { #[default] Unparsable, - SimpleSimulation(Simulation), - NewChunkedSimulation(u16), - SimulationChunk { + Simple(Box), + NewChunked(u16), + Chunk { i: u16, data: Vec, }, @@ -160,19 +234,20 @@ enum Input { impl Input { fn parse_new_chunk_simulation(bytes: &[u8]) -> Self { let num_chunks = u16::from_le_bytes(parsable!(bytes.try_into().ok())); - Self::NewChunkedSimulation(num_chunks) + Self::NewChunked(num_chunks) } fn parse_simulation_chunk(bytes: &[u8]) -> Self { let (num, remaining) = parsable!(parsing::split_at(bytes, 2)); let i = u16::from_le_bytes(num.try_into().unwrap()); - Self::SimulationChunk { + Self::Chunk { i, data: remaining.to_vec(), } } fn parse_simple_simulation(bytes: &[u8]) -> Self { - Input::SimpleSimulation(parsable!(bytes.try_into().ok())) + let message = parsable!(bytes.try_into().ok()); + Input::Simple(Box::new(message)) } // Internal custom message structure : @@ -199,11 +274,11 @@ impl Input { fn read_chunks( host: &mut Host, num_chunks: u16, -) -> Result { +) -> Result { let mut buffer: Vec = Vec::new(); for n in 0..num_chunks { match read_input(host)? { - Input::SimulationChunk { i, data } => { + Input::Chunk { i, data } => { if i != n { return Err(Error::InvalidConversion); } else { @@ -223,12 +298,12 @@ fn read_input(host: &mut Host) -> Result { } } -fn parse_inbox(host: &mut Host) -> Result { +fn parse_inbox(host: &mut Host) -> Result { // we just received simulation tag // next message is either a simulation or the nb of chunks needed match read_input(host)? { - Input::SimpleSimulation(s) => Ok(s), - Input::NewChunkedSimulation(num_chunks) => { + Input::Simple(s) => Ok(*s), + Input::NewChunked(num_chunks) => { // loop to find the chunks read_chunks(host, num_chunks) } @@ -236,29 +311,70 @@ fn parse_inbox(host: &mut Host) -> Result { } } -pub fn start_simulation_mode(host: &mut Host) -> Result<(), Error> { - log!(host, Debug, "Starting simulation mode "); - let simulation = parse_inbox(host)?; - let outcome = simulation.run(host)?; +fn store_simulation_outcome( + host: &mut Host, + outcome: ExecutionOutcome, +) -> Result<(), anyhow::Error> { log!(host, Debug, "outcome={:?} ", outcome); storage::store_simulation_status(host, outcome.is_success)?; - storage::store_simulation_gas(host, outcome.gas_used)?; + storage::store_evaluation_gas(host, outcome.gas_used)?; storage::store_simulation_result(host, outcome.result) } +fn store_tx_validation_outcome( + host: &mut Host, + outcome: TxValidationOutcome, +) -> Result<(), anyhow::Error> { + match outcome { + TxValidationOutcome::Valid => storage::store_simulation_status(host, true), + TxValidationOutcome::NonceTooLow => { + storage::store_simulation_status(host, false)?; + storage::store_simulation_result(host, Some(b"Nonce too low.".to_vec())) + } + TxValidationOutcome::NonceTooHigh => { + storage::store_simulation_status(host, false)?; + storage::store_simulation_result(host, Some(b"Nonce too high.".to_vec())) + } + TxValidationOutcome::NotCorrectSignature => { + storage::store_simulation_status(host, false)?; + storage::store_simulation_result(host, Some(b"Incorrect signature.".to_vec())) + } + } +} + +pub fn start_simulation_mode( + host: &mut Host, +) -> Result<(), anyhow::Error> { + log!(host, Debug, "Starting simulation mode "); + let simulation = parse_inbox(host)?; + match simulation { + Message::Evaluation(simulation) => { + let outcome = simulation.run(host)?; + store_simulation_outcome(host, outcome) + } + Message::TxValidation(tx_validation) => { + let outcome = tx_validation.run(host)?; + store_tx_validation_outcome(host, outcome) + } + } +} + #[cfg(test)] mod tests { - use tezos_ethereum::block::BlockConstants; + use primitive_types::H256; + use tezos_ethereum::{ + block::BlockConstants, transaction::TransactionType, tx_signature::TxSignature, + }; use tezos_smart_rollup_mock::MockHost; use crate::current_timestamp; use super::*; - impl Simulation { + impl Evaluation { /// Unserialize an hex string as RLP encoded data. - pub fn from_rlp(e: String) -> Result { + pub fn from_rlp(e: String) -> Result { let tx = hex::decode(e) .or(Err(DecoderError::Custom("Couldn't parse hex value")))?; Self::from_rlp_bytes(&tx) @@ -275,7 +391,7 @@ mod tests { let input_string = "da8094353535353535353535353535353535353535353580808080".to_string(); let address = address_of_str("3535353535353535353535353535353535353535"); - let expected = Simulation { + let expected = Evaluation { from: None, to: address, gas: None, @@ -284,12 +400,12 @@ mod tests { data: vec![], }; - let simulation = Simulation::from_rlp(input_string); + let evaluation = Evaluation::from_rlp(input_string); - assert!(simulation.is_ok(), "Simulation input should be decodable"); + assert!(evaluation.is_ok(), "Simulation input should be decodable"); assert_eq!( expected, - simulation.unwrap(), + evaluation.unwrap(), "The decoded result is not the one expected" ); } @@ -301,7 +417,7 @@ mod tests { let to = address_of_str("3535353535353535353535353535353535353535"); let from = address_of_str("2424242424242424242424242424242424242424"); let data = hex::decode("1616").unwrap(); - let expected = Simulation { + let expected = Evaluation { from, to, gas: Some(11111), @@ -310,12 +426,12 @@ mod tests { data, }; - let simulation = Simulation::from_rlp(input_string); + let evaluation = Evaluation::from_rlp(input_string); - assert!(simulation.is_ok(), "Simulation input should be decodable"); + assert!(evaluation.is_ok(), "Simulation input should be decodable"); assert_eq!( expected, - simulation.unwrap(), + evaluation.unwrap(), "The decoded result is not the one expected" ); } @@ -366,8 +482,8 @@ mod tests { let mut host = MockHost::default(); let new_address = create_contract(&mut host); - // run simulation num - let simulation = Simulation { + // run evaluation num + let evaluation = Evaluation { from: None, gas_price: None, to: Some(new_address), @@ -375,9 +491,9 @@ mod tests { gas: Some(10000), value: None, }; - let outcome = simulation.run(&mut host); + let outcome = evaluation.run(&mut host); - assert!(outcome.is_ok(), "simulation should have succeeded"); + assert!(outcome.is_ok(), "evaluation should have succeeded"); let outcome = outcome.unwrap(); assert_eq!( Some(vec![0u8; 32]), @@ -386,7 +502,7 @@ mod tests { ); // run simulation get - let simulation = Simulation { + let evaluation = Evaluation { from: None, gas_price: None, to: Some(new_address), @@ -394,25 +510,25 @@ mod tests { gas: Some(10000), value: None, }; - let outcome = simulation.run(&mut host); + let outcome = evaluation.run(&mut host); assert!(outcome.is_ok(), "simulation should have succeeded"); let outcome = outcome.unwrap(); assert_eq!( Some(vec![0u8; 32]), outcome.result, - "simulation result should be 0" + "evaluation result should be 0" ); } #[test] - fn simulation_result_no_gas() { + fn evaluation_result_no_gas() { // setup let mut host = MockHost::default(); let new_address = create_contract(&mut host); - // run simulation num - let simulation = Simulation { + // run evaluation num + let evaluation = Evaluation { from: None, gas_price: None, to: Some(new_address), @@ -420,14 +536,14 @@ mod tests { gas: None, value: None, }; - let outcome = simulation.run(&mut host); + let outcome = evaluation.run(&mut host); - assert!(outcome.is_ok(), "simulation should have succeeded"); + assert!(outcome.is_ok(), "evaluation should have succeeded"); let outcome = outcome.unwrap(); assert_eq!( Some(vec![0u8; 32]), outcome.result, - "simulation result should be 0" + "evaluation result should be 0" ); } @@ -436,7 +552,7 @@ mod tests { let to = address_of_str("3535353535353535353535353535353535353535"); let from = address_of_str("2424242424242424242424242424242424242424"); let data = hex::decode("1616").unwrap(); - let expected = Simulation { + let expected = Evaluation { from, to, gas: Some(11111), @@ -453,7 +569,7 @@ mod tests { let parsed = Input::parse(&input); assert_eq!( - Input::SimpleSimulation(expected), + Input::Simple(Box::new(Message::Evaluation(expected))), parsed, "should have been parsed as complete simulation" ); @@ -468,7 +584,7 @@ mod tests { let to = Some(new_address); let data = hex::decode(STORAGE_CONTRACT_CALL_GET).unwrap(); let gas = Some(11111); - let expected = Simulation { + let expected = Evaluation { from: None, to, gas, @@ -484,17 +600,18 @@ mod tests { let parsed = Input::parse(&encoded); assert_eq!( - Input::SimpleSimulation(expected), + Input::Simple(Box::new(Message::Evaluation(expected))), parsed, "should have been parsed as complete simulation" ); - if let Input::SimpleSimulation(s) = parsed { - let res = s.run(&mut host).expect("simulation should run"); - assert!(res.is_success, "simulation should have succeeded"); - } else { - panic!("Parsing failed") + if let Input::Simple(box_simple) = parsed { + if let Message::Evaluation(s) = *box_simple { + let res = s.run(&mut host).expect("simulation should run"); + return assert!(res.is_success, "simulation should have succeeded"); + } } + panic!("Parsing failed") } #[test] @@ -506,7 +623,7 @@ mod tests { let parsed = Input::parse(&input); assert_eq!( - Input::NewChunkedSimulation(42), + Input::NewChunked(42), parsed, "should have parsed start of chunked simulation" ); @@ -519,7 +636,7 @@ mod tests { input.extend(i.to_le_bytes()); input.extend(hex::decode("aaaaaa").unwrap()); - let expected = Input::SimulationChunk { + let expected = Input::Chunk { i: 20, data: vec![170u8; 3], }; @@ -528,4 +645,61 @@ mod tests { assert_eq!(expected, parsed, "should have parsed a chunk"); } + + #[test] + fn parse_tx_validation() { + let expected = { + let v = 2710.into(); + + let r = H256::from_slice( + &hex::decode( + "0c4604516693aafd2e74a993c280455fcad144a414f5aa580d96f3c51d4428e5", + ) + .unwrap(), + ); + + let s = H256::from_slice( + &hex::decode( + "630fb7fc1af4c1c1a82cabb4ef9d12f8fc2e54a047eb3e3bdffc9d23cd07a94e", + ) + .unwrap(), + ); + + let signature = TxSignature::new(v, r, s).unwrap(); + + EthereumTransactionCommon { + type_: TransactionType::Legacy, + chain_id: 1337.into(), + nonce: 0.into(), + max_priority_fee_per_gas: U256::default(), + max_fee_per_gas: U256::default(), + gas_limit: 2000000, + to: Some(H160::default()), + value: U256::default(), + data: vec![], + signature: Some(signature), + access_list: Vec::default(), + } + }; + + let hex = "f8628080831e84809400000000000000000000000000000000000000008080820a96a00c4604516693aafd2e74a993c280455fcad144a414f5aa580d96f3c51d4428e5a0630fb7fc1af4c1c1a82cabb4ef9d12f8fc2e54a047eb3e3bdffc9d23cd07a94e"; + let data = hex::decode(hex).unwrap(); + let tx = EthereumTransactionCommon::from_bytes(&data).unwrap(); + + assert_eq!(tx, expected); + + let mut encoded = hex::decode(hex).unwrap(); + let mut input = vec![parsing::SIMULATION_TAG, SIMULATION_SIMPLE_TAG]; + input.append(&mut encoded); + + let parsed = Input::parse(&input); + + assert_eq!( + Input::Simple(Box::new(Message::TxValidation(TxValidation { + transaction: expected + }))), + parsed, + "should have been parsed as complete tx validation" + ); + } } diff --git a/src/kernel_evm/kernel/src/storage.rs b/src/kernel_evm/kernel/src/storage.rs index 38b1d2a51d2fe77daec5b9a682ab909faf032969..525c81101904a4c26c8af80130e3ed73e4675df5 100644 --- a/src/kernel_evm/kernel/src/storage.rs +++ b/src/kernel_evm/kernel/src/storage.rs @@ -1,5 +1,6 @@ // SPDX-FileCopyrightText: 2023 Nomadic Labs // SPDX-FileCopyrightText: 2023 Functori +// SPDX-FileCopyrightText: 2023 Marigold // // SPDX-License-Identifier: MIT #![allow(dead_code)] @@ -286,15 +287,14 @@ pub fn store_current_block( pub fn store_simulation_result( host: &mut Host, result: Option>, -) -> Result<(), Error> { +) -> Result<(), anyhow::Error> { if let Some(result) = result { - host.store_write(&SIMULATION_RESULT, &result, 0) - .map_err(Error::from)?; + host.store_write(&SIMULATION_RESULT, &result, 0)? } Ok(()) } -pub fn store_simulation_gas( +pub fn store_evaluation_gas( host: &mut Host, result: u64, ) -> Result<(), Error> { @@ -304,9 +304,9 @@ pub fn store_simulation_gas( pub fn store_simulation_status( host: &mut Host, result: bool, -) -> Result<(), Error> { +) -> Result<(), anyhow::Error> { host.store_write(&SIMULATION_STATUS, &[result.into()], 0) - .map_err(Error::from) + .context("Failed to write the simulation status.") } pub fn store_transaction_receipt( diff --git a/tezt/lib_tezos/evm_proxy_server.ml b/tezt/lib_tezos/evm_proxy_server.ml index 283d34dd1049e7468689d18b5a4bf76834a9daeb..8fba31e3a53d83c1d73f4cdf59ee3831c74215b1 100644 --- a/tezt/lib_tezos/evm_proxy_server.ml +++ b/tezt/lib_tezos/evm_proxy_server.ml @@ -3,6 +3,7 @@ (* Open Source License *) (* Copyright (c) 2023 Nomadic Labs *) (* Copyright (c) 2023 Functori *) +(* Copyright (c) 2023 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -191,6 +192,8 @@ let batch_evm_rpc proxy_server requests = let extract_result json = JSON.(json |-> "result") +let extract_error_message json = JSON.(json |-> "error" |-> "message") + let fetch_contract_code evm_proxy_server contract_address = let* code = call_evm_rpc diff --git a/tezt/lib_tezos/evm_proxy_server.mli b/tezt/lib_tezos/evm_proxy_server.mli index b762bcc0bbe25b63ed328514a112e103fb6f3264..77d872d32f56db6b83196ed7055e9c3c34a4f14c 100644 --- a/tezt/lib_tezos/evm_proxy_server.mli +++ b/tezt/lib_tezos/evm_proxy_server.mli @@ -3,6 +3,7 @@ (* Open Source License *) (* Copyright (c) 2023 Nomadic Labs *) (* Copyright (c) 2023 Functori *) +(* Copyright (c) 2023 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -92,6 +93,9 @@ val batch_evm_rpc : t -> request list -> JSON.t Lwt.t (** [extract_result json] expects a JSON-RPC `result` and returns the value. *) val extract_result : JSON.t -> JSON.t +(** [extract_error_message json] expects a JSON-RPC `error.message` and returns the value. *) +val extract_error_message : JSON.t -> JSON.t + (** [fetch_contract_code proxy_server contract] returns the code associated to the given contract in the rollup. *) val fetch_contract_code : t -> string -> string Lwt.t diff --git a/tezt/tests/evm_kernel_inputs/100-inputs-for-proxy b/tezt/tests/evm_kernel_inputs/100-inputs-for-proxy index 340bbb76afca833e7118eca3a217058b1bccde62..f59c6be09ec16380ac3f15dfea2e4490745e25ec 100644 --- a/tezt/tests/evm_kernel_inputs/100-inputs-for-proxy +++ b/tezt/tests/evm_kernel_inputs/100-inputs-for-proxy @@ -1,100 +1,100 @@ -f86b8082520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0ec7f444df0d5855c758e0d0153ea7b23112984f221c44dd07a6a86d9fe0621d7a040c67f3586577f8114b7b58dea6377e034f80929c796e566a516b0b6ba6432e1 0x55c08baecbde8b397c01761b2adbb5b4529072901d1de1f86f58cfdd52fc5d9b -f86b0182520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0fe06e5226852eb7bb0911d39b9b2a650f37e792162c7c8270bafb8e12c118e7ea00e58fd7951b3877c0c8392cd6ff13dd900edd507bd93a3eada83826ac290069e 0xb62608908aaad0e2f755d34ab79426c12329e88570a0a0fad526203e24eaa132 -f86b0282520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0152067ed3c7b0c9ffd70b44291752ef19b1bcb752b265a160df33914a3cd1edaa06e662d253cbe44182bf67c50eed856db0efff8f280fd57949423f8cfc4244351 0xa5437845b1bef461b7d1de7c3cb417de4a195c2dcfccb95ff0cf4c11ac1ba56b -f86b0382520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0d18bd705831cc8898cff4c73e340fb6a5ce0a7a6fde4681e400905b6d1970c46a03c500dcfbdc679281dd268b485be97dec437269a3ab9bf3892125a917893e53a 0xba936ec6aa1fdbae97e1bc27f537623609f34f7238b95bf58a4ca96c4e1f1525 -f86b0482520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a087bcf40aa650c5a6290871286d0440c3e92570e9404219b9a2aaa2bf1f6721c9a06b7f88ef05c8fe65183bdbeeb5203aee9c5a15b40fa9714f7630284ef3602c7d 0xf433fce36612b73c6e2f894d4bd37b05fb86893b0b3248c2d90cbaf879e59c6c -f86b0582520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a018575f18a8c003c868fb28cd2e5de9a915adb8e2178596dc211669f6aea75f21a02dd5af9d6cb97f37d2ee0153b8e6e5b96804c45524f71e22b836f763290da670 0x28dfeeed32d21a51559580fce3c371900cdeb2cd442021754a8d47dede053e26 -f86b0682520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a075e41eadf03756e790b3b66b5db633229c75d9b77bbdc04946b9772aef54b301a06ff56dde9c64fa1524e4d6a05ba5477087b1b47b09cf0129379e197beedafcd8 0x0245cee1ab257282285b4ca90244349a575549b5949a1b227e7a7e36c6fa4829 -f86b0782520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0a0d051b7619a923c1791c9d371c96441105ec319461a37db43df6cd1d8fd5024a02cc68f8625e52873035cc37fd1079e0b5034cd9bf7ed6c987aa242e75c1c5f42 0x3a63f756dc8f7d9138b2d8999c69cdbe5d08f87fc2a0e840fd8bdae61cd5c4cd -f86b0882520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0100c436c4ef9f27a9b67f227cd1d7e132a64c949a626a1d685298b289929dd34a02bc2b227f5aa6b94696b5b1d027d2f693eb9951ff8d109d76534925409284280 0x67a9bc6026eb27f699e55136814ea250d7ec7a3e3a1d7ae38e0f7a60ef8b67d6 -f86b0982520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a08607f4fe0f8a8907d537ce8217b3dbafa550320693924a9a3aa5ff62a5666d0fa0173bac7a529e59829485e9988c826fdfbfe4ccfa0d970fd0f6ba2aece8891549 0xb556bca8c3430101f0287d1d073a8eae19c2d08b2bbc8d4177a9232eb4a28f82 -f86b0a82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a05a40a8b0c5cc42da9eb20b946a68214e98b1687bf97727ddf2564654c393ef18a036791ca34d323d8640f83d47f40f6e52cfc5578eaf396a86596a4648b75b91ab 0xf187384c0a63157c5eea11e37ba5f5b8f3015f8449f38d3dfb8de2c0e989a76f -f86b0b82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0a05dec1cbc56fe726302bc7f93a2002b26ec2e638cc94b9dcb833cb06921af77a01782683be6139f995fd1507530d14f691b1fb59cc5a06fe83e5a478e10a6b443 0x8ea988febe08264c4463652583c6145c1ab91e528063e21f18d2bbec5b0f75e5 -f86b0c82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a062101dbb80041535760e19dd782b71b75301d30e02d92e18884a7103e8e43e35a0079d01271dd91c9a63d603a1226259b55798a5af4ac05e833de3fa4dc57e48c6 0xbb13f2f463b3505a5a1d51a51ae3edae3e3448f212533dae3921b37b7898223e -f86b0d82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a014a4b6875abb9d289eb2f288a1117c551e291630fee6f361bcf52a0550ec1c2da07589c9e90021e815ab5c4cbe576cb098129b4dd40f98f1629e4b290321b6980b 0x4ae8f789081c30a687fa2c310e81b117386e2a990846103d7196f2a0e618ec92 -f86b0e82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a026531bd3931f67cbff8cf49eaaca9dd613b5caf1dae611491f7be090d941406ca00688ae0873367125d2bb16f273725612fbc1cb1f59354ea39651edb733d9f19b 0x4ba2375a1373fb83bf9f5801ab158eadbac49493c0875a6ae51b47ce189850e5 -f86b0f82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0e166f1ed7e90561d2327102bf965a2bd922ba0c7efb224b446f709bb0337a403a07b8ba6189730a009bd65feaa8157c06b79f1e222c8ecf393f6318b2f232e249e 0x84320bc68976d3ddd69b6eeddeaa52bd3efe00ed0e27ff92a5ff839fcb53d0a2 -f86b1082520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a06361ac2f4001e94413a767edb2a1ffe077ce33a345d10305fb0d50f2cda5848ca07f996609671aeb08f330579f63309ae3ffa6c69d21cd8a83c37bc56387ebd272 0x3504f226a83827af014320cb3e4a9b7651ac9c695e64ca27deac3ea12b61e8db -f86b1182520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0175c299b4d9f129d8d56070d479af98be5dda915ab3e9c911ec9b963d605dffea0672a242dd9edf44832c7268c92c7962c13dcb12d74dfc004ddf080b0719a2aee 0x0d58b325c01da9f77169f554483cf6baab70a4bcabe04f62d457b9b603cd246b -f86b1282520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0d76bd607b7e8860b453e2811874a8c938a650ee381a8e65b4dca76a2680d8f46a0242e7aca2be6fb7708c34922b7b9a4ff5c9e36c02de2ae306e41e8838a6955a0 0x51dfa19b5b7d14174052afa20da708bf7ec0149d3ae0290975a16858e4de8608 -f86b1382520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0169c6b753d664cd850f2d6dc3ed76701e508f995271f81269c35eff4f8d53deba017af93ba0f866696710e9f1ff8c930108bedd332aa460c8da680d514b4114c33 0x86b25ce7f18fd6164d65e7164ca542a0edc0bbb986a0231223b367d0bfddd5f1 -f86b1482520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a09c858bc1d7e9f0d43f40363a22aa2fbd5915fba7d11bfeb4dea592ad417617c1a029eef3a83a6b8ef52cff101ff0aaf8ef3c5ed92f8ad23dd1bd544a55bafc31a3 0x29d1447a09aadcbd27c99c33229b177d376548f1ddeefcf55d086702d6c34136 -f86b1582520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0f537df344f0ef2f36bd28ed4bf4d55c5e373da19a5deafd776642b2a258222c7a0189f255279a3ed76eed3ee75ab1570d8248c74d7d9066326eb3af3bf2eeeabec 0x9531685b6d810d92b468faf96fa7a2f4997c79833cc4df584e7b7086cff4409a -f86b1682520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0dfbe42c0c535a08e4d48974b6b0b358a807fc0ba652302e19dfa93709b3ba9b9a043307e9f0242b99ad7f95dac6f30e29a99de5aec885c3ef8c27a300c5e779cab 0x37d8011855ac0a23ed3c38cc7c7875ecb5b17621175474e0594365900ed09d94 -f86b1782520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a07cc0377d647977e7d6956371619f5b9c9a163431535357de4fe97287c540c9bca00c9bc430b9c4b2d53a57b83830ea7af28f8053c8587da33c831bbf3f51597b1a 0xe53329d144bac68256a873f24467cb7567cabfcbc30fd9ffe27802c3288f1025 -f86b1882520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0bae45cc7822ce942b4e77c758ced006c0ff0cb85128e02ec1cf4b2ffcd6bb546a059ff1717169a0a4e44e1b86b62458600b4226b65f5595ae00872923900ff1bed 0xbdfd50e57e9df74b8c478d16315518c4d7f5099dbcacd57d127314e66d47c05f -f86b1982520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0cdcd793a77059c4613bba2530884e7a1ea3624e1b14fea4743d2da94a4ba9996a00b62dee6ba54dfbe6878b73f4477619920c1d1c714d052c4e494d84b8b26629c 0xfeba2119d173c8c39c78cafb16e1336876db556bcef5f732d3afb48c1f745b37 -f86b1a82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0eb2b0ab20825c3b7dc9132bee6e8610677f2f461a0ba88f61e6b9e11834a4eb5a02505bc99fca4b5b9e167ca7d1c234d05b72c033e2400956ac7387ad0f37250ff 0x4a6e7f4e383291aec67f38d8037028e9b5000caa195d97a33911a1785300fd15 -f86b1b82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0cdd23e4f9e10a80efe29500229f5540404fb6c0d696398bb3d4ab4473108c0bea07bc8198de3f2d2ed44d4ec43e6297323bfc3f6232ea377fe019642ea3e0ccedf 0x870da6bdcff608be9828cf4e8853536db7415cb41455899cb368030ebcffbf14 -f86b1c82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0922b89718790b44d8e5905dce5682535a76ff5427a2f8ae1c7c5b1bb29386e37a00678ebac392ad8f5f64320e267ef63a193487687b9a2ae043d5c5edc7dff716d 0xf6bc3ce4f2b2e49ab7f3099ef32d59ffc92b3a65bfe4b7a603fa336a04d7f5d7 -f86b1d82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a031d78be1c62c058a480ed9bb0545b059114fe892dcd1f9d5fefa1a2ec547eb46a02d70c09b59640981dc11f5dd37a01df4d18d7183895b1a57bacd1c27d5d1e514 0x8b31ae8761d8b8e9f0dc7f5285a3f13bb652a5e81d27d5f5c58845b6a513122f -f86b1e82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a09010107f7d37acb98e566fb9fd4652131af54527114fa8623b1cd346024ca29ca02e99fdbf55c0984586fc218ccb9fda254cc954eb0534cd33177cd605f0bbbc33 0x24132d29bffbbbe340e29b4fc59a813cf4988d37952fb2719c2f9a439b3b5ac7 -f86b1f82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a048f8cf94a872526d4bee117c4eeb3be92f717e823d3961bbc920149fbf716574a06618f15ed86fa70e89fccb7c8759a8f1d1ad9357fa32ab998df4d526b41cebd7 0x04ab01d7730618103ba7ea375647d0fa99f80428308fc45f2e3496dd95afef88 -f86b2082520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a098f66c489f5cbbc9f8cb949d286b3c4c9f068b4951f61694b274830dd8640f70a066ad4ff7a23d5c2ab8d6d3de17c1f853d3655f9f7ae63aa4e0f56093d6221ecd 0xfa157beeb41c206b5cdeca6ed792381cb2aee7ea32f122d83759423e06b4219c -f86b2182520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0597b070c762626349f1477f6a5c3dff15cf66da9a5cfb02c7876bff6fa46478ea03e1071269de7b9a2f90898fa1746ecac0d105510cc27bf35fe62d109a8382c88 0xcb783a904df622e82252acf6621c30e628388a136d5b1060a448b8b88f476c4b -f86b2282520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a02e8dfe592e3eb52dab21e55942644ec48dd8a1433c151ac72ca388eee56694cba0583bf8d7c136e405a5e9966d8db96716a0273039666a446844e1eb51019cb2ee 0xb549a28ad68feba8adc864adb11eeda37db4a934bffa95ab2a583c010cc289fa -f86b2382520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a051583d5b9c211034fd0475dc27fdf1b6aeefe0b060c903e038dc18cc26c6dd8ea025ae4db4cd3c932a311b31e812a76fd208ebb9f2d268098e9b1b1700a8ef8e77 0x7e789b2eb6d9b0f04591c3da0275c999d233d76e48a3eb1a5160b9548e517175 -f86b2482520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a07b21ffe1f8cb52fc096647cce8e4bbb689e8bf7c75885a4ed371089438eab1fba01ef513b5a2b2b6a4bca88815757c85a48b212d62c49f299604553228315498f4 0x1a3bcf6073824a6ac9b9dfc7788faecec4bffe55285e873c5823476f71c36c38 -f86b2582520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a068c7e08ef7504a90426376ffccfa24b7462e81a4362414b3e205b4a4420aab86a03758192fd43617c7e245ac1f9598a2e7acecbec723f07b1238285f13c462ee8d 0x6c23ce3a97ed83bbc2ef4d2f1a40ca3d75d456652f85c9d437e3f263c94c1de2 -f86b2682520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a03f376563389ef3ffc122518b07c0db685bab520660c065799b10c0c0d617f6aca039e12444ec179d6eac094e9f697f450ac230e48cef60290c27f41425da5b8f0b 0x756e1a02cf7f186d33c44f110d80143897528c8621c545b90a4174b1ee1a4a1a -f86b2782520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a011a3bf8e4f364e532870c636248053f1e3b509db5fd2f561d8dc4c9945e62cbfa05d11f68c987a8b191c4df34c15228bea0385a0b28a640a0b659f032a6681f560 0xfb6db12c698dec2951835f08d8886167293c8f49011c236d1b7142d981935127 -f86b2882520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a09c2e1a88ff79ff1801cb29246e9667581ffdc0a357d287a0432c71b392c7002aa04a6d64395275aa1f715385d9690765d92e02abebe99bb8b9689c35dd1879c2e0 0x00423a6a6106e82a99e503fc1bf771add9c526bdd659d82844064e4613f159f1 -f86b2982520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0e6531b4a853d75a3a9b5c0c94d310ddd51ce20fbe87e833429d9c17521c6ffc4a030e18288471a51bcb28e0d114ba8bee9a4ddf195fdc60698b2819b0d9d29cc8e 0xdd6c39acaf6fe5b95589eb8b3aaf2234ef95fbceb2b1015d56874addc4ef7db5 -f86b2a82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a05bac2463d61627e22668bd75939becff530de057a8ca63ac25d00c6634ad4b3ca043ee7811d66c160002cd3de031d9984d36a553ba25ed977ffc4a582f125f295b 0x1e0c0475fc3f2d6807ce7d1fa617a1093fedaf76af93c2c34e386909c80774f4 -f86b2b82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0ce5afbc238fe3782457d8e66aac58dc5feb3003a21ba8ce074a81e7be22cf213a04efa6299bb06ba76bb0c600bccd90fbbe3936a21c4f0349daad3a6edd5fa53b8 0xf1fe3558d6964e91f7cbebe3563222758c042db4014d1d26d7c451c673d4ba7a -f86b2c82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0730b4c2415d5b3eba99b0d110931ef5b19f06f3d229620132318d0c29b71a385a012ec01d8ea94b5ba5979a715154163b85a0ee54a4eb695413337f3cb61df340a 0x25e0c1e7dc6ef54d15ee046ac201a15ae165d8804c24e967b57b672361f1de68 -f86b2d82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0a9f27b92ce5e4c8a3b743d01edea76625d65ad3586e15834369a4303637f6988a0224532ef43d914b6bac9d52c580310fbda593c8a96c4cf1fd85f0bfb91ffde2d 0x59270ba2e2c31a8d524f1dc606d4b72d3995064991eead444682da5d29327f6c -f86b2e82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0358194ace2d386a5a7073dbfea6d5823fe52bbb580c88d5844ec7d0566cbdd93a01218ecc241a913c0492102d7b0f06467711762fc81e58ffa1ef9b1517d28ea01 0x04c929d6b3264b7a4aaa40eb9025415cc04ccf27a219c852daf24df0631e7c25 -f86b2f82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0ed2be9e5e95ce6bd8eac853699022e2fb319ebff3db0d049bc90c2f70b522d04a00cadc1c62b21d1aa1bcf9efcb0389131139b9f70695c5578d28a26dd915ae23b 0x25382323a87fed1e0564f39524c55ef117a175ae33b66db2e01d5eab279c022f -f86b3082520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a062a510ae5f302ab5ced97db1e3a09a77659907295983a1dacfcd55920c74b014a01825d05f1ddddc6829269000bd40e01c201831d34411efb9edbe1717f8e15b7b 0xb427e52bfaee41f0ef39d62c8899a71210e3342fe4f0c8568a00083f01e93fc6 -f86b3182520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0ba8a13a7b63ffb8034958c6c59600060a442661530b636053ec02de881266eb4a017a0858dcf980e79a15ab5690a338ad439edb76fa75188f7dbbeaed23c8dd9c7 0x8736b4a7ead9caf66e695b99615583f1ed808472e6e69088c626b521686a1a67 -f86b3282520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0138c3db139a37fdfa85c75c07194df38c856983b025e5e788e1913284d86422aa003995150340b3587c86724cb60b1026f6230b1eeafa029feb2e30bf6af6040cf 0xf6c3b47dd5139777ac17b2f9e99997c490c86380193515f2d3736a4f20aa4ac2 -f86b3382520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a076ee06612c0397d4f29078e62eeec78cbd2832140287d27553c88bb39a207edea031021d7c18538b74c545fc62ae32d49b0866f03db089281d608a11bdf6fd0bca 0x471dfd2daf976523e42aeb366caac26e80cd83a5b4b2746b4813e030689e4efb -f86b3482520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a07dacbb44b74137203fe41c40e560fd8dbb3feb8325ab68defa198ee71c264a43a025f6c7bbedc5926034489fc2647d5c48ea010e896a0ae1a5aea45b40ef86b070 0x9a07c399f749d03403838a030d8a5683c5272319a5f111e499baef2afe9459ec -f86b3582520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0d51c20def20f51de0afea775d5c91983fe0bde1effb580f5c7c13cfb3b89ec38a07de4e04c5f086431cf0e15fbe4de16e9b9469124047c681f1fefcceb43d30a70 0x0524734153fa61d5e22b7f49a3cc539bb056a427d7e12a5f7ef3e7cea164a379 -f86b3682520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0652fe3fd4b5f72151707c954d709e4060570ab3446b9ca4a0713bb5819bc1027a056b9d41bd7c88c62fa4800864314bb639b8373ca18682a59588cb0ff8eaf6da1 0x50355033ef9ab4298acd5c7459ba7d29c6e448371617416b163b39d4ed7fdec1 -f86b3782520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a076ddc043996f73fde2aeb82aeb639d3cd4573432d14e2e69a511c750fb6e9b34a06c0de1086e0dcdcd77d07a142ad2eabbfba14d31bf87ce5af20879d462474d63 0x1bc01e04bd468046e6560791e8ccc51a69d2c00064b97a025803290ecd485b05 -f86b3882520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0ca3565e91f9f2a7388b74c64a2cadf776796f559594da2c7739d7e0a33fe1344a0650dbce5caef0847f77780b6b24c9704b139232b82bdf0f2edffb933c85d2eb5 0x67eb268c631e1f960bf221db214eea5d7c7936bf71b8c124aa75124a54abc13c -f86b3982520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a01489962def3a2b859dc0b486fbe59cce03a3c43f6029f115fb528fcfd1ea3caca01d9567baafd569ec404c714aba312e0e01b8ec2702979f908ec0dbca9e393c95 0xe316a7303afc3f432e240355a70f425431f1aff1561a0a095c83da7d01058572 -f86b3a82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a06390f0ebae35ee4f3db64397cf37445e9e99ae35f49baac194e7e588e80d117ca06dedb22be6bc63941d880701e60131770a9c60bc9f830577ca024bbc40d46e97 0x8a6a632c6e3a0a833c864dcc06117b6f5ca79e5f9b966d212516d49c353df731 -f86b3b82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a06bedba3544fbd63baa27fe3fcb89dbfe31ebc347d369263cea316c00d809317ea07abd55889c456906af66c56e11aaa0c9a947b4f832ff213e998436be4f0242af 0xe08261e42d7470033779598c4fdb487489d615ee4abfa4b0bbf3d5721e570861 -f86b3c82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a01d2d7aec77647d0825a81544e42b4e08851c905a0fced9079afd6e88b80e410ba0609a94fb17c0da96e7efc0955c14c369959756fb7853bb74589899f4d1c94613 0xd7030ea9bb229cf2c8e3cbba8ac147e6ef5614db5b40ab43accee86c1f1a261c -f86b3d82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0828c6ca09524822f3ee47b63726bd9c550b7a022742afd172299982041c58496a020c24f32875d15770a1b8490d13a66e777d2667c7fb9be34e08570e6d75eaead 0x75243bde20deeb007bd01f3d100c670145b456ce502e79c3ff075b06a670ee00 -f86b3e82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a067be128ed4486a6f950a871078da3d0c26a4fc53d91b27c53f49b5439bda73c3a00585216e9aa018cd298c533adac17419e9b3ecf35dc905bea386107430667400 0x02fcb0ba8f10c22542e5a344f9d6396e5a94979eaccf1b57ca50d60b90e56e93 -f86b3f82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a01effb11f60a8403eb9305ca8400235619d69329bc60603957af0759757a30355a06e272d752465629c88d616fa1d91d2c741140e8bb69f9e2a01598c619740ad59 0xb8c648edfc3c497824e67f63aee44e919e9c3ae4a6d1b43143800762117cee4a -f86b4082520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a00c55f258832aacf8bfa68451f925a9407b6a218577bc44b5f7609463f9eb0f7da01ac3e077fce3534fc62b67390de521e13299977ddcaea580941069311f11c262 0x72a89b387b10e64aa3906f2068aeb2d7b1c489da743c0e56bd485622a7ddd8a6 -f86b4182520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0bcdf7d1a6cd053e444be7fc34fbf515280d69d75a5ca06043f5c69d9372f6157a025866b321a471007b88b447f381d8f4dfba0c4c25df812a96af7108460082ef1 0xe32a04713843faaafee1a6fbef5242d37ca6da1907abaef77d0952b92ede9617 -f86b4282520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a08a5c7a0da2fa06d5dddd0bcb1a7662f673b0af932d576f19641c986fa91403a5a04d4b9a83b3a65fad6094778ff7bbe4c3fa84359baea7afaedf2fba5c59d08d59 0x7e4b7e7c1c8167a89cb434f320865e74703453634f878b5070a1c0a2691171f3 -f86b4382520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0ea179ed3db6c072dc64062b0688a9667913292c62b0ccc2a87e2d49bd50c18b2a07ef3f05c8ccb50025b4a189d2ba10d74da3597d0d1a9d272eee27df0fec51cb3 0x42bf07f4313e521f570e34545f42d2e5559aadf8e2c1c61ac57472c7713bd965 -f86b4482520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a08ec4a7b08ade5cdf81dbc8f8dc0c5a6dd60852f1d45babc3906a2b93a8f9db97a00c8a125fd18b2b7df15b03f77c92ef040840c22972eb3981b01d32a78d9c83a7 0x8d1dc42b67182033693760548e3de742eed2e1195027647e23f91649a9faf475 -f86b4582520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0afd7c5302e3b5a0057a359c96ba6c1077f0fb67e200ea03f597aa984ab14e962a07e85c2b63844d57ebe46801e3791a6ce0796a00242e5637779d8908ec76bfd95 0x54c4e87d0bb2338b65b40865a77082bd5c03e0bfbbb052ab2dce72225f8fb3db -f86b4682520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0c03e0b12fb0a77eafb297f29328464a98d2484ab44b1989cf5ca0f767d08ad7fa00a7653afa27dc426fce9a3746c0e58eb3473ca37ad4b4c2b9b521141fc06cba4 0x1634ebabde195c3dc2b8ae662379d25c9c43a841a828802266a28b46668d69f1 -f86b4782520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a07e07cb492be425c615608ae1847f9ff18b9d4154c562d90933709ab20db3c14aa03b13ca267e92c86c6fcc0ff1040afff169713f5eb6d96c49c55f3fc4edad6bee 0x5fe6f1fc4ac5e10da6863732e8eb3aea41f3dffe7b18a9b204353cbf77f9e4e4 -f86b4882520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0a0ab105035bef0b1e5cb76eeac3735f99ff7a5bc6bc3f30baf0d0cf87f1e3694a0232ba3324c66a500d4b2fcd0781181b87c0a875ed10cc9075ce297ab28aefafe 0x9402b3c4ac287f501f955f15f1aad52887821706f225fd1de3fde0eccea71c4b -f86b4982520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a02f5e7876022921beb9675d200a4be5e1e1619540c898513c45597ea7ccd9ce1ca042a6b0964c033abf7d4f1d50607cfba64ee13a1661edc634851d15582679c00b 0x060b562f48a91957caa12ff5df0f40ef291caef9075dbdb29161791926101e30 -f86b4a82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a03cc4eeb4677dd75289293f0352dc7c997b69a5ee994635976cf5045e421e4e5fa07927576719136f578a8f8c43f83c0d6563ba4cb1dd49f2c586fed7106735426d 0xad25a128f945ffdbda3c4bdf40f50bb242d99dcb006d12a8860d2d1efa8cca7a -f86b4b82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0a99a4955d16e8a459dc4253d10268623f24e0622b4bf0af9086d1ed549c31365a02193d079b4ef45f2d94d386d3b34ee4f5831ac5d14fa503495087896e70d1466 0xc463aff5b78c684da472e5c9dc3cd1a1bb8be0a31f90048f1741e8df7dc7bce2 -f86b4c82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0af9cbf9fdf12a804532dd6a6b02309adc7838ee776232d12a3e20277cf5f499ba00a4b7e38c827ab7a75d258f15d90d5442484d4069a79690f060363c0da1094ff 0xc444b3a3dee97a420c64c8409ccb47799ba74cee223bc0c98b922f8d0ff1b077 -f86a4d82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a08810530812e4a5583fa8debe012cc7417626ee721819ebe2b88d5ad9cdeae5789f2200523e79ae5465a30f525f3a4214f29e7d5f99239963f15d3dded849bd04 0x1aa03509ff7e81140e8999f775f48a5fb1998f95786faeb18b74f7a15bbdd048 -f86b4e82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a004bdf6f7ee31b693903637296f1ff75384b62d96e1356f26857fa465600bee33a018566bef5574106ac03803dc99bbd79fa672211d0b9c61fe084710dfb357ce40 0xa22b39c12ef341250899d90b47a8f2958ca85d4fe66e8266ef8f13bc2fa1ba5b -f86a4f82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0f27c097623ea49c76cb8224945d7c481205456a6ad88a82205af34946565a8d79fd0678204b0898d310bfd9db21f9233bbd74466671d6d30b5898d966074ca76 0x55a037c879b55bc61357d32c5255edab6628c07a7a8d964d1591a52de39b7d12 -f86b5082520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a066876e80074c81f494e43b497ef370b64b6f6682f29b5d047bc7bd30d68ce925a049890508e5941be2c60c3b3defed0588ca0245f6ac12ce6221120941e931e17d 0xa9f9ec59abbc0ae1cdfc5330b4c00782d6d245bad6e2f32e5ecefe0a851b0301 -f86b5182520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a044792a9a661d505832f590284926ea8b0f91855640e040b1a6e4ebc46b6f2aa3a0583029e538dba88515760a3b0042f5d177894b766e3fe29872a301b2d98e5588 0xeac6d6a9b25d8c559fae04285c8ac366de3a9910b68da95047b583dca0d9fea7 -f86b5282520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0b0ef50933159cbc8d93b232b3df80c5a4d3bf9bb9b72d8dc5ac81c6b9dbd4530a04a4f3c1fe0961400434cb9a43729a41b700235e5a05d3cbd09e1138c7b25c6a7 0x43fb8f9168ad88cf958e362aa4f862eb5ec55860aeb4dc04033a355decf402f3 -f86b5382520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0a77c862ad0d9c74d6929503abd3bc4151d42394275300d7c8baa631a079961c8a075e0aab179e0a0888470892a4d01a2fbff8ac309eabde167c7ca1bb16ead5564 0xc331d933e1097f5c833d40b45ee9931c13eb52a2563f96ac666e5f1df1b0ecd3 -f86b5482520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0031403b8fe507a8b9f21d53c65589f072b0da261266e11189d0d87db591ee43da0692831dc478acd3992bdfe99d7241c793bf83cdcfbb205dc65c4c8b32f0a7d25 0x4aca8fce92cbfd4510df4e6c8a8bf6df95511a0369b2af58f8894c2618c6a47b -f86b5582520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a05c524e890aad88969cca3a4d0e3a544e4ae6619d89558b825f6f9494376e0fbba01c9383d846b1e703aee301e84d96ddba13d470bbeff60c9892aa18006cdecdec 0x10645d5f3a7769e4bbc94a27496d33035f7c015e82d5a99f14cdfa163b30d794 -f86b5682520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0a01a8cec34fa235fcf65f98d905c0fa0ca808c0233bc637e473cbf53acc41cc4a06d11c488a50ce79afa6ec45da46388025ffeb94ddadd72c76c3ddd9d4ae24f87 0xd42ecae0a7206405f90468929741fefccc24f09e866f8aac86acf9b6ebf22aa6 -f86b5782520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0bdd5e13c66c0e516457729c8078c28cbf81a2cd996dff35c1aecb381f025cfafa06a0f06f95e088cc6ca402a24aa4e7a2346dbed9bc93e687ce037c65d0e7168cd 0xe33da3ef5002933868d4e29bb5230b0d6dfb7d5c6792af9400c42056f9c09de1 -f86b5882520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0efd67546818d7b97070a1651ef49c4b3323ef7322fcf263a87cffd60808a969aa071347c797c55027ff804254e76e8e5f16f429f7ed25d50983474f2e29c2b53e6 0x9291f190897723f354a62ea85e130fc9599030d6b0a2f54b60494fee846bf9a0 -f86b5982520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a093af13128c7c87e9475e7e4a78c0aa37c08df5169743b1fa19db8a77dfa1532ea02b9a34557fed57c2459fdd164bd563f6fe74adf08240e26f2522d3a710efd272 0xe06fcaee79af8e2768045059ccad12d3c0b60328ff2538ea6d439acbdd9d3ce2 -f86b5a82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a036ed28c90553da658cd796a4d7f001337b66fce22114977545d50ad19b4d359ea060372df24891d7807d9de475454dc0263d8129fe7c5fa248057b7b92e070e8b6 0x984a3032e95e95178275772a39597516d48fa944352ecbdf8806ce8b3e9078bc -f86b5b82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a08a250d28e95c5f3b5f6db4afba537eada28faee00e1e165914aa319e903f8e40a051edce71491eb522ca6fa6fffedd79d7ace79029d285990dec88bb18044ece78 0x5c970223e9b7ae3b63d32aa433ff79c763b4b8e17434c30aa766c93789e62feb -f86b5c82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0414c64935d7ab515bb444c65a2eec326933446a3b7969761fe2dfd037fc58e6da05d6264baf4356c74d4a820efa88f43eff364a0ef23a63ce07275d742cf33be05 0x99500f8451e57dce27de5be14c35ece8d339c7db5325acf2012bc313206f7831 -f86b5d82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0c881d196780ca0ce9ea439be16a088c3c2305e3783fc091eae5cd87d4ab5668ba07221288b81e69b34c426f45af7e287e5f1d93c4cc950ef641871f652fa4d0b81 0xe7d0d74784faa4ef555565d0d341fc881ad5a058997d920370c9eb60b15fd371 -f86b5e82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a0f2a7890c68c6abf5308aa1962550b8ccc72625dabef15ed8a3e6c463509a0cfda0314999e94fdee38b58572e3b3b0aba91be4766ad2f86bc838dc88ada1e357f3a 0xdc3f81b61cbed7d921af7673fbbe84aaa6a03837320526b3d3d2af23c7aaead7 -f86b5f82520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0887dfe19cf6a3d2d6a985dd490626da4aa9fe02e467cb7a9e0e5d018bace2afca07ae46f4d2dbaaa6e0fdec18356a70ecbfa02e790f114f8626d39642493bc129f 0xd13dae8f2ed0bc011d66cfe64d6ebd45a378976fac16d966852b9b07651d0b49 -f86b6082520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a006dd1939df407e242cc6e93a6d718f91da3bb92c943555b9d7eee7ee82fa70f9a0530ed4a1baf2845cb4c7e0223f36f231bae27c5d56154b3550b6f2617b765681 0x9618fc560a6c09d5da7f605ca655651ded420d3e8172864d80c212e974f75474 -f86b6182520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0f703bb28a21e59ddde4ebbc5a131585a9246fe44c7895fed17a435a767d7a52da0425fa2008b90656b87a50fb586fe91637684c5a38e7f9171a94aa34c57ef57c9 0x6c07290903bbea92798032b2040aff47ec184efa72ddf5f3cc3b2cbdde634cc1 -f86b6282520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a96a05995134876dc90d2b562f41a6fe89eaf084b1076d1f3e4b822c54cc2734d7639a0444b183da1eafd7f98f71b6f8926e897fc20ce47131e34b4aaab229f68547281 0xa14aaef7603356f01894afd54d4a83b1ed30afc1a9662d50042fdaad6abed95c -f86b6382520882520894b53dc01974176e5dff2298c5a94343c2585e3c54880de0b6b3a764000080820a95a0ca752227d6aa55af566b4dc786b3d028911ceddf85e9e47bf6f778650b5eddaea026c36fe8df32cd6f7e54788866176bcf9f47203357be4eb69b844506ed032395 0xf27943641fb869daa3ea538da9cd4454fed08ceba26737374d8e5560369d0f3e \ No newline at end of file +f863808252088252089400000000000000000000000000000000000000000a80820a95a0aedf43a765be7e57167a732fb460bec1c73f29bc8c2f7e753b652918ea19cd8da04062403d1ddcdf9d80dc69cab4509400a21604f0ec42f82289597f8476792648 0xfe63231c20e2db740e6c2f8e18a83f8c7c60bffe94add84ca22493d5f87c2592 +f863808252088252089400000000000000000000000000000000000000000a80820a95a01d41e53e3afc4feb32b1054fba14d838a80d940fb1d02bb44569f52880ae58e3a067f9d14a42b852cb0a1f597ed805b201740a81b791cf4edb49460df19e5eadeb 0x00994ec7cdf086d4398746068f81d98f2481e4231fc30aa41f1b2b1e03340c89 +f863808252088252089400000000000000000000000000000000000000000a80820a95a04dca8006b69930a6e1d9bd89b49f1b2987b0d6c5dad92ca082135d3416686215a03249cd8c7d2d10b18d9eb69928b0090c4da8f4c4d45ecaa50efd32a2526d74af 0x8ea29702d3850068fdfc8c6a5af46f7a82e9a9e281a0397122d546bc463fca84 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0e2c86d253efd01e1fa81c00a62c83add8d9bfa46fd9baf85e7208d97973d6066a0218a4ecc733ed83cd8df73b758aab559f54cdea7a94c8f21a3d9df38405761d7 0xebdc2710a2f05535a7120f6f1594a2140d5f058f9898658f818c3a7635b2a21b +f863808252088252089400000000000000000000000000000000000000000a80820a95a02389dc363f0245be926775aa5c97ef965834d4f9ff67b4f0e21eadd79c583c1fa032918940512c6fa07e9984a2bbaa393e6d9ca9b55a95066c053ab339ae706bb6 0xae7df8b84870509c821dbfd391bbdec72b406e44a337f31f4ae9dd9bef9db677 +f863808252088252089400000000000000000000000000000000000000000a80820a96a07efe898077ddc33c254d3c014909abbee63601692be1e56d4e1af2e06222f965a03c7c5d64b5041b789cb5b31345cec712d100e838bdfc885f2d66f8f0424264a3 0x366a2c98c80f66975180cad9d22b28471d156c5a4341cfa69454a4e9d411e44e +f863808252088252089400000000000000000000000000000000000000000a80820a96a0d530bac55a71fbbcb273cede8badfa236343d868849f999aa310cb9a94e5680da04f10054eb269b9b72ba13a8d719b3824476654cc84c29ba67c988e9eaf7c786a 0xa51b07ad1c3a65594156ca1d17cf2e2916a05a4a35e661e4c629ca2d90c9472c +f863808252088252089400000000000000000000000000000000000000000a80820a96a0111ee4f935b137187f69de739031b7b255cdd5433439437ed2ce29d6ea407e3ba067202e670f6d4515ae512eaae6f0f58873a53deed45085dd791368317c9d085d 0x46227c051641e907b215bcffdd8015e2fbdef71961b5a11748250aad3370e5f4 +f863808252088252089400000000000000000000000000000000000000000a80820a96a05fbd32257a7a1e2a3442c87616faa0f64c1ed6b2a361ae5ef6add113418dea19a054768809c7ea8040314f846bd6ac6f88a19cb38064841ace8a1e8b1549e4aa08 0x10c2a04463149b7c9ecf2322f0e3fe18e82e5d6424629f3a443961a0c5234f3b +f862808252088252089400000000000000000000000000000000000000000a80820a959f0824da1d8a8d0f4cf9c405c6256329d6ea8e2aa4b1cfd83303d722c7a8b6b3a001e17e60e38212861a53faa0196b27161a21261633144ea971b67d9ad189ddfc 0x4ec5757576cf19143f52ea619342df11b4711bcad02dd18671d388a3a020f440 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0cf4d83beb734ff52db807d2c5c2dd0dbf768ac5ae33c7a2b9d027111b3f3d364a07384c0c8ca1d9e57c86b654715c36470a78a28c55a02825b81d1d64cc4161cf7 0xc05615a942bd6329e236789d468687a0ed686b548bbf66c6454adcb07bc5d103 +f863808252088252089400000000000000000000000000000000000000000a80820a96a09f100b4cab5b2e12ffd0469f1940988a4dd243ff070fca843a2aeab9e53eaf95a0687efd7a05b104b2265d215a7253c5df1b41a3fe2e64322bdfd4133a7e373ba7 0x0cdf17574f240e9c59db66534d7c53420dc40f763851fa4756629f5eb3cf456f +f863808252088252089400000000000000000000000000000000000000000a80820a95a0612749864bd77338eda36771b107677bb69f6a924be09cf91ca0b9cd47ca3624a05fb1e77c18c65be858e666c6589623815b7b94b5f5b295b031290560ffdab5a0 0x836c8d68f8975bc5fa12a0514a959bce4dae6ccb7730fa08eae38afd93b00dfe +f863808252088252089400000000000000000000000000000000000000000a80820a95a0c35571dbdd9a9f08de53d22a48c78d14dca588ce1733c753205e5da398a4a286a01fc5533667bec9ec6228f4c4853968151cd207f59a2812bc3662c6a408b69cad 0x4f4076cab3c20e5c8e94b3c6408e407e3f8b9b8dbfbc1d8d52394877bf18fded +f863808252088252089400000000000000000000000000000000000000000a80820a95a05257202f5c887e3a61c044209fabd672408bbcef69cdf128dc0ad5cca4724abba04778a180fa7cb1a709496cbe3e1feb24989dd2f18e80ee3f8b1d7cfe2a0e3ca2 0x0dd61a60ce2805a984ece788dc15581aec01ddd64d3320e250f9e093413083c4 +f863808252088252089400000000000000000000000000000000000000000a80820a95a045d666e5141b29d4b5b313adb529a287b63a12750c6b1c7450771affde66a5cba02b7661e1d8f800a7ad3f92b7d4183308702ddcc5a68ac1268a53bc417ef04f2a 0xb8118a1d783758c401b4d4d698a4d0c9c353480b5c14fc72ac1aa84a04b1cc1f +f863808252088252089400000000000000000000000000000000000000000a80820a96a0de6aeacbe7e93f4468ad8c30d543674b95900356787a5cb6da3b5cfafc3688cda06bedb7226769a300d837ef1f5f1497dd2c844bcd5484a5ee560da5f41d6b5bf1 0x89f0b8cffcdb6d3c35f556e5696b31840aa76b0a93644c8b03e8f4d0a5ae9876 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0b2daa5c82bc2f6fca120d2f41b9d3e16328231dc1f9bb83f01d71afa7e4989aea04d84ea3d6d1433fa80064eb49fe3164c208b3f2a27f0870c434e9dc9218d81c4 0xbe00c04caf15869fad20c0a3ecc70beb4f2f5c69c703e6771dd25664f3d1b7cf +f863808252088252089400000000000000000000000000000000000000000a80820a95a0cac1030b1356d22036d164b78445d18e9ec3bd59ade4dd1a2c3d980164c70cf2a04587f2faac75296f55da0f52f7ba4bbeaece0c3cdd3dfdcfacb2efb04e6ff6e8 0xe3c6205c01f5b80ede1b956c41f8e2ddbc711ee90a64217295f30461d0fc3c94 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0129f9d575b3aafbedf3a3ee4ca3e0c885f9a18c61b2abb6bc7861447b998420ca0508da84e4792ea940ec459dc748aaf3d8aefd508f38d1794a453e46184b77383 0x9c44a90b0b747a9474c2c26974e71b3116ac213d703933a3e5566ab9c228c0a2 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0a813c749bde4b31bccd1a0018972ee2e8bf8e635bed4b5677b1b537b4dbcc57da051571a302adf83cb55a7c9f6cff65b1098c763f7ba5c1a0eead4ee719a83cd92 0x57e96173c15324d69991f1e7d8b3008fbd84e8d5d08e023ce68b1e0b579f0f7f +f863808252088252089400000000000000000000000000000000000000000a80820a96a0bef293dac04f10e200079276c46e50620c5c87cb7dd31877a2ec8e5544f73aaaa048da88e41904cad418d0348453a33c1d05951ea8ef67304f85deec0971ecf142 0xdaa4ca2072c4f91106f104b47e84e8aeda5722e3de2a938ed96e4331dfa9071a +f863808252088252089400000000000000000000000000000000000000000a80820a96a07b94c69fad1f9d1132b9449d1fd6404ba8703b5af784e9cecea38c82b01e29a2a047944fab9885ebcc1b206401b1088d44c314baeffc26d46d22a9ef78d3ff1169 0x9ec08e65d243c654a8de089727375fde22ed78fd1160ac5c62a5a9443756827a +f863808252088252089400000000000000000000000000000000000000000a80820a96a00b3a6beec69a1dbcfd44165427b1bee97abb5efce62f39a079f66fb738ca1815a02d4de737778e9562830f65eed71a6bcec51c02186efe8c7f671d1416a91f8eee 0xfbab598c00d39c68ffcbd550f1fb8a324e3531743b63708be7ac1c6909f9305d +f863808252088252089400000000000000000000000000000000000000000a80820a95a006e8e852a436bffd722a282047ab26444618c9499acda43316f81cbc2159647ca01c6e89dd9631f14be5ab7ce15727e6da307d2c522084dcf6dbbf47fd5a033de1 0x2fd7191b08a433f355c06d6858a423ad47493d6c97fcdeaebd391f2102e5fcfc +f863808252088252089400000000000000000000000000000000000000000a80820a95a061c1d377feba96f75211a8e2c7969fec10063cc0685080219b74bbf0887c22dfa03fa56ca1fed11dcc3e41184268208376691c33770a13186c790c367c9d92c322 0x29a2db6277588ff489668d11babfddd5e4d08adc056e08de2ac51342cc22fd45 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0f1f450de96d0a61a90217403142149e3125c20656a84a41c177bc582ce05531ba0338dad83bc97fb264c5803118505b8af7317ac7e587590db7d3d42039ba402bc 0xe21b9895e5d3c5b2298392f77cf01b0f106d3fc30a47cb678b45e290dafa9b41 +f863808252088252089400000000000000000000000000000000000000000a80820a96a00b08f3e0f2b6e65743e60b569c7cd9d60c48f1b47063ef3de9de586ed26e7e24a0195281fe05e2325cea95347d2046a70bf513de1604b9e141b15fc2392ed16da5 0xd7d2e4b2ab76a97f1850a1eba1e5ce1477bd2a975a629c4551667cd571182066 +f863808252088252089400000000000000000000000000000000000000000a80820a95a09f671b880dd0196728a95ebf4acf60ffda037cf0a99a0c1cd342efd81bdcfd46a038407d017da1fe1da2b52a4af6445452b6e2cac94cc6742773e29743c4b4ed62 0x448c4f3172e5686705595c65576a091aa6ec5e17b2850f043278bec4fdbc56bf +f862808252088252089400000000000000000000000000000000000000000a80820a96a0918142c9b2bc7b14ac631627e8479a4f4ddb6a250d47ef6124a7bc21c86cd1729f098403ba37c166e6a4e1f3e92ee35b5ef583e4e859265be26c9a8304169edc 0x0977b1a9d4798a0b0bcfebe32fc80db8c63c9b229cbb74d4472e11a324985efb +f863808252088252089400000000000000000000000000000000000000000a80820a95a087b4cd05cda1fd5e7e9c3b2580cba8416b58ac4d648a7264ec8259628d55a16da0633e0a580820eb2bda6d7ca06416f24e5a3c90f0e2bef3a7f094a9da4498f9c8 0xaadf071b288431a5690e182775f8cb2bb93d92b2d8315342a06057c0f1576390 +f863808252088252089400000000000000000000000000000000000000000a80820a95a05d26e8acd2678229d18670adf1676de8ae47cc96a10f4c146f3a7e70f65acd89a03b4d5b2261564dae52e8f46fe38e7be7285e49061826f99bd4ed986c87a06297 0x0f7963a6dfa3c6a45b57672f25c64b7da6c08a99a877f111ceabcadd4491ff4f +f863808252088252089400000000000000000000000000000000000000000a80820a95a0977471aaf30a5bc9fe56c4cd6d851198af366f91c604d23280181c0703549a2ca01531e6c42601bbc5a146c2ce92692d67d6b95d89927e3901d5d86276e4a05796 0x39c251d8b90d86082cc6f73795052cac7086b91fc320349a8ac5c41829652530 +f863808252088252089400000000000000000000000000000000000000000a80820a95a02c2bea0e745e75e4cbc2b632150dc43651818b20a2a8d3f3327075638da3ec8da024f43be23c7fbf52af85e67736af9b4198cdbe682d9d01352480a9748ca6e492 0x68bc7d04a71a92a8300ec8cb2187760a4efb0ed919671ab675a698b8846dc487 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0cd109bb023c32b464e9ba9dce3bb14c0e88c2b2dd3e9d004857ef68177655163a062f4ac358a6436462cd3f1bf03caf9a3770f71d6b63c8047bd10345ae3ab6cb6 0x801d95f39d958d829fe5d54f9d957508b9a76fdd363542d4cb5c169e37209925 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0c459975d7f99654ed47653909faeab2e617b99793683fe453c7716188eef47d3a057e63c8b6f5538a4b67af01bda0ae3b3871f66682e0c0dead064e2bdeac10457 0xcd9983b6d7269d34956f8b4db0f15356a25e87822a4f078155f2260c9389a7a2 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0a19c59231fe61d7a0835d39bacc3a2a7fca5a0ce9f24c1e3b3c130e650afbbbda0083654de3344cd21015cfbf92d6e1129a2020fdbdc452b320cca9b647a4e44a0 0xfaae6c12002016284e772a8213a3cfd3a0db564e0a123089def144de00c7e212 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0e33b19da0b0bbef6c3338a7b5a1c3d2861b25ac0290981d5e334c6df92f42f0ba03b3eb710f1068168894867db4dcbaf81aff48d9cab670a2caec961767b4ec0dd 0x907434a40a48a6b66c9d662f6cc37c0de381fdfdc00e650b76bda68fdfc36951 +f862808252088252089400000000000000000000000000000000000000000a80820a959fcb94661759163ba80a6a4442bf600c41006590a9df7cea3c002facbcfddee3a063eacdf4ea265e09629ca7548c1fd6068e22f45824e51ec1461b7beadd72cdc5 0x6d0e82089769c5e5d86bc0bc5d0b2a67f9a356c4ece5cea9cdde7f339c482ef2 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0772be702e2c3b6e97949602435de572fb70cfb8e9cb117dc02fa1b6d7a8298cca0268d1ffe7f772dc988b77387a952600acf4a6937461075408183f7f6a42b902b 0x9ef7d7ab286ee9cbe8df4faa7c88e12e20117e7b10140d356a0c492040a4f02b +f863808252088252089400000000000000000000000000000000000000000a80820a96a004c5b7b0d25ca1aa941fa319e3b159ea3402f03e8b9d720658782d290608669ea00f121fc9aab1146c3d5ac634103f23443aa4fd3df06952e3b991437af58f4461 0x9cd003846971d3e690d82a6195531ab91b84f92ca06ad0951722cf7a72e3fcdb +f863808252088252089400000000000000000000000000000000000000000a80820a96a02f697bda0620346946147654d07d8303cc3b1bd95a4d0802d7a14f13875ca624a00e21354f14f33bd6b602ac1f0802320ac62078d61e5a179c0a7effd968a07b3d 0x8430de33be697ed72bacb5b522dd0a969facfb7961a9a3d7426c95ea02d05801 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0e3121d5a8ac60cc3c417f0c84f9bce46ac684776a38ea876f9017b3d1fa124d7a019dab1c8bdf51adee0955d45ada66bf4e86c3a25f6b09561053620bda1d82f62 0x261f41fff8d9ad6a23fc6ee22bee8baae5e3bbc551e01430bb5b77d1bb68d247 +f863808252088252089400000000000000000000000000000000000000000a80820a96a01276dc25e931aa61bff90af3f1db2608b4f47fa903b00b54be867abaa1c18b21a0635b4b80b495c86b4eed435b4a4dcd7c0abd9a0d5e1a0920ef11ec8b2c252349 0x7b400d16d8159895eabfd12790054481013a25cdff69984fe8a8320747711174 +f863808252088252089400000000000000000000000000000000000000000a80820a96a045bbe1a03ee1f014fb90bc5179b60e128009073ac35cc6ae7d6b4fa798e69d23a03e15fdb15c814f971b7fb3c51ac914c0fcb21144653f86ff75644d5440cea93e 0x375d05ca450cfa4c784a68b2a68235764c1e9ad7fe68bc8d8e86d4884b7ac451 +f863808252088252089400000000000000000000000000000000000000000a80820a95a014cae30b39719dfd4d93381cead4e0e3d16040c8f43efb95ea933d92f14ebbf2a0375733a98f627477de6460d1836969cb94fa2cac74d490677bda7c12acb8adec 0xa08c5b0806c84e1d351e014340cf786f50bbc3308a0886d7891302ac8833bc44 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0030a9238e3ce51347207123bd1cbb4db1d2bdb7dc48f2aca802799b23eef881ca07a33867acbe76d67a063d144e2b1a4ad29be12db719ecc197808984e23e2b666 0xabebd401cb21da0ed278e85c3dcc5f38e214da73764c6d87bc58e46d2c0af341 +f863808252088252089400000000000000000000000000000000000000000a80820a96a06f12a9a0b8c20b09eedebdfa3e9d9b0a9f7ed601d1277b22fa5ec6292939a4caa030c4bc4e2a77dec875f25e6989ab31bce8b60a964f03a9068b13c1d177eba69b 0x91da9d552e956063a44aa257340ec2849351a6c7b65bf9b9400655cb7ee1918a +f863808252088252089400000000000000000000000000000000000000000a80820a95a054dcfc4955e327645eaa272f9186bfb3811b61c87094aba4a0c7528ee02d15b1a055929f5e269493336d58d079222a98553e942c8dd62294d1428e8e05dd588096 0x8a8f76338530b524744747fffa158bde22e0475ce8f8637a76d9df21018293c3 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0b37d3256d5960162e77d0cbf41e9f12dec78aded71e881bebedbb691b8ea092da077d77611bc3baa330e6a632e1e2bb1988cce185ff9960be95bfcb8ac4a946a63 0xac965350e3414962415eaf199f7b01b29149ec59dabccc1e1ffd72e242bf52f2 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0266656b8ab4a3b8d6c5bdfca2bb1279881c4ad709a4708ddba597fe031dea63aa0364f7dab978d6bfca5897ca799eea27d357a3b76e7aeac8449a6058780c68868 0xd36a5b6842d88f342a6339a41506e08ca7640068e9d1f71f6e78ce9c46ba4992 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0ee116ea73aca0b9f0ab9c6084cabe21fe13306004da972b8cf719c4142170ac5a009007244e5e4188b2bb039f5aca589febcc09c90ee05ecae399592827b3a06e6 0xd7c45f7f5d716c7111b7c75e980de39fc5cc114d1c626d752063c1c7049dc07c +f863808252088252089400000000000000000000000000000000000000000a80820a96a0c7b739d15b3982fdb001a80780ea44a7465bb1195f75ad412dab8c617d05a767a04bc37617d5e72875afcc0d4bf06d3375d83ad678a54755ffb65ecee9d80f153f 0x2f7dba96b9401bd453f3537f1cc970683f6ffcf74b7b70abecee1e74b3ef7336 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0cb646fc2f5fa6763dd1cf1817cbd009abedc7fb26c2e2ae3f080d9917cef9e89a02ba629756a34efeaaa59ffa72160115d0d91d78fa41432d0dbb05282a240410f 0x3486e2442388cd8783571b58efb4940dd05bae0e9ea58cf89c3fcebe8d311537 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0c738d5e35294c9578ee058a47188325f07726dd6152069df3865977d99338d7da01a2e329b83e2666209d7d8284ca6003074b233e073a1b34b3732942c4e3ede78 0x27949857985ac4459e0a771939a129656c29d7725e115ea00e318fd19d49480e +f862808252088252089400000000000000000000000000000000000000000a80820a969f0440567fa6f9fe2e02646a61b9cf362ac3b1126b431570e8159d09ceeacafda05a08906f6ec770a30f0224b6874de3358eb3f50a8e7cd3b740fdccff50ad3ba5 0x616c617cc94cebb8ca43df6e613313a673c90696e76ff0e0b71c67219fe5c29e +f863808252088252089400000000000000000000000000000000000000000a80820a95a0ddf9ae78434f7d24682c643c002d5249a472a8d0c246cd0b526a4b1167583fd6a03f376bb0698c8b7df47b6881a223cc6cd4ff3590b82c39cd68160bcd56a24821 0xc34dfb0b05d4ad4a36fd7f951cbc7d3a14cf8817b7b5c7a6a3aeca3b4c8821af +f863808252088252089400000000000000000000000000000000000000000a80820a95a0d6e0bf5cbeac58369846c7c2b5f7999e8b1e355aba06aa751caca236268e93cfa0674ab1c1917555647341cc61111e093eec39811c0dccb0e0f7e52d5526b0b557 0x71e49a5db642c068b81d6afd9e691f74d0337f84bcc17c0639a933e0d0b3915d +f863808252088252089400000000000000000000000000000000000000000a80820a96a05ee63b4071f60bf8ac4ebf79f211fd12eebc8a20d26212ce419fe936029205a8a018e30a35aade54be69f6251d813d014337262654c42373eb3741616c99ccc94d 0x339e5ea0b31f267a2a9ae35fd63e9679fa589e1b15b2c3a2bb5b2d754169c0c4 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0b582325720af642303fa29257a9702c5118183aebb0d30eea1a201b85f4a55caa032b6d46136436660de5a89eb770c01193f9ae20a3a3211fc8f523bd7482bff8f 0xf4a48c0d6371353a22d659b10b9816d4b96236a9ac162483094affa33a97066e +f863808252088252089400000000000000000000000000000000000000000a80820a95a0fe1c2cff0d74b46accac781859d4bf431168ef9c1213dc4c201a033eabca0ebaa021ed19c2b8bfd96e4caa668a92004c7a36c4c62fcfa4379455ecbdc420002df6 0x9e84951651b1ece570b9742de924d03509a9fbd7f96a44b5841ef8a04062e880 +f863808252088252089400000000000000000000000000000000000000000a80820a95a05e3afaa0480c1b88177e6be8fa7e724bf99758263f6b46bf6d071f8e6ea67549a042d9581b3b3ef96cd0e7495aac4b59e4edd16d49312c42a136506f1c0fd1295c 0x16f2fb8f5fffbbe630671a1085d2018aee734639c680a51333e07c0f8d63a7f2 +f863808252088252089400000000000000000000000000000000000000000a80820a96a02a63aa55e31cf0f31315ce754a6a7c6fe71a052e207fe7a5b4bcb4cc5b7a1691a00e0611e3b50b774bf4f41f4351ef383cc978df5d12b3775f4ce9643d36cf676e 0x93b6c5805b254e5389a106f2a00c1afc9cc9412ad9ec0e26f4a1b7f43f1d4dc0 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0ae51c4b35ee0839ecf8afdcb72beb23ea4307eae0b62039caa0f3fb2b2e26372a05e47b26b5c53fbdbd5fee195e54ec776bd82877a73344701165687d814ffb289 0x30a512c252919e16bc982887721acba4ba238640a163c61a9fff486da78bf7c4 +f863808252088252089400000000000000000000000000000000000000000a80820a95a07dd2eb1ca8b4f822633e04af1a5e70f693fb323cc00a1a108640d8b4823ee2d7a00722525081f0f0d886a68b400c57771c954ba553f5bb2ed5105c518d41afefae 0x38cba8bc80143b8979dccf8def32eb0ce689427c2e6ff92abda166368dda639c +f863808252088252089400000000000000000000000000000000000000000a80820a95a03c1fcfabecbf5e4d58cbcf0415f31705d18696f9d3360407d0080b0ec1e953cda00a8854fb83ce4754ced8679e36fa5340aeac87d8eb411a514418148d222ddd4c 0xed1135e571a03b407aba9c753fce5e428f72a87e5e2c5b835de6a1444a5d3a71 +f863808252088252089400000000000000000000000000000000000000000a80820a95a094537d430e9a62ed7a25974afc4994ffd41edb838532dcf8cc79813f73e884c5a029f01a78093b674ee1982b5c247c36ee6f6f366c69678d21804fa2ac2e48198d 0x82aac5ae967410485390f47457bca1122be1d3cb7f32e5b02acc06f053840bb2 +f863808252088252089400000000000000000000000000000000000000000a80820a96a03c99f8e5cd4762d30a45be3a511dfcf114eec3f3f159dddcd5f0c05e5df6bef3a04c822b8b3cb0df88a5d40a7019d37fcd55b9b9d08ce1619733ec415aa0e14997 0x0fe42934469a8fd2c84ec6a7d79b655288f4e0ef85b075d809097edf6f5b31d5 +f863808252088252089400000000000000000000000000000000000000000a80820a96a05c8bf15659fe612c5fc6b56d9bdeaab5a71ce5dd31a8c5c9ac11798f8a9bceb5a04ba8fd9b485b96b4575bd70e3330dcad6480d9a72bc718503c7b51cc99396cfb 0xac3aabc1be38df698986d97ccd9c57026c7bb45fd686a494a57267f2f5aca7e9 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0bce39091e5ec3880f6bedb71ef332de0bc3cfd2f3f558240e9582b30b3fed24aa0319a6ae4ab7026c472d284b4ec31726f06841a9a62d599097706755c732b6ce2 0xb816228e5c77df96ca53bdae0c45220ce76af0a3fa37e83bdc91ae12b142bd7d +f862808252088252089400000000000000000000000000000000000000000a80820a959fc782333e3f097bbac569871800191d61984767e9860b160ad78e52c93c2c5ba03c25cf17367d79c0a679ef57a189e891a91e495457525129eaa13651802d79e4 0x2b917da3ed78bb70e3bb61d7b2e73fb1828de362d2330b0fcd674e8acb56bfd6 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0451e88e807aa6c3928d64daad2b18693875c11c066764aec03018a3f9f5f1550a06048d3af5ce7fcda305d50c156431a53aa789fe438230e94ef8525840a3f6f85 0x5771ea74423b750210f2016b4d8dfad979e6a3f2b150d9e6a13f8cd3e2784e7d +f863808252088252089400000000000000000000000000000000000000000a80820a95a0e2611fcd55045c203730969d1c363b7a3a45a469b47f6e1261a73b86738c181ea060346f261e255dfd01a8d86b7cd71e1118d6aa417a2fb88e690ca66aa2a1d7c8 0x8125807e9b95f200ffa71f53c080c956b264982216c951cc2d443913e838768a +f863808252088252089400000000000000000000000000000000000000000a80820a96a032eb766ecb142fef181144fa66ff09b5cb508caaa82c81ef4fdd98530eb88cdda020993fc3102fb2482a2450eb7a831466857b1721bcf47e583688f4f4a55c8d40 0x2d087259b08a694eef304398229ee8689336042590ac1a5fa25bf8a12c9e0425 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0a7fd7d2fb2b56363a16d9687d1e86befecebeda435636522039c316f3fa8ff50a0040a74c6d9f39ff75b5763b2cb019723fe5ab05850e730bad671a02595732747 0x9ac7bf1ffe9daefe6eac4ca67503cfa38ca3836b38271412edf12605bf14f286 +f863808252088252089400000000000000000000000000000000000000000a80820a95a08ceb0b706c8a69cbfda385c3e136ca4b550446c8eabf14241e3d705d2d688a7aa03f311cfc6d475f048356e87336f80d2ba4f2c32b369fb26a70ead86c62f530a3 0x8e4434c7d4cab4e554b1ac603a185bfe1c0f00f0815a87c48bcc028dbf62552e +f863808252088252089400000000000000000000000000000000000000000a80820a95a013e9a6796066d9d52eb2f12f0776e3aa7e11c32e1bdba78e80e3ea94abce7586a04dfa65450d0bdc607b92bcc97ba3101e9fa5fd9e5a04eeef7873ad17f036d0f8 0x1ffe23fee54829a5567442a4eb9c92320a22e0b01aa9bcf456eda4a2bac168b1 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0a56bccb7699e6a50db32a540805ed8dee4128ef2017a9df5c5990cd6cad8d65ba0452c2fba80764a210259637dfae0c2bd81016a0dd5a6c9cf65ee4c15f04cf1b4 0x8fb9462a1ece3e131b907c563617d8111c3d8fa0df42a7f37a15198d72043f27 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0d21e08329e39caf07f5ecb70cd1a340e5af821cb46367f54b17de1ed24bbcee8a0750373206d05c9115fdd9c1bca9aa1f66097e17152d94758157b98dbfe9fdca9 0xf05cec1c01687ba07bed86011d0d8b9eea8c82b0dfe11f77ef96ec291a6307d2 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0355d15aebf9b615cf29da2c985c5d41935ad57c94e0adb0694f586f0b9c2380ca062322c79ba0fb1d09d1a282fa41b7b74630da2ef57a2babc8dea7bfbda2d3e30 0x6d9755d47740d5c22c19c53f7cba9ffb02ae74b50e1e4d59e8cb25d8abe25d1a +f863808252088252089400000000000000000000000000000000000000000a80820a96a0140969fd49e1439aed78abde1147f72663c400767a4b6d9a24725bb658790732a01a2260cdbb3b3c5705cc917281863beb8fd87e5bf74a648647b2d47aca383c0d 0x6cc8c4f4133ca558ad40402941e5964c629553b20c27c3b957e86377c0fe862c +f863808252088252089400000000000000000000000000000000000000000a80820a95a097a225d89a0a33a12e4053258c45b24449568739d56e8a0a927d40e4b6ec800ca008b4b273c5affd935ef9b60d5122b14245a48421b982dd14cce117d1c9c8308c 0x0d91833bd7dad065379fdc505a091b93fc7516bbd1469e9b0771363c7646916c +f863808252088252089400000000000000000000000000000000000000000a80820a96a01d8aabb569155600ec056da6bdca511184c2c938eeb44fc5cadfea01953d8222a0060797314b2abef46689ae8c2e2a1c48c37392cc3879433b7c421937e692dead 0xcdd38bc8167a679629970b02e8d71f14d93f4a9cfe6e332cc3eef90092b246fe +f863808252088252089400000000000000000000000000000000000000000a80820a95a0ea71a873cc79fc96bcb9c6ffa7d2f0eed37314da7222db561479ec4e4b3e3419a0416258449ed04cdbb135f0bb7b0ac28102b686f4788e58e72314e6edb624ceb2 0x90411bdd02b25c0d1d8c0fe00053330293363c900c1450b65778987aa94bc8ea +f863808252088252089400000000000000000000000000000000000000000a80820a96a0f7a43595fc8fc8532d822719d2484e728f2c278d347bc8e136c2f427edc164f5a0665667568d977c05e7fe4da6047da1f5827499733923f634509be83caf0dd00d 0x0f39ecc965f7c988f671eaae9cd3a6daf8d60335816bd838ca78bab67839cd4b +f863808252088252089400000000000000000000000000000000000000000a80820a95a037af33292325064cd8442b87355ace553aa4fa88fffe9f6a81f20aa7498ceafca033d9f40328974a50a65aea87e836c1b0b0cc15fe0c7e1b66a1da9dc27f0787c4 0xdd865caaf366077ca21e8447a84547e8068e1576e5e80d46443331433c088768 +f863808252088252089400000000000000000000000000000000000000000a80820a96a02ff1f112b7cb35be8896bf5b614b9771fda6958481f9382627f322ec9da84618a02357e2717910d85f8bb4ce923f606c2c99152c80787f37a5400a2464313b80b3 0x5ecfdf62b2cd1b63ce7d698af656f8c279cfac68df71f2a016db45cf73369f14 +f863808252088252089400000000000000000000000000000000000000000a80820a96a05ac61f9c719245bbd010e20e481cc261d896844fcc097699ca5d5ee74d3c8445a07a8e8e81a961f2e9cec97b7c9fd2e68e2c50536abd13078f8811a7d738f2a5b9 0x2cbf9420a875e5c1e6d76f2b46a51b7219f9ea3ab0ead005b82ff277e3a82624 +f863808252088252089400000000000000000000000000000000000000000a80820a96a073b3f3a09ac57a0747b43504c979ad06c1f2b2d087406d34ab1063e50df104a2a001d8193081b44a3ca685f51ab94995a9b99333d9eee38f6edad98dfd3badf7ed 0x56ac198d13e84796fd6ffe2ce8520aa2946b219b6ddaf05a912617c01f124130 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0a046eeec6de2db34a45166c786de808b7f673aea07e409524fbcf6352462be31a0111b4a4996bacb81e42e1694bb4d970ec02c497acfb7ca25df599a82ea19909f 0x5c3e4dc9d576b572addf30bd74e04704fef1590aff18ece2f21fe5fbbbd35b17 +f863808252088252089400000000000000000000000000000000000000000a80820a95a008fc77413cf1e3560e6399d5b14203556a14b6c454f5dc74820b84a71423ba7aa0358680e645cc0f54555ef54fc5088ba125404c57c4c6a1105490c9f7d5fb7415 0xceccc762fbd0d2928f991fafc60415783959b41080f1e9d5cd5522980630d5d9 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0109c18594f04661a9091d220b82fc459820ce3544cefe1b199484c40e78267e1a0432dec390afbbe9d78f1670a08ac1238eeb5d34759bd0699b227798593f81d19 0x84a81fc450786ff8432e63d19b019fc4b0d6b113b179d403d70738c71b891160 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0a22040ebe638e0f55cb3c17c7238b811b5950e36a144cfc9f931b346bb1b330ba035001671572b0b8ba4e4193560e78a6b3a1752b5a558568999e280ddec2ea762 0xcc456d5cc5b9c21c07de399045d08394dcff05c07807562c71fd04e6c5151e93 +f863808252088252089400000000000000000000000000000000000000000a80820a95a02e128fd950289df6bd66e02f487bda8ba5a930dfe50b64b96f8697a27b916fd3a06fbcbafb6e73113a730b333c2c551d69debdfbedce28138e57e31e7bd1e4da5f 0x1fd2e03ed01b2ad971550e7b4812697442867ec7c7d41a57d2cd5fe389bb52c5 +f863808252088252089400000000000000000000000000000000000000000a80820a96a07b85c724d2ee172f7c152fc82c37fa05b359b8caaca072b97f9aec7528a7b11ea066d8549f562e269f56f4c90b7024fa5a5f2205fb01b294b825b17992bb2b10c4 0x19cc8206767c62fdaba9542c96aeec83e1105ca5a5b0197cfd2eb7e9d2560f71 +f863808252088252089400000000000000000000000000000000000000000a80820a95a0a5d3b745b2f9391f861d8cef880a734f99f7a3a0b8e592b5b627c39d74a6abbea076b2aef7127094b45364a2a6eaf1cd6035a8ea2a6b1929b3b1126fa179eea9ff 0xca7df955d2778be8e2645b83fbce2a250bf4a396396da55ccd24a7523cebdb82 +f863808252088252089400000000000000000000000000000000000000000a80820a95a03871424b5b964757b45d0625bb4c40b96a9e62ced36a93dee823a23416f8ed5fa063472901c780d2a18c0d23c7da00fdc136253f9c0e10a7777a9c251f204ffc11 0x7dee500bd2ee98b393f9fcbf4edfa6295a5ecd24561959ad8fb9635427532731 +f863808252088252089400000000000000000000000000000000000000000a80820a96a01f822cb54b42aa449b851f6562224915ec2edcc268c62d8dd50dbe1a0da74c4ea00b5bea2f19719716232c0a72d4e6ecd7e9458b36b4c23f4452f8c9b8a2956d84 0x0576ab967f2b2c7415924b6b6435efb241a65de42e6fcf149eb0661c2b07aaeb +f863808252088252089400000000000000000000000000000000000000000a80820a95a0e649447d55dcd63152c105cbe914cddd8381f76e29d5a2dee26a4fd6cd1b948da0109ac9bb1c33df7fe31d3ea85380aad803a5895624dd653054a19c51daed3d9a 0x86ea8174f5b9365e58ed665d69504599d159b1fe1bed0c4685f95b22f51ac781 +f863808252088252089400000000000000000000000000000000000000000a80820a96a0640d19fe7f289f633cc21c9c354a2011c17b443a21912e1ffbcbd9eb6db619f3a02802c397c5e3dc696377e9b09a7098048f649b891ddf746ed27c997c546c2fb3 0x393001e6d0414c1d17055ca0803d99a6cdad1b0a23bc0e5f7c72c53eca0696e4 \ No newline at end of file diff --git a/tezt/tests/evm_rollup.ml b/tezt/tests/evm_rollup.ml index 226ba2e1c14ac7162581e967c494156c00ff55d3..f0b82fc707a82e162c47ee1180c686eadd66b023 100644 --- a/tezt/tests/evm_rollup.ml +++ b/tezt/tests/evm_rollup.ml @@ -2096,15 +2096,21 @@ let send_raw_transaction_request raw_tx = {method_ = "eth_sendRawTransaction"; parameters = `A [`String raw_tx]} let send_raw_transaction proxy_server raw_tx = - let* transaction_hash = + let* response = Evm_proxy_server.call_evm_rpc proxy_server (send_raw_transaction_request raw_tx) in let hash = - transaction_hash |> Evm_proxy_server.extract_result |> JSON.as_string + response |> Evm_proxy_server.extract_result |> JSON.as_string_opt in - return hash + let error_message = + response |> Evm_proxy_server.extract_error_message |> JSON.as_string_opt + in + match (hash, error_message) with + | Some hash, _ -> return (Ok hash) + | _, Some error_code -> return (Error error_code) + | _ -> failwith "invalid response from eth_sendRawTransaction" let test_rpc_sendRawTransaction = Protocol.register_test @@ -2119,6 +2125,7 @@ let test_rpc_sendRawTransaction = Lwt_list.map_p (fun (tx_raw, _) -> let* hash = send_raw_transaction evm_proxy_server tx_raw in + let hash = Result.get_ok hash in return hash) txs in @@ -2333,6 +2340,54 @@ let test_deposit_dailynet = (* Check the balance in the EVM rollup. *) check_balance ~receiver ~endpoint amount_mutez +let test_rpc_sendRawTransaction_nonce_too_low = + Protocol.register_test + ~__FILE__ + ~tags:["evm"; "nonce"] + ~title:"Returns an error if the nonce is too low" + @@ fun protocol -> + let* {evm_proxy_server; sc_rollup_node; node; client; _} = + setup_past_genesis ~admin:None protocol + in + (* Nonce: 0 *) + let raw_tx = + "0xf86c80825208831e8480940000000000000000000000000000000000000000888ac7230489e8000080820a96a038294f867266c767aee6c3b54a0c444368fb8d5e90353219bce1da78de16aea4a018a7d3c58ddb1f6b33bad5dde106843acfbd6467e5df181d22270229dcfdf601" + in + let* result = send_raw_transaction evm_proxy_server raw_tx in + let transaction_hash = Result.get_ok result in + let* _ = + wait_for_application + ~sc_rollup_node + ~node + ~client + (wait_for_transaction_receipt ~evm_proxy_server ~transaction_hash) + () + in + let* result = send_raw_transaction evm_proxy_server raw_tx in + let error_message = Result.get_error result in + Check.( + ((error_message = "Nonce too low.") string) + ~error_msg:"The transaction should fail") ; + unit + +let test_rpc_sendRawTransaction_nonce_too_high = + Protocol.register_test + ~__FILE__ + ~tags:["evm"; "nonce"] + ~title:"Returns an error if the nonce is too high." + @@ fun protocol -> + let* {evm_proxy_server; _} = setup_past_genesis ~admin:None protocol in + (* Nonce: 1 *) + let raw_tx = + "0xf86c01825208831e8480940000000000000000000000000000000000000000888ac7230489e8000080820a95a0a349864bedc9b84aea88cda197e96538c62c242286ead58eb7180a611f850237a01206525ff16ae5b708ee02b362f9b4d7565e0d7e9b4c536d7ef7dec81cda3ac7" + in + let* result = send_raw_transaction evm_proxy_server raw_tx in + let error_message = Result.get_error result in + Check.( + ((error_message = "Nonce too high.") string) + ~error_msg:"The transaction should fail") ; + unit + let test_deposit_before_and_after_migration = Protocol.register_test ~__FILE__ @@ -2466,7 +2521,9 @@ let register_evm_proxy_server ~protocols = test_kernel_upgrade_failing_migration protocols ; test_check_kernel_upgrade_nonce protocols ; test_rpc_sendRawTransaction protocols ; - test_deposit_dailynet protocols + test_deposit_dailynet protocols ; + test_rpc_sendRawTransaction_nonce_too_low protocols ; + test_rpc_sendRawTransaction_nonce_too_high protocols let register ~protocols = register_evm_proxy_server ~protocols ;