From 2895dd87a634fe85b9b5f88a02c1584f8513f3d4 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Tue, 7 Jan 2025 16:23:48 +0100 Subject: [PATCH 01/22] SputnikVM: Cancun configuration --- etherlink/sputnikvm/runtime/src/lib.rs | 61 ++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/etherlink/sputnikvm/runtime/src/lib.rs b/etherlink/sputnikvm/runtime/src/lib.rs index 8809e58f3594..396ce0aa6470 100644 --- a/etherlink/sputnikvm/runtime/src/lib.rs +++ b/etherlink/sputnikvm/runtime/src/lib.rs @@ -288,6 +288,15 @@ pub struct Config { pub has_push0: bool, /// Whether the gasometer is running in estimate mode. pub estimate: bool, + /// Whether the opcode SELFEDESTRUCT is considered deprecated. + /// See [EIP-6780](https://eips.ethereum.org/EIPS/eip-6780) + pub selfdestruct_deprecated: bool, + /// Has transient storage. + pub has_transient_storage: bool, + /// Has mcopy. + pub has_mcopy: bool, + /// Has blob instructions. + pub has_blob_instructions: bool, } impl Config { @@ -342,6 +351,10 @@ impl Config { has_base_fee: false, has_push0: false, estimate: false, + selfdestruct_deprecated: false, + has_transient_storage: false, + has_mcopy: false, + has_blob_instructions: false, } } @@ -396,6 +409,10 @@ impl Config { has_base_fee: false, has_push0: false, estimate: false, + selfdestruct_deprecated: false, + has_transient_storage: false, + has_mcopy: false, + has_blob_instructions: false, } } @@ -419,6 +436,11 @@ impl Config { Self::config_with_derived_values(DerivedConfigInputs::shanghai()) } + /// Cancun hard fork configuration. + pub const fn cancun() -> Config { + Self::config_with_derived_values(DerivedConfigInputs::cancun()) + } + const fn config_with_derived_values(inputs: DerivedConfigInputs) -> Config { let DerivedConfigInputs { gas_storage_read_warm, @@ -430,6 +452,10 @@ impl Config { disallow_executable_format, warm_coinbase_address, max_initcode_size, + selfdestruct_deprecated, + has_transient_storage, + has_mcopy, + has_blob_instructions, } = inputs; // See https://eips.ethereum.org/EIPS/eip-2929 @@ -493,6 +519,10 @@ impl Config { has_base_fee, has_push0, estimate: false, + selfdestruct_deprecated, + has_transient_storage, + has_mcopy, + has_blob_instructions, } } } @@ -509,6 +539,10 @@ struct DerivedConfigInputs { disallow_executable_format: bool, warm_coinbase_address: bool, max_initcode_size: Option, + selfdestruct_deprecated: bool, + has_transient_storage: bool, + has_mcopy: bool, + has_blob_instructions: bool, } impl DerivedConfigInputs { @@ -523,6 +557,10 @@ impl DerivedConfigInputs { disallow_executable_format: false, warm_coinbase_address: false, max_initcode_size: None, + selfdestruct_deprecated: false, + has_transient_storage: false, + has_mcopy: false, + has_blob_instructions: false, } } @@ -537,6 +575,10 @@ impl DerivedConfigInputs { disallow_executable_format: true, warm_coinbase_address: false, max_initcode_size: None, + selfdestruct_deprecated: false, + has_transient_storage: false, + has_mcopy: false, + has_blob_instructions: false, } } @@ -551,6 +593,10 @@ impl DerivedConfigInputs { disallow_executable_format: true, warm_coinbase_address: false, max_initcode_size: None, + selfdestruct_deprecated: false, + has_transient_storage: false, + has_mcopy: false, + has_blob_instructions: false, } } @@ -566,6 +612,21 @@ impl DerivedConfigInputs { warm_coinbase_address: true, // 2 * 24576 as per EIP-3860 max_initcode_size: Some(0xC000), + selfdestruct_deprecated: false, + has_transient_storage: false, + has_mcopy: false, + has_blob_instructions: false, + } + } + + const fn cancun() -> Self { + let base = Self::shanghai(); + Self { + selfdestruct_deprecated: true, + has_transient_storage: true, + has_mcopy: true, + has_blob_instructions: true, + ..base } } } -- GitLab From 95791bb9d7d3a646f8899c33658aa689f5fc2c49 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Tue, 4 Mar 2025 11:13:53 +0100 Subject: [PATCH 02/22] SputnikVM/Macro: as_usize_or_revert --- etherlink/sputnikvm/core/src/eval/macros.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/etherlink/sputnikvm/core/src/eval/macros.rs b/etherlink/sputnikvm/core/src/eval/macros.rs index 3fd7a9f6ed05..34c537d58d85 100644 --- a/etherlink/sputnikvm/core/src/eval/macros.rs +++ b/etherlink/sputnikvm/core/src/eval/macros.rs @@ -130,3 +130,13 @@ macro_rules! as_usize_or_fail { $v.as_usize() }}; } + +macro_rules! as_usize_or_revert { + ($value:expr) => {{ + if $value > U256::from(usize::MAX) { + return Control::Exit(crate::ExitReason::Revert(ExitRevert::Reverted)); + } else { + $value.as_usize() + } + }}; +} -- GitLab From 8b3750044cd131a283285917605c798d8acef797 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Tue, 7 Jan 2025 13:46:42 +0100 Subject: [PATCH 03/22] SputnikVM: handle MCOPY instruction (EIP-5656) https://eips.ethereum.org/EIPS/eip-5656 --- etherlink/sputnikvm/core/src/eval/misc.rs | 22 ++++++++++++++++++++++ etherlink/sputnikvm/core/src/eval/mod.rs | 5 +++++ etherlink/sputnikvm/core/src/opcode.rs | 2 ++ 3 files changed, 29 insertions(+) diff --git a/etherlink/sputnikvm/core/src/eval/misc.rs b/etherlink/sputnikvm/core/src/eval/misc.rs index 8271d5f6c6b6..38b4afb10bff 100644 --- a/etherlink/sputnikvm/core/src/eval/misc.rs +++ b/etherlink/sputnikvm/core/src/eval/misc.rs @@ -110,6 +110,28 @@ pub fn mstore8(state: &mut Machine) -> Control { } } +#[inline] +pub fn mcopy(state: &mut Machine) -> Control { + pop_u256!(state, dst, src, len); + + try_or_fail!(state.memory.resize_offset(U256::max(dst, src), len)); + + if len == U256::zero() { + return Control::Continue(1); + } + + let dst = as_usize_or_revert!(dst); + let src = as_usize_or_revert!(src); + let len = as_usize_or_revert!(len); + + let data = state.memory.get(src, len); + + match state.memory.set(dst, &data, None) { + Ok(()) => Control::Continue(1), + Err(e) => Control::Exit(e.into()), + } +} + #[inline] pub fn jump(state: &mut Machine) -> Control { pop_u256!(state, dest); diff --git a/etherlink/sputnikvm/core/src/eval/mod.rs b/etherlink/sputnikvm/core/src/eval/mod.rs index 519f5d92585a..580fba4bf2dc 100644 --- a/etherlink/sputnikvm/core/src/eval/mod.rs +++ b/etherlink/sputnikvm/core/src/eval/mod.rs @@ -160,6 +160,10 @@ fn eval_jump(state: &mut Machine, _opcode: Opcode, _position: usize) -> Control self::misc::jump(state) } +fn eval_mcopy(state: &mut Machine, _opcode: Opcode, _position: usize) -> Control { + self::misc::mcopy(state) +} + fn eval_jumpi(state: &mut Machine, _opcode: Opcode, _position: usize) -> Control { self::misc::jumpi(state) } @@ -492,6 +496,7 @@ pub fn eval(state: &mut Machine, opcode: Opcode, position: usize) -> Control { table[Opcode::MLOAD.as_usize()] = eval_mload as _; table[Opcode::MSTORE.as_usize()] = eval_mstore as _; table[Opcode::MSTORE8.as_usize()] = eval_mstore8 as _; + table[Opcode::MCOPY.as_usize()] = eval_mcopy as _; table[Opcode::JUMP.as_usize()] = eval_jump as _; table[Opcode::JUMPI.as_usize()] = eval_jumpi as _; table[Opcode::PC.as_usize()] = eval_pc as _; diff --git a/etherlink/sputnikvm/core/src/opcode.rs b/etherlink/sputnikvm/core/src/opcode.rs index 15814b0acfb3..5c636f316faf 100644 --- a/etherlink/sputnikvm/core/src/opcode.rs +++ b/etherlink/sputnikvm/core/src/opcode.rs @@ -83,6 +83,8 @@ impl Opcode { pub const MSTORE: Opcode = Opcode(0x52); /// `MSTORE8` pub const MSTORE8: Opcode = Opcode(0x53); + /// `MCOPY` + pub const MCOPY: Opcode = Opcode(0x5e); /// `JUMP` pub const JUMP: Opcode = Opcode(0x56); /// `JUMPI` -- GitLab From 22f169684ac4dc2a93a63c87b115506ea4a32b72 Mon Sep 17 00:00:00 2001 From: Brahima Dibassi Date: Thu, 27 Feb 2025 11:48:00 +0100 Subject: [PATCH 04/22] SputnikVM: MCOPY gasometer Co-authored-by: Rodi-Can Bozman --- etherlink/sputnikvm/gasometer/src/lib.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/etherlink/sputnikvm/gasometer/src/lib.rs b/etherlink/sputnikvm/gasometer/src/lib.rs index ce60a3907f46..765489f16d8f 100644 --- a/etherlink/sputnikvm/gasometer/src/lib.rs +++ b/etherlink/sputnikvm/gasometer/src/lib.rs @@ -536,6 +536,10 @@ pub fn dynamic_opcode_cost( Opcode::CALLDATACOPY | Opcode::CODECOPY => GasCost::VeryLowCopy { len: U256::from_big_endian(&stack.peek(2)?[..]), }, + Opcode::MCOPY if config.has_mcopy => GasCost::VeryLowCopy { + len: U256::from_big_endian(&stack.peek(2)?[..]), + }, + Opcode::MCOPY => GasCost::Invalid(opcode), Opcode::EXP => GasCost::Exp { power: U256::from_big_endian(&stack.peek(1)?[..]), }, @@ -642,10 +646,12 @@ pub fn dynamic_opcode_cost( len: U256::from_big_endian(&stack.peek(1)?[..]), }), - Opcode::CODECOPY | Opcode::CALLDATACOPY | Opcode::RETURNDATACOPY => Some(MemoryCost { - offset: U256::from_big_endian(&stack.peek(0)?[..]), - len: U256::from_big_endian(&stack.peek(2)?[..]), - }), + Opcode::CODECOPY | Opcode::CALLDATACOPY | Opcode::RETURNDATACOPY | Opcode::MCOPY => { + Some(MemoryCost { + offset: U256::from_big_endian(&stack.peek(0)?[..]), + len: U256::from_big_endian(&stack.peek(2)?[..]), + }) + } Opcode::EXTCODECOPY => Some(MemoryCost { offset: U256::from_big_endian(&stack.peek(1)?[..]), -- GitLab From 21c09cf6fe1f30918055daac043e0dd75cc350a3 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Tue, 7 Jan 2025 13:51:01 +0100 Subject: [PATCH 05/22] SputnikVM: extend interface to retrieve block blob base fee (EIP-7516) https://eips.ethereum.org/EIPS/eip-7516 --- etherlink/kernel_evm/evm_execution/src/handler.rs | 4 ++++ etherlink/sputnikvm/core/src/opcode.rs | 2 ++ etherlink/sputnikvm/runtime/src/eval/mod.rs | 1 + etherlink/sputnikvm/runtime/src/eval/system.rs | 8 ++++++++ etherlink/sputnikvm/runtime/src/handler.rs | 2 ++ etherlink/sputnikvm/src/backend/memory.rs | 6 ++++++ etherlink/sputnikvm/src/backend/mod.rs | 2 ++ etherlink/sputnikvm/src/executor/stack/executor.rs | 3 +++ etherlink/sputnikvm/src/executor/stack/memory.rs | 4 ++++ 9 files changed, 32 insertions(+) diff --git a/etherlink/kernel_evm/evm_execution/src/handler.rs b/etherlink/kernel_evm/evm_execution/src/handler.rs index 11c944fb54a4..9332205eb235 100644 --- a/etherlink/kernel_evm/evm_execution/src/handler.rs +++ b/etherlink/kernel_evm/evm_execution/src/handler.rs @@ -2417,6 +2417,10 @@ impl Handler for EvmHandler<'_, Host> { self.block.base_fee_per_gas() } + fn block_blob_base_fee(&self) -> U256 { + todo!() + } + fn block_randomness(&self) -> Option { self.block.prevrandao // Always None } diff --git a/etherlink/sputnikvm/core/src/opcode.rs b/etherlink/sputnikvm/core/src/opcode.rs index 5c636f316faf..b6affd5d5ad7 100644 --- a/etherlink/sputnikvm/core/src/opcode.rs +++ b/etherlink/sputnikvm/core/src/opcode.rs @@ -191,6 +191,8 @@ impl Opcode { pub const SELFBALANCE: Opcode = Opcode(0x47); /// `BASEFEE` pub const BASEFEE: Opcode = Opcode(0x48); + /// `BLOBBASEFEE` + pub const BLOBBASEFEE: Opcode = Opcode(0x4a); /// `ORIGIN` pub const ORIGIN: Opcode = Opcode(0x32); /// `CALLER` diff --git a/etherlink/sputnikvm/runtime/src/eval/mod.rs b/etherlink/sputnikvm/runtime/src/eval/mod.rs index b2965335f97e..f39bcd1ed547 100644 --- a/etherlink/sputnikvm/runtime/src/eval/mod.rs +++ b/etherlink/sputnikvm/runtime/src/eval/mod.rs @@ -59,6 +59,7 @@ pub fn eval(state: &mut Runtime, opcode: Opcode, handler: &mut H) -> Opcode::STATICCALL => system::call(state, CallScheme::StaticCall, handler), Opcode::CHAINID => system::chainid(state, handler), Opcode::BASEFEE => system::base_fee(state, handler), + Opcode::BLOBBASEFEE => system::blob_base_fee(state, handler), _ => handle_other(state, opcode, handler), } } diff --git a/etherlink/sputnikvm/runtime/src/eval/system.rs b/etherlink/sputnikvm/runtime/src/eval/system.rs index 5b5353751035..f8f13d20ed75 100644 --- a/etherlink/sputnikvm/runtime/src/eval/system.rs +++ b/etherlink/sputnikvm/runtime/src/eval/system.rs @@ -90,6 +90,14 @@ pub fn base_fee(runtime: &mut Runtime, handler: &H) -> Control { Control::Continue } +pub fn blob_base_fee(runtime: &mut Runtime, handler: &H) -> Control { + let mut ret = H256::default(); + handler.block_blob_base_fee().to_big_endian(&mut ret[..]); + push!(runtime, ret); + + Control::Continue +} + pub fn extcodesize(runtime: &mut Runtime, handler: &H) -> Control { pop!(runtime, address); push_u256!(runtime, handler.code_size(address.into())); diff --git a/etherlink/sputnikvm/runtime/src/handler.rs b/etherlink/sputnikvm/runtime/src/handler.rs index e87b88d53c66..fb1cf459075c 100644 --- a/etherlink/sputnikvm/runtime/src/handler.rs +++ b/etherlink/sputnikvm/runtime/src/handler.rs @@ -62,6 +62,8 @@ pub trait Handler { fn block_gas_limit(&self) -> U256; /// Environmental block base fee. fn block_base_fee_per_gas(&self) -> U256; + /// Returns the value of the blob base-fee of the current block it is executing in. + fn block_blob_base_fee(&self) -> U256; /// Get environmental chain ID. fn chain_id(&self) -> U256; diff --git a/etherlink/sputnikvm/src/backend/memory.rs b/etherlink/sputnikvm/src/backend/memory.rs index 37e7718b10cd..26cc1d1a400a 100644 --- a/etherlink/sputnikvm/src/backend/memory.rs +++ b/etherlink/sputnikvm/src/backend/memory.rs @@ -31,6 +31,8 @@ pub struct MemoryVicinity { pub block_gas_limit: U256, /// Environmental base fee per gas. pub block_base_fee_per_gas: U256, + /// Environmental blob base fee. + pub block_blob_base_fee: U256, /// Environmental randomness. /// /// In Ethereum, this is the randomness beacon provided by the beacon @@ -125,6 +127,10 @@ impl<'vicinity> Backend for MemoryBackend<'vicinity> { self.vicinity.block_base_fee_per_gas } + fn block_blob_base_fee(&self) -> U256 { + self.vicinity.block_blob_base_fee + } + fn chain_id(&self) -> U256 { self.vicinity.chain_id } diff --git a/etherlink/sputnikvm/src/backend/mod.rs b/etherlink/sputnikvm/src/backend/mod.rs index 7cda7fd1d871..d423c42307c5 100644 --- a/etherlink/sputnikvm/src/backend/mod.rs +++ b/etherlink/sputnikvm/src/backend/mod.rs @@ -72,6 +72,8 @@ pub trait Backend { fn block_gas_limit(&self) -> U256; /// Environmental block base fee. fn block_base_fee_per_gas(&self) -> U256; + /// Returns the value of the blob base-fee of the current block it is executing in. + fn block_blob_base_fee(&self) -> U256; /// Environmental chain ID. fn chain_id(&self) -> U256; diff --git a/etherlink/sputnikvm/src/executor/stack/executor.rs b/etherlink/sputnikvm/src/executor/stack/executor.rs index 480ea3bd43fb..9fd315ed8043 100644 --- a/etherlink/sputnikvm/src/executor/stack/executor.rs +++ b/etherlink/sputnikvm/src/executor/stack/executor.rs @@ -1123,6 +1123,9 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler fn block_base_fee_per_gas(&self) -> U256 { self.state.block_base_fee_per_gas() } + fn block_blob_base_fee(&self) -> U256 { + self.state.block_blob_base_fee() + } fn chain_id(&self) -> U256 { self.state.chain_id() } diff --git a/etherlink/sputnikvm/src/executor/stack/memory.rs b/etherlink/sputnikvm/src/executor/stack/memory.rs index 957b2b3d56d4..711259e83971 100644 --- a/etherlink/sputnikvm/src/executor/stack/memory.rs +++ b/etherlink/sputnikvm/src/executor/stack/memory.rs @@ -436,6 +436,10 @@ impl<'backend, 'config, B: Backend> Backend for MemoryStackState<'backend, 'conf self.backend.block_base_fee_per_gas() } + fn block_blob_base_fee(&self) -> U256 { + self.backend.block_blob_base_fee() + } + fn chain_id(&self) -> U256 { self.backend.chain_id() } -- GitLab From 861ffa443e81f52f0555f20d28abec3684df22e9 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Thu, 27 Feb 2025 11:50:01 +0100 Subject: [PATCH 06/22] SputnikVM: BLOBBASEFEE gasometer --- etherlink/sputnikvm/gasometer/src/consts.rs | 1 + etherlink/sputnikvm/gasometer/src/lib.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/etherlink/sputnikvm/gasometer/src/consts.rs b/etherlink/sputnikvm/gasometer/src/consts.rs index 285a4c1ac8ec..cff87fc60d66 100644 --- a/etherlink/sputnikvm/gasometer/src/consts.rs +++ b/etherlink/sputnikvm/gasometer/src/consts.rs @@ -19,3 +19,4 @@ pub const G_SHA3WORD: u64 = 6; pub const G_COPY: u64 = 3; pub const G_BLOCKHASH: u64 = 20; pub const G_CODEDEPOSIT: u64 = 200; +pub const G_BLOBBASEFEE: u64 = 2; diff --git a/etherlink/sputnikvm/gasometer/src/lib.rs b/etherlink/sputnikvm/gasometer/src/lib.rs index 765489f16d8f..5623b6fe88c5 100644 --- a/etherlink/sputnikvm/gasometer/src/lib.rs +++ b/etherlink/sputnikvm/gasometer/src/lib.rs @@ -477,6 +477,8 @@ pub fn dynamic_opcode_cost( Opcode::BASEFEE if config.has_base_fee => GasCost::Base, Opcode::BASEFEE => GasCost::Invalid(opcode), + Opcode::BLOBBASEFEE if config.has_blob_instructions => GasCost::BlobBaseFee, + Opcode::BLOBBASEFEE => GasCost::Invalid(opcode), Opcode::EXTCODESIZE => { let target = stack.peek(0)?.into(); @@ -841,6 +843,7 @@ impl<'config> Inner<'config> { self.config.gas_ext_code_hash, self.config, ), + GasCost::BlobBaseFee => consts::G_BLOBBASEFEE, }) } @@ -997,6 +1000,8 @@ pub enum GasCost { /// True if target has not been previously accessed in this transaction target_is_cold: bool, }, + /// Gas cost for `BLOBBASEFEE`. + BlobBaseFee, } /// Storage opcode will access. Used for tracking accessed storage (EIP-2929). -- GitLab From 98aae509853ba87bae3b0749002e6306884aa318 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Tue, 7 Jan 2025 14:00:23 +0100 Subject: [PATCH 07/22] EVM/Execution: implement block blob base fee Mainly for consistency with other function of the interface. In the context of our L2, Etherlink, it doesn't really make sense (for now). --- etherlink/kernel_evm/ethereum/src/block.rs | 16 ++++++++++++++++ .../kernel_evm/evm_execution/src/handler.rs | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/etherlink/kernel_evm/ethereum/src/block.rs b/etherlink/kernel_evm/ethereum/src/block.rs index a315867b2551..fa5f117e032f 100644 --- a/etherlink/kernel_evm/ethereum/src/block.rs +++ b/etherlink/kernel_evm/ethereum/src/block.rs @@ -23,6 +23,7 @@ pub struct BlockFees { minimum_base_fee_per_gas: U256, base_fee_per_gas: U256, da_fee_per_byte: U256, + blob_base_fee: U256, } impl BlockFees { @@ -36,6 +37,11 @@ impl BlockFees { minimum_base_fee_per_gas, base_fee_per_gas, da_fee_per_byte, + // Etherlink doesn't support blob as defined by + // EIP-7516. + // As such, the following value will always return + // zero. + blob_base_fee: U256::zero(), } } @@ -56,6 +62,11 @@ impl BlockFees { pub const fn da_fee_per_byte(&self) -> U256 { self.da_fee_per_byte } + + #[inline(always)] + pub const fn blob_base_fee(&self) -> U256 { + self.blob_base_fee + } } /// All data for an Ethereum block. @@ -109,6 +120,11 @@ impl BlockConstants { pub const fn base_fee_per_gas(&self) -> U256 { self.block_fees.base_fee_per_gas } + + #[inline(always)] + pub const fn blob_base_fee(&self) -> U256 { + self.block_fees.blob_base_fee + } } #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/etherlink/kernel_evm/evm_execution/src/handler.rs b/etherlink/kernel_evm/evm_execution/src/handler.rs index 9332205eb235..1f0a8c835590 100644 --- a/etherlink/kernel_evm/evm_execution/src/handler.rs +++ b/etherlink/kernel_evm/evm_execution/src/handler.rs @@ -2418,7 +2418,7 @@ impl Handler for EvmHandler<'_, Host> { } fn block_blob_base_fee(&self) -> U256 { - todo!() + self.block.blob_base_fee() } fn block_randomness(&self) -> Option { -- GitLab From 8cea21859c8f1ad575252095f86c62403ce1be32 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Thu, 27 Feb 2025 11:35:49 +0100 Subject: [PATCH 08/22] SputnikVM: extend interface to retrieve blob hash (EIP-4844) https://eips.ethereum.org/EIPS/eip-4844 --- etherlink/kernel_evm/evm_execution/src/handler.rs | 4 ++++ etherlink/sputnikvm/core/src/opcode.rs | 2 ++ etherlink/sputnikvm/runtime/src/eval/mod.rs | 1 + etherlink/sputnikvm/runtime/src/eval/system.rs | 8 ++++++++ etherlink/sputnikvm/runtime/src/handler.rs | 2 ++ etherlink/sputnikvm/src/backend/memory.rs | 13 ++++++++++++- etherlink/sputnikvm/src/backend/mod.rs | 2 ++ etherlink/sputnikvm/src/executor/stack/executor.rs | 3 +++ etherlink/sputnikvm/src/executor/stack/memory.rs | 4 ++++ 9 files changed, 38 insertions(+), 1 deletion(-) diff --git a/etherlink/kernel_evm/evm_execution/src/handler.rs b/etherlink/kernel_evm/evm_execution/src/handler.rs index 1f0a8c835590..d9dc36da6dfb 100644 --- a/etherlink/kernel_evm/evm_execution/src/handler.rs +++ b/etherlink/kernel_evm/evm_execution/src/handler.rs @@ -2417,6 +2417,10 @@ impl Handler for EvmHandler<'_, Host> { self.block.base_fee_per_gas() } + fn blob_hash(&self, _index: H256) -> H256 { + todo!() + } + fn block_blob_base_fee(&self) -> U256 { self.block.blob_base_fee() } diff --git a/etherlink/sputnikvm/core/src/opcode.rs b/etherlink/sputnikvm/core/src/opcode.rs index b6affd5d5ad7..13c3d60dd916 100644 --- a/etherlink/sputnikvm/core/src/opcode.rs +++ b/etherlink/sputnikvm/core/src/opcode.rs @@ -191,6 +191,8 @@ impl Opcode { pub const SELFBALANCE: Opcode = Opcode(0x47); /// `BASEFEE` pub const BASEFEE: Opcode = Opcode(0x48); + /// `BLOBHASH` + pub const BLOBHASH: Opcode = Opcode(0x49); /// `BLOBBASEFEE` pub const BLOBBASEFEE: Opcode = Opcode(0x4a); /// `ORIGIN` diff --git a/etherlink/sputnikvm/runtime/src/eval/mod.rs b/etherlink/sputnikvm/runtime/src/eval/mod.rs index f39bcd1ed547..61b576c44105 100644 --- a/etherlink/sputnikvm/runtime/src/eval/mod.rs +++ b/etherlink/sputnikvm/runtime/src/eval/mod.rs @@ -59,6 +59,7 @@ pub fn eval(state: &mut Runtime, opcode: Opcode, handler: &mut H) -> Opcode::STATICCALL => system::call(state, CallScheme::StaticCall, handler), Opcode::CHAINID => system::chainid(state, handler), Opcode::BASEFEE => system::base_fee(state, handler), + Opcode::BLOBHASH => system::blob_hash(state, handler), Opcode::BLOBBASEFEE => system::blob_base_fee(state, handler), _ => handle_other(state, opcode, handler), } diff --git a/etherlink/sputnikvm/runtime/src/eval/system.rs b/etherlink/sputnikvm/runtime/src/eval/system.rs index f8f13d20ed75..c50008169bd9 100644 --- a/etherlink/sputnikvm/runtime/src/eval/system.rs +++ b/etherlink/sputnikvm/runtime/src/eval/system.rs @@ -90,6 +90,14 @@ pub fn base_fee(runtime: &mut Runtime, handler: &H) -> Control { Control::Continue } +pub fn blob_hash(runtime: &mut Runtime, handler: &H) -> Control { + pop!(runtime, index); + let ret = handler.blob_hash(index); + push!(runtime, ret); + + Control::Continue +} + pub fn blob_base_fee(runtime: &mut Runtime, handler: &H) -> Control { let mut ret = H256::default(); handler.block_blob_base_fee().to_big_endian(&mut ret[..]); diff --git a/etherlink/sputnikvm/runtime/src/handler.rs b/etherlink/sputnikvm/runtime/src/handler.rs index fb1cf459075c..ff42bd0ec963 100644 --- a/etherlink/sputnikvm/runtime/src/handler.rs +++ b/etherlink/sputnikvm/runtime/src/handler.rs @@ -62,6 +62,8 @@ pub trait Handler { fn block_gas_limit(&self) -> U256; /// Environmental block base fee. fn block_base_fee_per_gas(&self) -> U256; + /// Returns the value of the blob versioned hash at index i. + fn blob_hash(&self, index: H256) -> H256; /// Returns the value of the blob base-fee of the current block it is executing in. fn block_blob_base_fee(&self) -> U256; /// Get environmental chain ID. diff --git a/etherlink/sputnikvm/src/backend/memory.rs b/etherlink/sputnikvm/src/backend/memory.rs index 26cc1d1a400a..5574e01cd5f9 100644 --- a/etherlink/sputnikvm/src/backend/memory.rs +++ b/etherlink/sputnikvm/src/backend/memory.rs @@ -63,15 +63,21 @@ pub struct MemoryAccount { pub struct MemoryBackend<'vicinity> { vicinity: &'vicinity MemoryVicinity, state: BTreeMap, + blob_hashes: BTreeMap, logs: Vec, } impl<'vicinity> MemoryBackend<'vicinity> { /// Create a new memory backend. - pub fn new(vicinity: &'vicinity MemoryVicinity, state: BTreeMap) -> Self { + pub fn new( + vicinity: &'vicinity MemoryVicinity, + state: BTreeMap, + blob_hashes: BTreeMap, + ) -> Self { Self { vicinity, state, + blob_hashes, logs: Vec::new(), } } @@ -123,6 +129,11 @@ impl<'vicinity> Backend for MemoryBackend<'vicinity> { fn block_gas_limit(&self) -> U256 { self.vicinity.block_gas_limit } + + fn blob_hash(&self, index: H256) -> H256 { + self.blob_hashes.get(&index).copied().unwrap_or_default() + } + fn block_base_fee_per_gas(&self) -> U256 { self.vicinity.block_base_fee_per_gas } diff --git a/etherlink/sputnikvm/src/backend/mod.rs b/etherlink/sputnikvm/src/backend/mod.rs index d423c42307c5..d4c27de87ea7 100644 --- a/etherlink/sputnikvm/src/backend/mod.rs +++ b/etherlink/sputnikvm/src/backend/mod.rs @@ -70,6 +70,8 @@ pub trait Backend { fn block_randomness(&self) -> Option; /// Environmental block gas limit. fn block_gas_limit(&self) -> U256; + /// Environmental blob hash at index. + fn blob_hash(&self, index: H256) -> H256; /// Environmental block base fee. fn block_base_fee_per_gas(&self) -> U256; /// Returns the value of the blob base-fee of the current block it is executing in. diff --git a/etherlink/sputnikvm/src/executor/stack/executor.rs b/etherlink/sputnikvm/src/executor/stack/executor.rs index 9fd315ed8043..f1a1e1e50395 100644 --- a/etherlink/sputnikvm/src/executor/stack/executor.rs +++ b/etherlink/sputnikvm/src/executor/stack/executor.rs @@ -1120,6 +1120,9 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler fn block_gas_limit(&self) -> U256 { self.state.block_gas_limit() } + fn blob_hash(&self, index: H256) -> H256 { + self.state.blob_hash(index) + } fn block_base_fee_per_gas(&self) -> U256 { self.state.block_base_fee_per_gas() } diff --git a/etherlink/sputnikvm/src/executor/stack/memory.rs b/etherlink/sputnikvm/src/executor/stack/memory.rs index 711259e83971..364947cafc7a 100644 --- a/etherlink/sputnikvm/src/executor/stack/memory.rs +++ b/etherlink/sputnikvm/src/executor/stack/memory.rs @@ -436,6 +436,10 @@ impl<'backend, 'config, B: Backend> Backend for MemoryStackState<'backend, 'conf self.backend.block_base_fee_per_gas() } + fn blob_hash(&self, index: H256) -> H256 { + self.backend.blob_hash(index) + } + fn block_blob_base_fee(&self) -> U256 { self.backend.block_blob_base_fee() } -- GitLab From 27996888a9693d66542c200f25b63137b44a903f Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Thu, 27 Feb 2025 11:50:36 +0100 Subject: [PATCH 09/22] SputnikVM: BLOBHASH gasometer --- etherlink/sputnikvm/gasometer/src/consts.rs | 1 + etherlink/sputnikvm/gasometer/src/lib.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/etherlink/sputnikvm/gasometer/src/consts.rs b/etherlink/sputnikvm/gasometer/src/consts.rs index cff87fc60d66..addc1b4bbf9f 100644 --- a/etherlink/sputnikvm/gasometer/src/consts.rs +++ b/etherlink/sputnikvm/gasometer/src/consts.rs @@ -19,4 +19,5 @@ pub const G_SHA3WORD: u64 = 6; pub const G_COPY: u64 = 3; pub const G_BLOCKHASH: u64 = 20; pub const G_CODEDEPOSIT: u64 = 200; +pub const G_BLOBHASH: u64 = 3; pub const G_BLOBBASEFEE: u64 = 2; diff --git a/etherlink/sputnikvm/gasometer/src/lib.rs b/etherlink/sputnikvm/gasometer/src/lib.rs index 5623b6fe88c5..330dd0b01ad2 100644 --- a/etherlink/sputnikvm/gasometer/src/lib.rs +++ b/etherlink/sputnikvm/gasometer/src/lib.rs @@ -477,6 +477,8 @@ pub fn dynamic_opcode_cost( Opcode::BASEFEE if config.has_base_fee => GasCost::Base, Opcode::BASEFEE => GasCost::Invalid(opcode), + Opcode::BLOBHASH if config.has_blob_instructions => GasCost::BlobHash, + Opcode::BLOBHASH => GasCost::Invalid(opcode), Opcode::BLOBBASEFEE if config.has_blob_instructions => GasCost::BlobBaseFee, Opcode::BLOBBASEFEE => GasCost::Invalid(opcode), @@ -843,6 +845,7 @@ impl<'config> Inner<'config> { self.config.gas_ext_code_hash, self.config, ), + GasCost::BlobHash => consts::G_BLOBHASH, GasCost::BlobBaseFee => consts::G_BLOBBASEFEE, }) } @@ -1000,6 +1003,8 @@ pub enum GasCost { /// True if target has not been previously accessed in this transaction target_is_cold: bool, }, + /// Gas cost for `BLOBHASH`. + BlobHash, /// Gas cost for `BLOBBASEFEE`. BlobBaseFee, } -- GitLab From 0ca1eb045a859323e3a46121efa68c704095cd8e Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Thu, 27 Feb 2025 11:37:28 +0100 Subject: [PATCH 10/22] EVM/Execution: implement blob hash Mainly for consistency with other function of the interface. In the context of our L2, Etherlink, it doesn't really make sense (for now). --- etherlink/kernel_evm/evm_execution/src/handler.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/etherlink/kernel_evm/evm_execution/src/handler.rs b/etherlink/kernel_evm/evm_execution/src/handler.rs index d9dc36da6dfb..7ad98869aa8c 100644 --- a/etherlink/kernel_evm/evm_execution/src/handler.rs +++ b/etherlink/kernel_evm/evm_execution/src/handler.rs @@ -2418,7 +2418,11 @@ impl Handler for EvmHandler<'_, Host> { } fn blob_hash(&self, _index: H256) -> H256 { - todo!() + // Etherlink doesn't support blob as defined by + // EIP-4844 (Proto-Danksharding). + // As such, the following value will always return + // zero. + H256::zero() } fn block_blob_base_fee(&self) -> U256 { -- GitLab From 8bb296bba865bcb794ce623a0e21f48266d24fd6 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Wed, 5 Mar 2025 15:48:15 +0100 Subject: [PATCH 11/22] EVM/Execution: kzg_point_evaluation precompile contract --- .../evm_execution/src/precompiles/mod.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/etherlink/kernel_evm/evm_execution/src/precompiles/mod.rs b/etherlink/kernel_evm/evm_execution/src/precompiles/mod.rs index f11eeee487fe..6bfa71fa7367 100644 --- a/etherlink/kernel_evm/evm_execution/src/precompiles/mod.rs +++ b/etherlink/kernel_evm/evm_execution/src/precompiles/mod.rs @@ -29,6 +29,7 @@ use crate::EthereumError; use alloc::collections::btree_map::BTreeMap; use blake2::blake2f_precompile; use ecdsa::ecrecover_precompile; +use evm::executor::stack::PrecompileFailure; use evm::{Context, ExitReason, Handler, Transfer}; use fa_bridge::fa_bridge_precompile; use hash::{ripemd160_precompile, sha256_precompile}; @@ -162,6 +163,21 @@ pub const WITHDRAWAL_ADDRESS: H160 = H160([ 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ]); +// This precompile is part of EIP-4844 which we don't support +// on Etherlink, as they are related to blobs. +// See: https://eips.ethereum.org/EIPS/eip-4844#point-evaluation-precompile +fn kzg_point_evaluation( + _handler: &mut EvmHandler, + _input: &[u8], + _context: &Context, + _is_static: bool, + _transfer: Option, +) -> Result { + Err(EthereumError::PrecompileFailed(PrecompileFailure::Fatal { + exit_status: evm::ExitFatal::NotSupported, + })) +} + pub fn evm_precompile_set() -> PrecompileBTreeMap { BTreeMap::from([ ( @@ -200,6 +216,10 @@ pub fn evm_precompile_set() -> PrecompileBTreeMap { H160::from_low_u64_be(9u64), blake2f_precompile as PrecompileFn, ), + ( + H160::from_low_u64_be(10u64), + kzg_point_evaluation as PrecompileFn, + ), ]) } -- GitLab From 4bc9da1c9938f72f4307f8c7daa63a6a71631ca7 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Tue, 7 Jan 2025 13:44:59 +0100 Subject: [PATCH 12/22] SputnikVM: extend interface to introduce transient storage (EIP-1153) https://eips.ethereum.org/EIPS/eip-1153 --- .../kernel_evm/evm_execution/src/handler.rs | 13 +++++++++ etherlink/sputnikvm/core/src/opcode.rs | 4 +++ etherlink/sputnikvm/runtime/src/eval/mod.rs | 2 ++ .../sputnikvm/runtime/src/eval/system.rs | 29 +++++++++++++++++++ etherlink/sputnikvm/runtime/src/handler.rs | 9 ++++++ etherlink/sputnikvm/runtime/src/tracing.rs | 10 +++++++ etherlink/sputnikvm/src/backend/memory.rs | 10 +++++++ etherlink/sputnikvm/src/backend/mod.rs | 2 ++ .../sputnikvm/src/executor/stack/executor.rs | 15 ++++++++++ .../sputnikvm/src/executor/stack/memory.rs | 29 +++++++++++++++++++ 10 files changed, 123 insertions(+) diff --git a/etherlink/kernel_evm/evm_execution/src/handler.rs b/etherlink/kernel_evm/evm_execution/src/handler.rs index 7ad98869aa8c..a5bd28b4a6f0 100644 --- a/etherlink/kernel_evm/evm_execution/src/handler.rs +++ b/etherlink/kernel_evm/evm_execution/src/handler.rs @@ -2345,6 +2345,10 @@ impl Handler for EvmHandler<'_, Host> { cached_storage_access(self, address, index, layer) } + fn transient_storage(&self, address: H160, index: H256) -> H256 { + todo!() + } + fn original_storage(&mut self, address: H160, index: H256) -> H256 { let key = StorageKey { address, index }; if let Some(value) = self.original_storage_cache.get(&key) { @@ -2496,6 +2500,15 @@ impl Handler for EvmHandler<'_, Host> { Ok(()) } + fn set_transient_storage( + &mut self, + address: H160, + index: H256, + value: H256, + ) -> Result<(), ExitError> { + todo!() + } + fn log( &mut self, address: H160, diff --git a/etherlink/sputnikvm/core/src/opcode.rs b/etherlink/sputnikvm/core/src/opcode.rs index 13c3d60dd916..67f8dafd6ec3 100644 --- a/etherlink/sputnikvm/core/src/opcode.rs +++ b/etherlink/sputnikvm/core/src/opcode.rs @@ -229,6 +229,10 @@ impl Opcode { pub const SLOAD: Opcode = Opcode(0x54); /// `SSTORE` pub const SSTORE: Opcode = Opcode(0x55); + /// `TLOAD` + pub const TLOAD: Opcode = Opcode(0x5c); + /// `TSTORE` + pub const TSTORE: Opcode = Opcode(0x5d); /// `GAS` pub const GAS: Opcode = Opcode(0x5a); /// `LOGn` diff --git a/etherlink/sputnikvm/runtime/src/eval/mod.rs b/etherlink/sputnikvm/runtime/src/eval/mod.rs index 61b576c44105..4421a4027b6d 100644 --- a/etherlink/sputnikvm/runtime/src/eval/mod.rs +++ b/etherlink/sputnikvm/runtime/src/eval/mod.rs @@ -44,6 +44,8 @@ pub fn eval(state: &mut Runtime, opcode: Opcode, handler: &mut H) -> Opcode::GASLIMIT => system::gaslimit(state, handler), Opcode::SLOAD => system::sload(state, handler), Opcode::SSTORE => system::sstore(state, handler), + Opcode::TLOAD => system::tload(state, handler), + Opcode::TSTORE => system::tstore(state, handler), Opcode::GAS => system::gas(state, handler), Opcode::LOG0 => system::log(state, 0, handler), Opcode::LOG1 => system::log(state, 1, handler), diff --git a/etherlink/sputnikvm/runtime/src/eval/system.rs b/etherlink/sputnikvm/runtime/src/eval/system.rs index c50008169bd9..7e8f2ff4e108 100644 --- a/etherlink/sputnikvm/runtime/src/eval/system.rs +++ b/etherlink/sputnikvm/runtime/src/eval/system.rs @@ -244,6 +244,35 @@ pub fn sstore(runtime: &mut Runtime, handler: &mut H) -> Control } } +pub fn tload(runtime: &mut Runtime, handler: &H) -> Control { + pop!(runtime, index); + let value = handler.transient_storage(runtime.context.address, index); + push!(runtime, value); + + event!(TLoad { + address: runtime.context.address, + index, + value + }); + + Control::Continue +} + +pub fn tstore(runtime: &mut Runtime, handler: &mut H) -> Control { + pop!(runtime, index, value); + + event!(TStore { + address: runtime.context.address, + index, + value + }); + + match handler.set_transient_storage(runtime.context.address, index, value) { + Ok(()) => Control::Continue, + Err(e) => Control::Exit(e.into()), + } +} + pub fn gas(runtime: &mut Runtime, handler: &H) -> Control { push_u256!(runtime, handler.gas_left()); diff --git a/etherlink/sputnikvm/runtime/src/handler.rs b/etherlink/sputnikvm/runtime/src/handler.rs index ff42bd0ec963..78b4bd50c831 100644 --- a/etherlink/sputnikvm/runtime/src/handler.rs +++ b/etherlink/sputnikvm/runtime/src/handler.rs @@ -37,6 +37,8 @@ pub trait Handler { fn code(&self, address: H160) -> Vec; /// Get storage value of address at index. fn storage(&mut self, address: H160, index: H256) -> H256; + /// Get transient storage value of address at index. + fn transient_storage(&self, address: H160, index: H256) -> H256; /// Get original storage value of address at index. fn original_storage(&mut self, address: H160, index: H256) -> H256; @@ -83,6 +85,13 @@ pub trait Handler { /// Set storage value of address at index. fn set_storage(&mut self, address: H160, index: H256, value: H256) -> Result<(), ExitError>; + /// Set transient storage value of address at index. + fn set_transient_storage( + &mut self, + address: H160, + index: H256, + value: H256, + ) -> Result<(), ExitError>; /// Create a log owned by address with given topics and data. fn log(&mut self, address: H160, topics: Vec, data: Vec) -> Result<(), ExitError>; /// Mark an address to be deleted, with funds transferred to target. diff --git a/etherlink/sputnikvm/runtime/src/tracing.rs b/etherlink/sputnikvm/runtime/src/tracing.rs index f9fed1961f83..c502bfb66147 100644 --- a/etherlink/sputnikvm/runtime/src/tracing.rs +++ b/etherlink/sputnikvm/runtime/src/tracing.rs @@ -32,6 +32,16 @@ pub enum Event<'a> { index: H256, value: H256, }, + TLoad { + address: H160, + index: H256, + value: H256, + }, + TStore { + address: H160, + index: H256, + value: H256, + }, } // Expose `listener::with` to the crate only. diff --git a/etherlink/sputnikvm/src/backend/memory.rs b/etherlink/sputnikvm/src/backend/memory.rs index 5574e01cd5f9..353750e64e25 100644 --- a/etherlink/sputnikvm/src/backend/memory.rs +++ b/etherlink/sputnikvm/src/backend/memory.rs @@ -64,6 +64,7 @@ pub struct MemoryBackend<'vicinity> { vicinity: &'vicinity MemoryVicinity, state: BTreeMap, blob_hashes: BTreeMap, + transient_state: BTreeMap<(H160, H256), H256>, logs: Vec, } @@ -73,11 +74,13 @@ impl<'vicinity> MemoryBackend<'vicinity> { vicinity: &'vicinity MemoryVicinity, state: BTreeMap, blob_hashes: BTreeMap, + transient_state: BTreeMap<(H160, H256), H256>, ) -> Self { Self { vicinity, state, blob_hashes, + transient_state, logs: Vec::new(), } } @@ -174,6 +177,13 @@ impl<'vicinity> Backend for MemoryBackend<'vicinity> { .unwrap_or_default() } + fn transient_storage(&self, address: H160, index: H256) -> H256 { + self.transient_state + .get(&(address, index)) + .cloned() + .unwrap_or_default() + } + fn original_storage(&self, address: H160, index: H256) -> Option { Some(self.storage(address, index)) } diff --git a/etherlink/sputnikvm/src/backend/mod.rs b/etherlink/sputnikvm/src/backend/mod.rs index d4c27de87ea7..c9bb01200fc2 100644 --- a/etherlink/sputnikvm/src/backend/mod.rs +++ b/etherlink/sputnikvm/src/backend/mod.rs @@ -87,6 +87,8 @@ pub trait Backend { fn code(&self, address: H160) -> Vec; /// Get storage value of address at index. fn storage(&self, address: H160, index: H256) -> H256; + /// Get transient storage value of address at index. + fn transient_storage(&self, address: H160, index: H256) -> H256; /// Get original storage value of address at index, if available. fn original_storage(&self, address: H160, index: H256) -> Option; } diff --git a/etherlink/sputnikvm/src/executor/stack/executor.rs b/etherlink/sputnikvm/src/executor/stack/executor.rs index f1a1e1e50395..3364e470e40d 100644 --- a/etherlink/sputnikvm/src/executor/stack/executor.rs +++ b/etherlink/sputnikvm/src/executor/stack/executor.rs @@ -206,6 +206,7 @@ pub trait StackState<'config>: Backend { fn inc_nonce(&mut self, address: H160) -> Result<(), ExitError>; fn set_storage(&mut self, address: H160, key: H256, value: H256); + fn set_transient_storage(&mut self, address: H160, key: H256, value: H256); fn reset_storage(&mut self, address: H160); fn log(&mut self, address: H160, topics: Vec, data: Vec); fn set_deleted(&mut self, address: H160); @@ -1049,6 +1050,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler self.state.storage(address, index) } + fn transient_storage(&self, address: H160, index: H256) -> H256 { + self.state.transient_storage(address, index) + } + fn original_storage(&mut self, address: H160, index: H256) -> H256 { self.state .original_storage(address, index) @@ -1142,6 +1147,16 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler Ok(()) } + fn set_transient_storage( + &mut self, + address: H160, + index: H256, + value: H256, + ) -> Result<(), ExitError> { + self.state.set_transient_storage(address, index, value); + Ok(()) + } + fn log(&mut self, address: H160, topics: Vec, data: Vec) -> Result<(), ExitError> { self.state.log(address, topics, data); Ok(()) diff --git a/etherlink/sputnikvm/src/executor/stack/memory.rs b/etherlink/sputnikvm/src/executor/stack/memory.rs index 364947cafc7a..26f193a67f6e 100644 --- a/etherlink/sputnikvm/src/executor/stack/memory.rs +++ b/etherlink/sputnikvm/src/executor/stack/memory.rs @@ -23,6 +23,7 @@ pub struct MemoryStackSubstate<'config> { logs: Vec, accounts: BTreeMap, storages: BTreeMap<(H160, H256), H256>, + transient_storages: BTreeMap<(H160, H256), H256>, deletes: BTreeSet, } @@ -34,6 +35,7 @@ impl<'config> MemoryStackSubstate<'config> { logs: Vec::new(), accounts: BTreeMap::new(), storages: BTreeMap::new(), + transient_storages: BTreeMap::new(), deletes: BTreeSet::new(), } } @@ -119,6 +121,7 @@ impl<'config> MemoryStackSubstate<'config> { logs: Vec::new(), accounts: BTreeMap::new(), storages: BTreeMap::new(), + transient_storages: BTreeMap::new(), deletes: BTreeSet::new(), }; mem::swap(&mut entering, self); @@ -232,6 +235,18 @@ impl<'config> MemoryStackSubstate<'config> { None } + pub fn known_transient_storage(&self, address: H160, key: H256) -> Option { + if let Some(value) = self.transient_storages.get(&(address, key)) { + return Some(*value); + } + + if let Some(parent) = self.parent.as_ref() { + return parent.known_transient_storage(address, key); + } + + None + } + pub fn known_original_storage(&self, address: H160) -> Option { if let Some(account) = self.accounts.get(&address) { if account.reset { @@ -314,6 +329,10 @@ impl<'config> MemoryStackSubstate<'config> { self.storages.insert((address, key), value); } + pub fn set_transient_storage(&mut self, address: H160, key: H256, value: H256) { + self.transient_storages.insert((address, key), value); + } + pub fn reset_storage(&mut self, address: H160, backend: &B) { let mut removing = Vec::new(); @@ -470,6 +489,12 @@ impl<'backend, 'config, B: Backend> Backend for MemoryStackState<'backend, 'conf .unwrap_or_else(|| self.backend.storage(address, key)) } + fn transient_storage(&self, address: H160, key: H256) -> H256 { + self.substate + .known_transient_storage(address, key) + .unwrap_or_else(|| self.backend.transient_storage(address, key)) + } + fn original_storage(&self, address: H160, key: H256) -> Option { if let Some(value) = self.substate.known_original_storage(address) { return Some(value); @@ -534,6 +559,10 @@ impl<'backend, 'config, B: Backend> StackState<'config> for MemoryStackState<'ba self.substate.set_storage(address, key, value) } + fn set_transient_storage(&mut self, address: H160, key: H256, value: H256) { + self.substate.set_transient_storage(address, key, value) + } + fn reset_storage(&mut self, address: H160) { self.substate.reset_storage(address, self.backend); } -- GitLab From d2fd84081bb1040b3a66e521f4277ac0a3607756 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Thu, 27 Feb 2025 11:50:53 +0100 Subject: [PATCH 13/22] SputnikVM: TSTORE/TLOAD gasometer --- etherlink/sputnikvm/gasometer/src/consts.rs | 2 ++ etherlink/sputnikvm/gasometer/src/lib.rs | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/etherlink/sputnikvm/gasometer/src/consts.rs b/etherlink/sputnikvm/gasometer/src/consts.rs index addc1b4bbf9f..c1c3da2c4096 100644 --- a/etherlink/sputnikvm/gasometer/src/consts.rs +++ b/etherlink/sputnikvm/gasometer/src/consts.rs @@ -19,5 +19,7 @@ pub const G_SHA3WORD: u64 = 6; pub const G_COPY: u64 = 3; pub const G_BLOCKHASH: u64 = 20; pub const G_CODEDEPOSIT: u64 = 200; +pub const G_TLOAD: u64 = 100; +pub const G_TSTORE: u64 = 100; pub const G_BLOBHASH: u64 = 3; pub const G_BLOBBASEFEE: u64 = 2; diff --git a/etherlink/sputnikvm/gasometer/src/lib.rs b/etherlink/sputnikvm/gasometer/src/lib.rs index 330dd0b01ad2..1cf9be9e7759 100644 --- a/etherlink/sputnikvm/gasometer/src/lib.rs +++ b/etherlink/sputnikvm/gasometer/src/lib.rs @@ -584,6 +584,10 @@ pub fn dynamic_opcode_cost( target_is_cold: handler.is_cold(address, Some(index))?, } } + Opcode::TLOAD if config.has_transient_storage => GasCost::TLoad, + Opcode::TLOAD => GasCost::Invalid(opcode), + Opcode::TSTORE if config.has_transient_storage => GasCost::TStore, + Opcode::TSTORE => GasCost::Invalid(opcode), Opcode::LOG0 if !is_static => GasCost::Log { n: 0, len: U256::from_big_endian(&stack.peek(1)?[..]), @@ -845,6 +849,8 @@ impl<'config> Inner<'config> { self.config.gas_ext_code_hash, self.config, ), + GasCost::TLoad => consts::G_TLOAD, + GasCost::TStore => consts::G_TSTORE, GasCost::BlobHash => consts::G_BLOBHASH, GasCost::BlobBaseFee => consts::G_BLOBBASEFEE, }) @@ -1003,6 +1009,10 @@ pub enum GasCost { /// True if target has not been previously accessed in this transaction target_is_cold: bool, }, + /// Gas cost for `TLOAD`. + TLoad, + /// Gas cost for `TSTORE`. + TStore, /// Gas cost for `BLOBHASH`. BlobHash, /// Gas cost for `BLOBBASEFEE`. -- GitLab From 74fd7805e63c5e1af75d4700ce9d21166911bf22 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Tue, 7 Jan 2025 14:38:59 +0100 Subject: [PATCH 14/22] EVM/Execution: implement transient storage --- .../kernel_evm/evm_execution/src/handler.rs | 57 ++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/etherlink/kernel_evm/evm_execution/src/handler.rs b/etherlink/kernel_evm/evm_execution/src/handler.rs index a5bd28b4a6f0..564f58081cd5 100644 --- a/etherlink/kernel_evm/evm_execution/src/handler.rs +++ b/etherlink/kernel_evm/evm_execution/src/handler.rs @@ -361,6 +361,10 @@ impl CacheStorageValue { /// address and an index (StorageKey) to a value (CacheStorageValue). pub type LayerCache = HashMap; +/// A transient layer associates at each address and index (StorageKey) +/// its value (H256). +pub type TransientLayer = HashMap; + /// The storage cache is associating at each layer (usize) its /// own cache (LayerCache). For each slot that is modified or /// read during a call it will be added to the cache in its own @@ -372,6 +376,13 @@ pub type LayerCache = HashMap; // 300_000 × 32B = 9_600_000B = 9.6MB pub type StorageCache = HashMap; +/// The transient storage is a temporary data storage area within the +/// EVM. It is associating at each layer (usize) its own storage map. +/// For each slot that is modified it will be added to the associated +/// layer and map. If the value did not exist, by default we return the +/// default value as specified by EIP-1153. +pub type TransientStorage = HashMap; + /// The implementation of the SputnikVM [Handler] trait pub struct EvmHandler<'a, Host: Runtime> { /// The host @@ -409,6 +420,8 @@ pub struct EvmHandler<'a, Host: Runtime> { /// access storage slots before any transaction happens. /// See: `fn original_storage`. original_storage_cache: LayerCache, + /// Transient storage as specified by EIP-1153. + pub transient_storage: TransientStorage, /// Reentrancy guard prevents circular calls to impure precompiles reentrancy_guard: ReentrancyGuard, } @@ -443,6 +456,7 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { tracer, storage_cache: HashMap::with_capacity(10), original_storage_cache: HashMap::with_capacity(10), + transient_storage: HashMap::with_capacity(10), reentrancy_guard: ReentrancyGuard::new(vec![ WITHDRAWAL_ADDRESS, FA_BRIDGE_PRECOMPILE_ADDRESS, @@ -1753,6 +1767,7 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { let _ = self.transaction_data.pop(); self.storage_cache.clear(); + self.transient_storage.clear(); self.original_storage_cache.clear(); Ok(ExecutionOutcome { @@ -1937,6 +1952,7 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { let gas_refunded = self.gas_refunded(); commit_storage_cache(self, number_of_tx_layer); + commit_transient_storage(self, number_of_tx_layer); self.evm_account_storage .commit_transaction(self.host) @@ -2008,6 +2024,7 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { } self.storage_cache.remove(&number_of_tx_layer); + self.transient_storage.remove(&number_of_tx_layer); self.evm_account_storage .rollback_transaction(self.host) @@ -2264,6 +2281,20 @@ fn commit_storage_cache( } } +fn commit_transient_storage( + handler: &mut EvmHandler<'_, Host>, + current_layer: usize, +) { + let commit_layer = current_layer - 1; + if let Some(t_storage) = handler.transient_storage.remove(¤t_layer) { + if let Some(prev_t_storage) = handler.transient_storage.get_mut(&commit_layer) { + prev_t_storage.extend(t_storage); + } else { + handler.transient_storage.insert(commit_layer, t_storage); + } + } +} + fn cached_storage_access( handler: &mut EvmHandler<'_, Host>, address: H160, @@ -2346,7 +2377,15 @@ impl Handler for EvmHandler<'_, Host> { } fn transient_storage(&self, address: H160, index: H256) -> H256 { - todo!() + let layer = self.evm_account_storage.stack_depth(); + for layer in (0..=layer).rev() { + if let Some(t_storage) = self.transient_storage.get(&layer) { + if let Some(value) = t_storage.get(&StorageKey { address, index }) { + return *value; + } + } + } + H256::zero() } fn original_storage(&mut self, address: H160, index: H256) -> H256 { @@ -2506,7 +2545,21 @@ impl Handler for EvmHandler<'_, Host> { index: H256, value: H256, ) -> Result<(), ExitError> { - todo!() + if self.is_static() { + return Err(ExitError::Other(Cow::from( + "TSTORE cannot be executed inside a static call", + ))); + } + + let layer = self.evm_account_storage.stack_depth(); + if let Some(t_storage) = self.transient_storage.get_mut(&layer) { + t_storage.insert(StorageKey { address, index }, value); + } else { + let mut t_storage = HashMap::new(); + t_storage.insert(StorageKey { address, index }, value); + self.transient_storage.insert(layer, t_storage); + } + Ok(()) } fn log( -- GitLab From 60341dad07114d4ced44cb582fd3a68c92f44e83 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Tue, 4 Mar 2025 14:23:04 +0100 Subject: [PATCH 15/22] EVM/Execution: readapt SELFDESTRUCT to EIP-6780 --- .../evm_execution/src/fa_bridge/mod.rs | 17 +- .../evm_execution/src/fa_bridge/test_utils.rs | 9 +- .../kernel_evm/evm_execution/src/handler.rs | 379 +++++++++++++++--- .../src/precompiles/fa_bridge.rs | 11 +- .../src/transaction_layer_data.rs | 21 +- 5 files changed, 370 insertions(+), 67 deletions(-) diff --git a/etherlink/kernel_evm/evm_execution/src/fa_bridge/mod.rs b/etherlink/kernel_evm/evm_execution/src/fa_bridge/mod.rs index 2c31dc896318..254e4811ab97 100644 --- a/etherlink/kernel_evm/evm_execution/src/fa_bridge/mod.rs +++ b/etherlink/kernel_evm/evm_execution/src/fa_bridge/mod.rs @@ -51,6 +51,7 @@ use crate::{ precompiles::{PrecompileBTreeMap, PrecompileOutcome, SYSTEM_ACCOUNT_ADDRESS}, trace::TracerInput, transaction::TransactionContext, + transaction_layer_data::CallContext, withdrawal_counter::WithdrawalCounter, EthereumError, }; @@ -152,7 +153,13 @@ pub fn execute_fa_deposit<'a, Host: Runtime>( tracer_input, ); - handler.begin_initial_transaction(false, Some(gas_limit))?; + handler.begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + Some(gas_limit), + )?; // It's ok if internal proxy call fails, we will update the ticket table anyways. let ticket_owner = if let Some(proxy) = deposit.proxy { @@ -259,7 +266,13 @@ pub fn execute_fa_withdrawal( }); } - handler.begin_inter_transaction(false, gas_limit)?; + handler.begin_inter_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + gas_limit, + )?; // Execute the withdrawal in the transaction layer and clean it based // on the result. diff --git a/etherlink/kernel_evm/evm_execution/src/fa_bridge/test_utils.rs b/etherlink/kernel_evm/evm_execution/src/fa_bridge/test_utils.rs index 38d874928511..bf5580ad1255 100644 --- a/etherlink/kernel_evm/evm_execution/src/fa_bridge/test_utils.rs +++ b/etherlink/kernel_evm/evm_execution/src/fa_bridge/test_utils.rs @@ -31,6 +31,7 @@ use crate::{ self, precompile_set, FA_BRIDGE_PRECOMPILE_ADDRESS, SYSTEM_ACCOUNT_ADDRESS, }, run_transaction, + transaction_layer_data::CallContext, utilities::keccak256_hash, withdrawal_counter::WITHDRAWAL_COUNTER_PATH, }; @@ -408,7 +409,13 @@ pub fn fa_bridge_precompile_call_withdraw( ); handler - .begin_initial_transaction(false, Some(30_000_000)) + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + Some(30_000_000), + ) .unwrap(); let res = execute_fa_withdrawal(&mut handler, caller, withdrawal); diff --git a/etherlink/kernel_evm/evm_execution/src/handler.rs b/etherlink/kernel_evm/evm_execution/src/handler.rs index 564f58081cd5..21936e60f9a2 100644 --- a/etherlink/kernel_evm/evm_execution/src/handler.rs +++ b/etherlink/kernel_evm/evm_execution/src/handler.rs @@ -24,7 +24,7 @@ use crate::trace::{ StructLoggerInput, TracerInput, }; use crate::transaction::TransactionContext; -use crate::transaction_layer_data::TransactionLayerData; +use crate::transaction_layer_data::{CallContext, TransactionLayerData}; use crate::utilities::create_address_legacy; use crate::EthereumError; use crate::PrecompileSet; @@ -41,7 +41,7 @@ use evm::{ use primitive_types::{H160, H256, U256}; use sha3::{Digest, Keccak256}; use std::cmp::min; -use std::collections::HashMap; +use std::collections::{BTreeSet, HashMap}; use std::fmt::Debug; use tezos_data_encoding::enc::{BinResult, BinWriter}; use tezos_ethereum::block::BlockConstants; @@ -422,6 +422,10 @@ pub struct EvmHandler<'a, Host: Runtime> { original_storage_cache: LayerCache, /// Transient storage as specified by EIP-1153. pub transient_storage: TransientStorage, + /// All the freshly created contracts. + /// It will help identify created contracts within the same transaction + /// accross all the execution layers to help comply with EIP-6780. + pub created_contracts: BTreeSet, /// Reentrancy guard prevents circular calls to impure precompiles reentrancy_guard: ReentrancyGuard, } @@ -457,6 +461,7 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { storage_cache: HashMap::with_capacity(10), original_storage_cache: HashMap::with_capacity(10), transient_storage: HashMap::with_capacity(10), + created_contracts: BTreeSet::new(), reentrancy_guard: ReentrancyGuard::new(vec![ WITHDRAWAL_ADDRESS, FA_BRIDGE_PRECOMPILE_ADDRESS, @@ -707,10 +712,16 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { fn is_static(&self) -> bool { self.transaction_data .last() - .map(|data| data.is_static) + .map(|data| data.call_context.is_static) .unwrap_or(false) } + /// Returns true if [address] was created during the on-going transaction accross + /// all the layers. + fn was_created(&self, address: &H160) -> bool { + self.created_contracts.contains(address) + } + /// Record the base fee part of the transaction cost. We need the SputnikVM /// error code in case this goes wrong, so that's what we return. fn record_base_gas_cost( @@ -1382,7 +1393,13 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { is_static: bool, ) -> Result { self.increment_nonce(caller)?; - self.begin_initial_transaction(is_static, gas_limit)?; + self.begin_initial_transaction( + CallContext { + is_static, + is_creation: false, + }, + gas_limit, + )?; if self.mark_address_as_hot(caller).is_err() { return Err(EthereumError::InconsistentState(Cow::from( @@ -1430,7 +1447,13 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { let address = self.create_address(default_create_scheme)?; self.increment_nonce(caller)?; - self.begin_initial_transaction(false, gas_limit)?; + self.begin_initial_transaction( + CallContext { + is_static: false, + is_creation: true, + }, + gas_limit, + )?; if self.mark_address_as_hot(caller).is_err() { return Err(EthereumError::InconsistentState(Cow::from( @@ -1624,7 +1647,7 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { /// this. pub(crate) fn begin_initial_transaction( &mut self, - is_static: bool, + call_context: CallContext, gas_limit: Option, ) -> Result<(), EthereumError> { let number_of_tx_layer = self.evm_account_storage.stack_depth(); @@ -1646,7 +1669,8 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { } self.transaction_data.push(TransactionLayerData::new( - self.is_static() || is_static, + self.is_static() || call_context.is_static, + call_context.is_creation, gas_limit, self.config, AccessRecord::default(), @@ -1711,6 +1735,10 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { .commit_transaction(self.host) .map_err(EthereumError::from)?; + if let ExecutionResult::ContractDeployed(new_address, _) = result { + self.created_contracts.insert(new_address); + } + Ok(ExecutionOutcome { gas_used, logs: last_layer.logs, @@ -1895,7 +1923,7 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { /// Begin an intermediate transaction pub fn begin_inter_transaction( &mut self, - is_static: bool, + call_context: CallContext, gas_limit: Option, ) -> Result<(), EthereumError> { let number_of_tx_layer = self.evm_account_storage.stack_depth(); @@ -1918,7 +1946,8 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { let accessed_storage_keys = current_top.accessed_storage_keys.clone(); self.transaction_data.push(TransactionLayerData::new( - self.is_static() || is_static, + self.is_static() || call_context.is_static, + call_context.is_creation, gas_limit, self.config, accessed_storage_keys, @@ -2061,7 +2090,7 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { execution_result: Result, ) -> Capture { match execution_result { - Ok((ref exit_reason, _, _)) => match exit_reason { + Ok((ref exit_reason, new_address, _)) => match exit_reason { ExitReason::Succeed(_) => { log!( self.host, @@ -2070,6 +2099,10 @@ impl<'a, Host: Runtime> EvmHandler<'a, Host> { exit_reason ); + if let Some(new_address) = new_address { + self.created_contracts.insert(new_address); + } + if let Err(err) = self.commit_inter_transaction() { log!( self.host, @@ -2326,6 +2359,77 @@ fn cached_storage_access( } } +/// SELFDESTRUCT implementation prior to EIP-6780. +/// See https://eips.ethereum.org/EIPS/eip-6780. +fn mark_delete_legacy( + handler: &mut EvmHandler<'_, Host>, + address: H160, + target: H160, +) -> Result<(), ExitError> { + let new_deletion = match handler.transaction_data.last_mut() { + Some(top_layer) => Ok(top_layer.deleted_contracts.insert(address)), + None => Err(ExitError::Other(Cow::from( + "No transaction data for delete", + ))), + }?; + if new_deletion && address == target { + handler.reset_balance(address).map_err(|_| { + ExitError::Other(Cow::from("Could not reset balance when deleting contract")) + }) + } else if new_deletion { + let balance = handler.balance(address); + + handler + .execute_transfer(address, target, balance) + .map_err(|_| { + ExitError::Other(Cow::from( + "Could not execute transfer on contract delete", + )) + })?; + Ok(()) + } else { + log!(handler.host, Debug, "Contract already marked to delete"); + Ok(()) + } +} + +/// SELFDESTRUCT implementation after EIP-6780. +/// See https://eips.ethereum.org/EIPS/eip-6780. +fn mark_delete_eip6780( + handler: &mut EvmHandler<'_, Host>, + address: H160, + target: H160, +) -> Result<(), ExitError> { + if address != target { + let balance = handler.balance(address); + + handler + .execute_transfer(address, target, balance) + .map_err(|_| { + ExitError::Other(Cow::from( + "Could not execute transfer on contract delete", + )) + })?; + } + + match handler.transaction_data.last_mut() { + Some(top_layer) => { + if top_layer.call_context.is_creation { + top_layer.deleted_contracts.insert(address); + handler.reset_balance(address).map_err(|_| { + ExitError::Other(Cow::from( + "Could not reset balance when deleting contract", + )) + })?; + } + Ok(()) + } + None => Err(ExitError::Other(Cow::from( + "No transaction data for delete", + ))), + } +} + #[allow(unused_variables)] impl Handler for EvmHandler<'_, Host> { type CreateInterrupt = Infallible; @@ -2576,31 +2680,13 @@ impl Handler for EvmHandler<'_, Host> { } fn mark_delete(&mut self, address: H160, target: H160) -> Result<(), ExitError> { - let new_deletion = match self.transaction_data.last_mut() { - Some(top_layer) => Ok(top_layer.deleted_contracts.insert(address)), - None => Err(ExitError::Other(Cow::from( - "No transaction data for delete", - ))), - }?; - if new_deletion && address == target { - self.reset_balance(address).map_err(|_| { - ExitError::Other(Cow::from( - "Could not reset balance when deleting contract", - )) - }) - } else if new_deletion { - let balance = self.balance(address); - - self.execute_transfer(address, target, balance) - .map_err(|_| { - ExitError::Other(Cow::from( - "Could not execute transfer on contract delete", - )) - })?; - Ok(()) + // To comply with EIP-6780, if the opcode is considered not deprecated or if + // the address where the SELFDESTRUCT is called was just created, we keep + // the legacy behavior, otherwise we use the "deprecated" behavior. + if !self.config.selfdestruct_deprecated || self.was_created(&address) { + mark_delete_legacy(self, address, target) } else { - log!(self.host, Debug, "Contract already marked to delete"); - Ok(()) + mark_delete_eip6780(self, address, target) } } @@ -2708,7 +2794,13 @@ impl Handler for EvmHandler<'_, Host> { )); } - match self.begin_inter_transaction(false, gas_limit) { + match self.begin_inter_transaction( + CallContext { + is_static: false, + is_creation: true, + }, + gas_limit, + ) { Ok(()) => { let gas_before = self.gas_used(); let result = self.execute_create( @@ -2853,7 +2945,10 @@ impl Handler for EvmHandler<'_, Host> { } if let Err(err) = self.begin_inter_transaction( - call_scheme == CallScheme::StaticCall, + CallContext { + is_static: call_scheme == CallScheme::StaticCall, + is_creation: false, + }, gas_limit, ) { return Capture::Exit((ethereum_error_to_exit_reason(&err), vec![])); @@ -3258,7 +3353,15 @@ mod test { set_code(&mut handler, &address, code); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call(address, transfer, input, transaction_context); @@ -3352,7 +3455,15 @@ mod test { set_code(&mut handler, &address, code); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call(address, transfer, input, transaction_context); @@ -3447,7 +3558,15 @@ mod test { set_code(&mut handler, &address, code); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call(address, transfer, input.to_vec(), transaction_context); @@ -3542,7 +3661,15 @@ mod test { set_code(&mut handler, &address, code); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call(address, transfer, input.to_vec(), transaction_context); @@ -3607,7 +3734,15 @@ mod test { set_code(&mut handler, &address, code); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call(address, transfer, input, transaction_context); @@ -3662,7 +3797,15 @@ mod test { let expected_address = handler.create_address(create_scheme).unwrap_or_default(); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: true, + }, + None, + ) + .unwrap(); let result = handler.execute_create(caller, value, init_code, expected_address); @@ -3731,7 +3874,15 @@ mod test { ]; let contract_address = handler.create_address(create_scheme).unwrap_or_default(); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: true, + }, + None, + ) + .unwrap(); let result = handler.execute_create(caller, value, initial_code, contract_address); @@ -3799,7 +3950,15 @@ mod test { set_code(&mut handler, &address, code); set_balance(&mut handler, &caller, U256::from(101_u32)); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call(address, transfer, input, transaction_context); @@ -3861,7 +4020,15 @@ mod test { set_code(&mut handler, &address, code); set_balance(&mut handler, &caller, U256::from(99_u32)); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call(address, transfer, input, transaction_context); @@ -3932,7 +4099,15 @@ mod test { set_code(&mut handler, &address, code); set_balance(&mut handler, &caller, U256::from(99_u32)); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call(address, transfer, input, transaction_context); @@ -4028,7 +4203,13 @@ mod test { set_balance(&mut handler, &caller, U256::from(99_u32)); handler - .begin_initial_transaction(false, Some(30000)) + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + Some(30000), + ) .unwrap(); let result = handler.execute_call(address, transfer, input, transaction_context); @@ -4081,7 +4262,15 @@ mod test { set_code(&mut handler, &address, code); set_balance(&mut handler, &caller, U256::from(99_u32)); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call(address, transfer, input, transaction_context); @@ -4146,7 +4335,15 @@ mod test { set_code(&mut handler, &address, code); set_balance(&mut handler, &caller, U256::from(99_u32)); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call(address, transfer, input, transaction_context); @@ -4209,7 +4406,15 @@ mod test { set_code(&mut handler, &target_address, code); set_balance(&mut handler, &caller, U256::from(1000000000000000000u64)); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call(target_address, None, input, transaction_context); @@ -4260,7 +4465,13 @@ mod test { let contract_address = handler.create_address(scheme).unwrap_or_default(); handler - .begin_initial_transaction(false, Some(10000)) + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: true, + }, + Some(10000), + ) .unwrap(); let result = @@ -4337,7 +4548,15 @@ mod test { set_balance(&mut handler, &caller, U256::from(1000_u32)); set_balance(&mut handler, &address_1, U256::from(1000_u32)); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call(address_1, transfer, input, transaction_context); @@ -4492,7 +4711,13 @@ mod test { set_balance(&mut handler, &address_1, U256::from(1000_u32)); handler - .begin_initial_transaction(false, Some(1000000)) + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + Some(1000000), + ) .unwrap(); let result = @@ -4588,7 +4813,13 @@ mod test { set_balance(&mut handler, &address_1, U256::from(1000_u32)); handler - .begin_initial_transaction(false, Some(1000000)) + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + Some(1000000), + ) .unwrap(); let result = @@ -4729,7 +4960,13 @@ mod test { let transfer: Option = None; handler - .begin_initial_transaction(false, Some(1000000)) + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + Some(1000000), + ) .unwrap(); let _ = handler.execute_call(contrac_addr, transfer, input, transaction_context); @@ -4767,11 +5004,23 @@ mod test { ); handler - .begin_initial_transaction(false, Some(150000)) + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + Some(150000), + ) .unwrap(); handler - .begin_inter_transaction(false, Some(150000)) + .begin_inter_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + Some(150000), + ) .unwrap(); let ecmul = H160::from_low_u64_be(7u64); @@ -4912,7 +5161,13 @@ mod test { let initial_code = [1; 49153]; // MAX_INIT_CODE_SIZE + 1 handler - .begin_initial_transaction(false, Some(150000)) + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: true, + }, + Some(150000), + ) .unwrap(); let capture = handler.create( @@ -4960,7 +5215,13 @@ mod test { None, ); - let _ = handler.begin_initial_transaction(false, None); + let _ = handler.begin_initial_transaction( + CallContext { + is_static: false, + is_creation: true, + }, + None, + ); set_balance(&mut handler, &caller, U256::from(1000000000)); set_nonce(&mut handler, &caller, u64::MAX); diff --git a/etherlink/kernel_evm/evm_execution/src/precompiles/fa_bridge.rs b/etherlink/kernel_evm/evm_execution/src/precompiles/fa_bridge.rs index 91f613ff8166..65b412902cfb 100644 --- a/etherlink/kernel_evm/evm_execution/src/precompiles/fa_bridge.rs +++ b/etherlink/kernel_evm/evm_execution/src/precompiles/fa_bridge.rs @@ -176,6 +176,7 @@ mod tests { handler::{EvmHandler, ExecutionOutcome, ExecutionResult}, precompiles::{self, FA_BRIDGE_PRECOMPILE_ADDRESS}, transaction::TransactionContext, + transaction_layer_data::CallContext, utilities::{bigint_to_u256, keccak256_hash}, }; @@ -337,7 +338,15 @@ mod tests { None, ); - handler.begin_initial_transaction(false, None).unwrap(); + handler + .begin_initial_transaction( + CallContext { + is_static: false, + is_creation: false, + }, + None, + ) + .unwrap(); let result = handler.execute_call( FA_BRIDGE_PRECOMPILE_ADDRESS, diff --git a/etherlink/kernel_evm/evm_execution/src/transaction_layer_data.rs b/etherlink/kernel_evm/evm_execution/src/transaction_layer_data.rs index 956892ab3004..4a85dfdf3660 100644 --- a/etherlink/kernel_evm/evm_execution/src/transaction_layer_data.rs +++ b/etherlink/kernel_evm/evm_execution/src/transaction_layer_data.rs @@ -1,5 +1,6 @@ // SPDX-FileCopyrightText: 2022-2023 TriliTech // SPDX-FileCopyrightText: 2023-2024 Nomadic Labs +// SPDX-FileCopyrightText: 2025 Functori // // SPDX-License-Identifier: MIT @@ -11,15 +12,23 @@ use evm::Config; use primitive_types::H160; use std::collections::BTreeSet; +pub struct CallContext { + /// Whether the current transaction is static or not, ie, if the + /// transaction is allowed to update durable storage. + pub is_static: bool, + /// Whether the current transaction is a contract creation or not. + pub is_creation: bool, +} + /// Data related to the current transaction layer pub struct TransactionLayerData<'config> { /// Gasometer for the current transaction layer. If this value is /// `None`, then the current transaction has no gas limit and no /// gas accounting. pub gasometer: Option>, - /// Whether the current transaction is static or not, ie, if the - /// transaction is allowed to update durable storage. - pub is_static: bool, + /// Call context. + /// See `CallContext` for more documentation. + pub call_context: CallContext, /// The log records gathered in this layer of transactions and any /// committed sub layers. pub logs: Vec, @@ -42,13 +51,17 @@ impl<'config> TransactionLayerData<'config> { /// will be no gasometer. pub fn new( is_static: bool, + is_creation: bool, gas_limit: Option, config: &'config Config, accessed_storage_keys: AccessRecord, ) -> Self { TransactionLayerData { gasometer: gas_limit.map(|gl| Gasometer::new(gl, config)), - is_static, + call_context: CallContext { + is_static, + is_creation, + }, logs: vec![], deleted_contracts: BTreeSet::new(), withdrawals: vec![], -- GitLab From ec317a1d42e7c525eb3572f6938fc95e9b013cf7 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Tue, 7 Jan 2025 16:22:40 +0100 Subject: [PATCH 16/22] EVM/Evaluation: activate Cancun in evaluation --- etherlink/kernel_evm/evm_evaluation/src/runner.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/etherlink/kernel_evm/evm_evaluation/src/runner.rs b/etherlink/kernel_evm/evm_evaluation/src/runner.rs index 4b3a9e955356..57639d983e23 100644 --- a/etherlink/kernel_evm/evm_evaluation/src/runner.rs +++ b/etherlink/kernel_evm/evm_evaluation/src/runner.rs @@ -339,6 +339,7 @@ pub fn run_test( for (spec_name, tests) in &unit.post { let config = match spec_name { SpecName::Shanghai => Config::shanghai(), + SpecName::Cancun => Config::cancun(), // TODO: enable future configs when parallelization is enabled. // Other tests are ignored _ => continue, -- GitLab From 5f56a39ede7f64e6753f4e370a3303d1024ca098 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Tue, 4 Mar 2025 10:15:02 +0100 Subject: [PATCH 17/22] EVM/Evaluation: skip irrelevant tests for Etherlink This commit also contain a slight change on the decoding of [resources/skip_data.yml]. The new structure contains the name of the test that is skipped alongside the data associated, so that when we skip it, we make sure that we don't skip another test with the same data by mistake. --- .../kernel_evm/evm_evaluation/Cargo.toml | 2 +- .../evm_evaluation/resources/skip_data.yml | 10 +++- .../kernel_evm/evm_evaluation/src/main.rs | 48 +++++++++++++++++-- .../evm_evaluation/src/models/deserializer.rs | 21 -------- .../evm_evaluation/src/models/mod.rs | 7 ++- .../kernel_evm/evm_evaluation/src/runner.rs | 12 +++-- 6 files changed, 66 insertions(+), 34 deletions(-) diff --git a/etherlink/kernel_evm/evm_evaluation/Cargo.toml b/etherlink/kernel_evm/evm_evaluation/Cargo.toml index 841471ee6386..d670e7e14846 100644 --- a/etherlink/kernel_evm/evm_evaluation/Cargo.toml +++ b/etherlink/kernel_evm/evm_evaluation/Cargo.toml @@ -19,7 +19,7 @@ tezos-smart-rollup-mock.workspace = true tezos-smart-rollup-host.workspace = true tezos-smart-rollup-core.workspace = true -hex.workspace = true +hex = { version = "0.4.3", features = ["serde"] } hex-literal.workspace = true bytes = "1.5" diff --git a/etherlink/kernel_evm/evm_evaluation/resources/skip_data.yml b/etherlink/kernel_evm/evm_evaluation/resources/skip_data.yml index 42c9594145e4..0aa059228b57 100644 --- a/etherlink/kernel_evm/evm_evaluation/resources/skip_data.yml +++ b/etherlink/kernel_evm/evm_evaluation/resources/skip_data.yml @@ -5,4 +5,12 @@ datas: # when we exceed the max init code limit. # Other tests behave in the same way and we're passing them, we are also passing # this test but it expects an exception when it shouldn't. - - 601080600b6000396000f360606040523615610074576000357c010000000000000000000000000000000000000000000000000000000090048063a3b9f3e514610079578063b50345b61461008d578063d4f639ea146100a1578063d9bb316f146100b5578063e22a5d5b146100c9578063f983c0fa146100dd57610074565b610002565b346100025761008b60048050506100f1565b005b346100025761009f6004805050611097565b005b34610002576100b3600480505061203d565b005b34610002576100c76004805050612fe3565b005b34610002576100db6004805050613f89565b005b34610002576100ef6004805050614f2f565b005b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b505660606040523615610074576000357c010000000000000000000000000000000000000000000000000000000090048063a3b9f3e514610079578063b50345b61461008d578063d4f639ea146100a1578063d9bb316f146100b5578063e22a5d5b146100c9578063f983c0fa146100dd57610074565b610002565b346100025761008b60048050506100f1565b005b346100025761009f6004805050611097565b005b34610002576100b3600480505061203d565b005b34610002576100c76004805050612fe3565b005b34610002576100db6004805050613f89565b005b34610002576100ef6004805050614f2f565b005b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b505660606040523615610074576000357c010000000000000000000000000000000000000000000000000000000090048063a3b9f3e514610079578063b50345b61461008d578063d4f639ea146100a1578063d9bb316f146100b5578063e22a5d5b146100c9578063f983c0fa146100dd57610074565b610002565b346100025761008b60048050506100f1565b005b346100025761009f6004805050611097565b005b34610002576100b3600480505061203d565b005b34610002576100c76004805050612fe3565b005b34610002576100db6004805050613f89565b005b34610002576100ef6004805050614f2f565b005b60007310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000 + creationTxInitCodeSizeLimit: + - 601080600b6000396000f360606040523615610074576000357c010000000000000000000000000000000000000000000000000000000090048063a3b9f3e514610079578063b50345b61461008d578063d4f639ea146100a1578063d9bb316f146100b5578063e22a5d5b146100c9578063f983c0fa146100dd57610074565b610002565b346100025761008b60048050506100f1565b005b346100025761009f6004805050611097565b005b34610002576100b3600480505061203d565b005b34610002576100c76004805050612fe3565b005b34610002576100db6004805050613f89565b005b34610002576100ef6004805050614f2f565b005b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b505660606040523615610074576000357c010000000000000000000000000000000000000000000000000000000090048063a3b9f3e514610079578063b50345b61461008d578063d4f639ea146100a1578063d9bb316f146100b5578063e22a5d5b146100c9578063f983c0fa146100dd57610074565b610002565b346100025761008b60048050506100f1565b005b346100025761009f6004805050611097565b005b34610002576100b3600480505061203d565b005b34610002576100c76004805050612fe3565b005b34610002576100db6004805050613f89565b005b34610002576100ef6004805050614f2f565b005b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b50565b6000731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000008905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000000990508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000000109050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000101905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010290508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001039050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000104905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010590508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001069050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000107905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010890508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001099050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000110905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020190508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002029050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000203905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020490508050731000000000000000000000000000000000000205905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000206905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020790508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002089050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000209905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000021090508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003019050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000302905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030390508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003049050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000305905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030690508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003079050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000308905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000030990508050731000000000000000000000000000000000000310905080507310000000000000000000000000000000000003109050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000001905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000290508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000039050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000004905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000590508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000069050805073100000000000000000000000000000000000000790508050731000000000000000000000000000000000000007905080507310000000000000000000000000000000000000089050805073100000000000000000000000000000000000000890508050731000000000000000000000000000000000000009905080507310000000000000000000000000000000000000099050805073100000000000000000000000000000000000001090508050731000000000000000000000000000000000000010905080507310000000000000000000000000000000000001019050805073100000000000000000000000000000000000010190508050731000000000000000000000000000000000000102905080507310000000000000000000000000000000000001029050805073100000000000000000000000000000000000010390508050731000000000000000000000000000000000000103905080507310000000000000000000000000000000000001049050805073100000000000000000000000000000000000010490508050731000000000000000000000000000000000000105905080507310000000000000000000000000000000000001059050805073100000000000000000000000000000000000010690508050731000000000000000000000000000000000000106905080507310000000000000000000000000000000000001079050805073100000000000000000000000000000000000010790508050731000000000000000000000000000000000000108905080507310000000000000000000000000000000000001089050805073100000000000000000000000000000000000010990508050731000000000000000000000000000000000000109905080507310000000000000000000000000000000000001109050805073100000000000000000000000000000000000011090508050731000000000000000000000000000000000000201905080507310000000000000000000000000000000000002019050805073100000000000000000000000000000000000020290508050731000000000000000000000000000000000000202905080507310000000000000000000000000000000000002039050805073100000000000000000000000000000000000020390508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002049050805073100000000000000000000000000000000000020590508050731000000000000000000000000000000000000204905080507310000000000000000000000000000000000002069050805073100000000000000000000000000000000000020690508050731000000000000000000000000000000000000207905080507310000000000000000000000000000000000002079050805073100000000000000000000000000000000000020890508050731000000000000000000000000000000000000208905080507310000000000000000000000000000000000002099050805073100000000000000000000000000000000000020990508050731000000000000000000000000000000000000210905080507310000000000000000000000000000000000002109050805073100000000000000000000000000000000000030190508050731000000000000000000000000000000000000301905080507310000000000000000000000000000000000003029050805073100000000000000000000000000000000000030290508050731000000000000000000000000000000000000303905080507310000000000000000000000000000000000003039050805073100000000000000000000000000000000000030490508050731000000000000000000000000000000000000304905080507310000000000000000000000000000000000003059050805073100000000000000000000000000000000000030590508050731000000000000000000000000000000000000306905080507310000000000000000000000000000000000003069050805073100000000000000000000000000000000000030790508050731000000000000000000000000000000000000307905080507310000000000000000000000000000000000003089050805073100000000000000000000000000000000000030890508050731000000000000000000000000000000000000309905080507310000000000000000000000000000000000003099050805073100000000000000000000000000000000000031090508050731000000000000000000000000000000000000310905080505b505660606040523615610074576000357c010000000000000000000000000000000000000000000000000000000090048063a3b9f3e514610079578063b50345b61461008d578063d4f639ea146100a1578063d9bb316f146100b5578063e22a5d5b146100c9578063f983c0fa146100dd57610074565b610002565b346100025761008b60048050506100f1565b005b346100025761009f6004805050611097565b005b34610002576100b3600480505061203d565b005b34610002576100c76004805050612fe3565b005b34610002576100db6004805050613f89565b005b34610002576100ef6004805050614f2f565b005b60007310000000000000000000000000000000000000019050805073100000000000000000000000000000000000000190508050731000000000000000000000000000000000000002905080507310000000000000000000000000000000000000029050805073100000000000000000000000000000000000000390508050731000000000000000000000000000000000000003905080507310000000000000000000000000000000000000049050805073100000000000000000000000000000000000000490508050731000000000000000000000000000000000000005905080507310000000000000000000000000000000000000059050805073100000000000000000000000000000000000000690508050731000000000000000000000000000000000000006905080507310000000000000000000000000000000000000079050805073100000000000000000000000000000000000 + # The following tests are relying on specific BLOBBASEFEE values which we don't support + # on Etherlink. + opc4ADiffPlaces: + - 693c61390000000000000000000000000000000000000000000000000000000000000000 + - 693c613900000000000000000000000000000000000000000000000000000000000000fd + - 693c613900000000000000000000000000000000000000000000000000000000000000fe + - 693c613900000000000000000000000000000000000000000000000000000000000000ff diff --git a/etherlink/kernel_evm/evm_evaluation/src/main.rs b/etherlink/kernel_evm/evm_evaluation/src/main.rs index 7c04a468867d..8dbe7a712773 100644 --- a/etherlink/kernel_evm/evm_evaluation/src/main.rs +++ b/etherlink/kernel_evm/evm_evaluation/src/main.rs @@ -330,6 +330,21 @@ fn generate_diff( pub fn check_skip(test_file_path: &Path) -> bool { let file_name = test_file_path.file_name().unwrap().to_str().unwrap(); + let test_path = test_file_path.to_str().unwrap(); + + let skip_blob_tests = [ + "stEIP4844-blobtransactions", + "eip7516_blobgasfee", + "eip4844_blobs", + ]; + + // Reason: Etherlink doesn't support blob related features. + if skip_blob_tests + .iter() + .any(|folder| test_path.contains(folder)) + { + return true; + } matches!( file_name, @@ -337,8 +352,18 @@ pub fn check_skip(test_file_path: &Path) -> bool { | "CALLBlake2f_MaxRounds.json" // ✔ | "loopMul.json" // ✔ + // TODO: The two following tests should be investigated. + // Context: bugs were discovered thanks to the more finer-grained + // generated filler files, these bugs existed prior to Cancun. + // They are temporarily skipped and will be fixed seperatly. + // See: https://gitlab.com/tezos/tezos/-/issues/7817. + | "randomStatetestDEFAULT-Tue_07_58_41-15153-575192.json" + | "randomStatetestDEFAULT-Tue_07_58_41-15153-575192_london.json" + // Reason: chainId is tested for ethereum mainnet (1) not for etherlink (1337) | "chainId.json" + | "chainid_1.json" + | "chainid_0.json" // Reason: we temporarily reduce stack limit to 256. | "Call1024PreCalls.json" @@ -380,6 +405,13 @@ pub fn check_skip(test_file_path: &Path) -> bool { | "transactionCosts.json" | "variedContext.json" + // Reason: relying on precompile contract kzg_point_evaluation from + // EIP-4844 which we don't support. + | "value_transfer_gas_calculation_0.json" + | "value_transfer_gas_calculation_1.json" + | "value_transfer_gas_calculation_2.json" + | "value_transfer_gas_calculation_3.json" + // Reason: those test the refund mechanism // see https://gitlab.com/tezos/tezos/-/merge_requests/11835 | "refund_getEtherBack.json" @@ -391,6 +423,14 @@ pub fn check_skip(test_file_path: &Path) -> bool { | "refund50percentCap.json" | "refund600.json" + // Reason: these tests are assuming EIP-7610 is implemented in Cancun. + // The EIP is slated for inclusion in the upcoming Pectra upgrade. + | "RevertInCreateInInit_Paris.json" + | "dynamicAccountOverwriteEmpty_Paris.json" + | "RevertInCreateInInitCreate2Paris.json" + | "create2collisionStorageParis.json" + | "InitCollisionParis.json" + // SKIPPED BECAUSE TESTS ARE EXPECTED TO BE RUNNED VIA AN EXTERNAL CLIENT // Reason: Invalid transaction. The gas limit is set to less than 21000. @@ -453,9 +493,7 @@ pub fn check_skip_parsing(test_file_path: &Path) -> bool { // byte array containing between (0; 32] bytes | "ZeroValue_SUICIDE_ToOneStorageKey.json" | "ValueOverflow.json" - - // Reason: invalid length 0, expected a (both 0x-prefixed or not) hex string or - // byte array containing between (0; 32] bytes + | "ValueOverflowParis.json" | "eqNonConst.json" | "mulmodNonConst.json" | "addmodNonConst.json" @@ -571,7 +609,9 @@ pub fn main() { write_out!(output_file, "WARNING: the specified path [{}] can not be found, data(s) \ that should be skipped will not be and the outcome of the \ evaluation could be erroneous.", skip_data_path.display()); - SkipData { datas: vec![] } + SkipData { + datas: HashMap::new(), + } } }; diff --git a/etherlink/kernel_evm/evm_evaluation/src/models/deserializer.rs b/etherlink/kernel_evm/evm_evaluation/src/models/deserializer.rs index 31ef7319fd0f..95e2be301758 100644 --- a/etherlink/kernel_evm/evm_evaluation/src/models/deserializer.rs +++ b/etherlink/kernel_evm/evm_evaluation/src/models/deserializer.rs @@ -109,27 +109,6 @@ where Ok(Some(H160::from_str(&string).map_err(D::Error::custom)?)) } -pub fn deserialize_vec_str_as_u8_vectors<'de, D>( - deserializer: D, -) -> Result>, D::Error> -where - D: de::Deserializer<'de>, -{ - let strings: Vec = Vec::deserialize(deserializer)?; - - let mut vecs: Vec> = vec![]; - - for string in strings.iter() { - vecs.push( - hex::decode(string.strip_prefix("0x").unwrap_or(string)) - .map_err(D::Error::custom) - .unwrap(), - ) - } - - Ok(vecs) -} - pub fn deserialize_str_as_bytes<'de, D>(deserializer: D) -> Result where D: de::Deserializer<'de>, diff --git a/etherlink/kernel_evm/evm_evaluation/src/models/mod.rs b/etherlink/kernel_evm/evm_evaluation/src/models/mod.rs index 4c218f7bab66..e19df831d032 100644 --- a/etherlink/kernel_evm/evm_evaluation/src/models/mod.rs +++ b/etherlink/kernel_evm/evm_evaluation/src/models/mod.rs @@ -244,10 +244,13 @@ pub struct Env { pub tx: TxEnv, } +#[derive(Clone, Debug, PartialEq, Eq, Deserialize)] +#[serde(transparent)] +pub struct HexBytes(#[serde(with = "hex::serde")] pub Vec); + #[derive(Clone, Debug, PartialEq, Eq, Deserialize)] pub struct SkipData { - #[serde(deserialize_with = "deserialize_vec_str_as_u8_vectors")] - pub datas: Vec>, + pub datas: HashMap>, } #[cfg(test)] diff --git a/etherlink/kernel_evm/evm_evaluation/src/runner.rs b/etherlink/kernel_evm/evm_evaluation/src/runner.rs index 57639d983e23..364beb9a1978 100644 --- a/etherlink/kernel_evm/evm_evaluation/src/runner.rs +++ b/etherlink/kernel_evm/evm_evaluation/src/runner.rs @@ -253,10 +253,12 @@ fn execute_transaction( ) } -fn data_to_skip(data: &[u8], skip_data: &SkipData) -> bool { - for skip_data in skip_data.datas.iter() { - if data == skip_data { - return true; +fn data_to_skip(name: &str, data: &[u8], skip_data: &SkipData) -> bool { + for (skip_name, skip_datas) in skip_data.datas.iter() { + for skip_data in skip_datas { + if data == skip_data.0 && name == skip_name { + return true; + } } } false @@ -381,7 +383,7 @@ pub fn run_test( .unwrap() .clone(); - if data_to_skip(&data, skip_data) { + if data_to_skip(&name, &data, skip_data) { continue; } -- GitLab From 9d9a8228395fa91bc9b4e8ffd0d0d780d0b01cba Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Fri, 7 Mar 2025 13:58:35 +0100 Subject: [PATCH 18/22] EVM/Kernel: enable Cancun on the kernel --- etherlink/kernel_evm/kernel/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etherlink/kernel_evm/kernel/src/lib.rs b/etherlink/kernel_evm/kernel/src/lib.rs index ef13486007cd..9c66c77ef9d6 100644 --- a/etherlink/kernel_evm/kernel/src/lib.rs +++ b/etherlink/kernel_evm/kernel/src/lib.rs @@ -74,7 +74,7 @@ pub const CHAIN_ID: u32 = 1337; /// The configuration for the EVM execution. const CONFIG: Config = Config { - // The current implementation doesn't support Shanghai call stack limit of 256. + // The current implementation doesn't support Cancun call stack limit of 256. // We need to set a lower limit until we have switched to a head-based // recursive calls. // @@ -82,7 +82,7 @@ const CONFIG: Config = Config { // to be reactivated. As well as tests `call_too_deep_not_revert` and // `multiple_call_all_the_way_to_1024` in the evm execution crate. call_stack_limit: 256, - ..Config::shanghai() + ..Config::cancun() }; const KERNEL_VERSION: &str = env!("GIT_HASH"); -- GitLab From e10043b8eb70018a0f2a654013bb583dba8452c5 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Fri, 7 Mar 2025 14:10:07 +0100 Subject: [PATCH 19/22] EVM/Kernel: readapt unit tests for Cancun configuration --- .../evm_execution/src/fa_bridge/test_utils.rs | 16 +++-- .../kernel_evm/evm_execution/src/handler.rs | 70 +++++++++++-------- etherlink/kernel_evm/evm_execution/src/lib.rs | 11 +-- .../src/precompiles/fa_bridge.rs | 8 +-- .../evm_execution/src/precompiles/mod.rs | 4 +- 5 files changed, 64 insertions(+), 45 deletions(-) diff --git a/etherlink/kernel_evm/evm_execution/src/fa_bridge/test_utils.rs b/etherlink/kernel_evm/evm_execution/src/fa_bridge/test_utils.rs index bf5580ad1255..da9bfb85f6b3 100644 --- a/etherlink/kernel_evm/evm_execution/src/fa_bridge/test_utils.rs +++ b/etherlink/kernel_evm/evm_execution/src/fa_bridge/test_utils.rs @@ -62,6 +62,14 @@ const MOCK_WRAPPER_BYTECODE: &[u8] = const REENTRANCY_TESTER_BYTECODE: &[u8] = include_bytes!("../../tests/contracts/artifacts/ReentrancyTester.bytecode"); +pub const CONFIG: Config = Config { + // The current implementation doesn't support Cancun call + // stack limit of 256. We need to set a lower limit until we + // have switched to a head-based recursive calls. + call_stack_limit: 256, + ..Config::cancun() +}; + /// Create a smart contract in the storage with the mocked token code pub fn deploy_mock_wrapper( host: &mut MockKernelHost, @@ -88,7 +96,7 @@ pub fn deploy_mock_wrapper( &block, evm_account_storage, &precompiles, - Config::shanghai(), + CONFIG, None, *caller, [code, calldata.abi_encode()].concat(), @@ -135,7 +143,7 @@ pub fn deploy_reentrancy_tester( &block, evm_account_storage, &precompiles, - Config::shanghai(), + CONFIG, None, *caller, [code, calldata.abi_encode()].concat(), @@ -169,7 +177,7 @@ pub fn run_fa_deposit( &block, evm_account_storage, &precompiles, - Config::shanghai(), + CONFIG, *caller, deposit, 100_000_000_000, @@ -393,7 +401,7 @@ pub fn fa_bridge_precompile_call_withdraw( ) -> ExecutionOutcome { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); - let config = Config::shanghai(); + let config = CONFIG; let mut handler = EvmHandler::new( host, diff --git a/etherlink/kernel_evm/evm_execution/src/handler.rs b/etherlink/kernel_evm/evm_execution/src/handler.rs index 21936e60f9a2..e52ca3690d7e 100644 --- a/etherlink/kernel_evm/evm_execution/src/handler.rs +++ b/etherlink/kernel_evm/evm_execution/src/handler.rs @@ -3177,13 +3177,21 @@ mod test { ) } + const CONFIG: Config = Config { + // The current implementation doesn't support Cancun call + // stack limit of 256. We need to set a lower limit until we + // have switched to a head-based recursive calls. + call_stack_limit: 256, + ..Config::cancun() + }; + #[test] fn legacy_create_to_correct_address() { let mut mock_runtime = MockKernelHost::default(); let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let gas_price = U256::from(21000); @@ -3226,7 +3234,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller: H160 = H160::from_str("9bbfed6889322e016e0a02ee459d306fc19545d8").unwrap(); @@ -3268,7 +3276,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let gas_price = U256::from(21000); @@ -3314,7 +3322,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(28349_u64); // We use an origin distinct from caller for testing purposes @@ -3387,7 +3395,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(28349_u64); let gas_price = U256::from(21000); @@ -3489,7 +3497,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(2340); let gas_price = U256::from(21000); @@ -3592,7 +3600,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(8213); let gas_price = U256::from(21000); @@ -3693,7 +3701,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(444); let gas_price = U256::from(21000); @@ -3773,7 +3781,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(117); let gas_price = U256::from(21000); @@ -3838,7 +3846,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(117); let gas_price = U256::from(21000); @@ -3912,7 +3920,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(118); let gas_price = U256::from(21000); @@ -3983,7 +3991,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let gas_price = U256::from(21000); @@ -4053,7 +4061,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let gas_price = U256::from(21000); @@ -4132,7 +4140,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let gas_price = U256::from(21000); @@ -4227,7 +4235,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let gas_price = U256::from(21000); @@ -4287,7 +4295,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let gas_price = U256::from(21000); @@ -4364,7 +4372,7 @@ mod test { let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller_address: [u8; 20] = hex::decode("a94f5374fce5edbc8e2a8697c15331677e6ebf0b") @@ -4440,7 +4448,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_str("a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap(); @@ -4489,7 +4497,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let gas_price = U256::from(21000); @@ -4573,7 +4581,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let gas_price = U256::from(21000); @@ -4602,7 +4610,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_str("a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap(); let withdrawal_contract = @@ -4646,7 +4654,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let gas_price = U256::from(21000); @@ -4735,7 +4743,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let gas_price = U256::from(21000); @@ -4841,6 +4849,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); + // This test is specifically testing a Shanghai behaviour: let config = Config::shanghai(); let caller = H160::from_str("095e7baea6a6c7c4c2dfeb977efac326af552d87").unwrap(); @@ -4907,7 +4916,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let gas_price = U256::from(21000); @@ -4987,7 +4996,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let mut handler = EvmHandler::new( @@ -5058,7 +5067,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let gas_price = U256::from(21000); @@ -5140,7 +5149,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let gas_price = U256::from(21000); @@ -5198,7 +5207,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_str("a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap(); @@ -5248,7 +5257,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(523_u64); let mut handler = EvmHandler::new( @@ -5326,6 +5335,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); + // This test is specifically testing a Shanghai behaviour: let config = Config::shanghai(); let caller = H160::from_low_u64_be(111_u64); @@ -5398,7 +5408,7 @@ mod test { let block = dummy_first_block(); let precompiles = precompiles::precompile_set::(false); let mut evm_account_storage = init_account_storage().unwrap(); - let config = Config::shanghai(); + let config = CONFIG; let caller = H160::from_low_u64_be(111_u64); let gas_price = U256::from(21000); diff --git a/etherlink/kernel_evm/evm_execution/src/lib.rs b/etherlink/kernel_evm/evm_execution/src/lib.rs index c72670a1d812..bd8cdbf2023d 100755 --- a/etherlink/kernel_evm/evm_execution/src/lib.rs +++ b/etherlink/kernel_evm/evm_execution/src/lib.rs @@ -469,11 +469,11 @@ mod test { "60fe47b1000000000000000000000000000000000000000000000000000000000000002a"; const CONFIG: Config = Config { - // The current implementation doesn't support Shanghai call + // The current implementation doesn't support Cancun call // stack limit of 256. We need to set a lower limit until we // have switched to a head-based recursive calls. call_stack_limit: 256, - ..Config::shanghai() + ..Config::cancun() }; // The compiled initialization code for the Ethereum demo contract given @@ -609,7 +609,7 @@ mod test { let caller = H160::from_low_u64_be(985493); let call_data: Vec = vec![]; let transaction_value = U256::from(100_u32); - let config = Config::shanghai(); + let config = CONFIG; let gas_price = U256::from(1); set_balance( @@ -674,7 +674,7 @@ mod test { let caller = H160::from_low_u64_be(1234); let call_data: Vec = vec![]; let transaction_value = U256::from(100_u32); - let config = Config::shanghai(); + let config = CONFIG; let gas_price = U256::from(1); set_balance( @@ -2144,7 +2144,8 @@ mod test { &block, &mut evm_account_storage, &precompiles, - CONFIG, + // This test is specifically testing a Shanghai behaviour: + Config::shanghai(), Some(target), caller, vec![], diff --git a/etherlink/kernel_evm/evm_execution/src/precompiles/fa_bridge.rs b/etherlink/kernel_evm/evm_execution/src/precompiles/fa_bridge.rs index 65b412902cfb..04bd010a758d 100644 --- a/etherlink/kernel_evm/evm_execution/src/precompiles/fa_bridge.rs +++ b/etherlink/kernel_evm/evm_execution/src/precompiles/fa_bridge.rs @@ -158,7 +158,7 @@ mod tests { use std::{borrow::Cow, str::FromStr}; use alloy_sol_types::SolCall; - use evm::{Config, ExitError}; + use evm::ExitError; use primitive_types::{H160, U256}; use tezos_data_encoding::enc::BinWriter; use tezos_evm_runtime::runtime::MockKernelHost; @@ -170,7 +170,7 @@ mod tests { test_utils::{ convert_h160, convert_u256, deploy_reentrancy_tester, dummy_fa_withdrawal, dummy_first_block, dummy_ticket, kernel_wrapper, - set_balance, ticket_balance_add, ticket_id, + set_balance, ticket_balance_add, ticket_id, CONFIG, }, }, handler::{EvmHandler, ExecutionOutcome, ExecutionResult}, @@ -192,7 +192,7 @@ mod tests { disable_reentrancy_guard: bool, ) -> ExecutionOutcome { let block = dummy_first_block(); - let config = Config::shanghai(); + let config = CONFIG; let callee = FA_BRIDGE_PRECOMPILE_ADDRESS; let precompiles = precompiles::precompile_set::(true); @@ -321,7 +321,7 @@ mod tests { let caller = H160::from_low_u64_be(1); let callee = H160::from_low_u64_be(2); let block = dummy_first_block(); - let config = Config::shanghai(); + let config = CONFIG; let precompiles = precompiles::precompile_set::(true); diff --git a/etherlink/kernel_evm/evm_execution/src/precompiles/mod.rs b/etherlink/kernel_evm/evm_execution/src/precompiles/mod.rs index 6bfa71fa7367..83c73fd744c9 100644 --- a/etherlink/kernel_evm/evm_execution/src/precompiles/mod.rs +++ b/etherlink/kernel_evm/evm_execution/src/precompiles/mod.rs @@ -302,11 +302,11 @@ mod test_helpers { use crate::account_storage::account_path; use crate::account_storage::init_account_storage as init_evm_account_storage; use crate::account_storage::EthereumAccountStorage; + use crate::fa_bridge::test_utils::CONFIG; use crate::handler::EvmHandler; use crate::handler::ExecutionOutcome; use crate::EthereumError; use crate::NATIVE_TOKEN_TICKETER_PATH; - use evm::Config; use evm::Transfer; use host::runtime::Runtime; use primitive_types::{H160, U256}; @@ -362,7 +362,7 @@ mod test_helpers { ); let mut evm_account_storage = init_evm_account_storage().unwrap(); let precompiles = precompile_set::(false); - let config = Config::shanghai(); + let config = CONFIG; let gas_price = U256::from(21000); set_ticketer(&mut mock_runtime, DUMMY_TICKETER); -- GitLab From bcef8b13dd8b845800a9cd9bef6239d20a9c81f4 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Fri, 7 Mar 2025 16:47:26 +0100 Subject: [PATCH 20/22] Kernel/Changes: add an entry in new features --- etherlink/CHANGES_KERNEL.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/etherlink/CHANGES_KERNEL.md b/etherlink/CHANGES_KERNEL.md index aeb7c1305db6..e35ef2abad98 100644 --- a/etherlink/CHANGES_KERNEL.md +++ b/etherlink/CHANGES_KERNEL.md @@ -14,6 +14,14 @@ - The EVM is now refunding accounts as expected during inter (layer) transactions. (!16973) +### Features + +- The EVM's configuration has been bumped to Cancun. (!16141)\ + The following EIPs are now supported by Etherlink: + * [EIP-1153](https://eips.ethereum.org/EIPS/eip-1153) + * [EIP-5656](https://eips.ethereum.org/EIPS/eip-5656) + * [EIP-6780](https://eips.ethereum.org/EIPS/eip-6780) + ### Internal - Rework block production to simplify data flow and remove unnecessary -- GitLab From 117aa7dff7caf99166f08be641e2b5461ccfab72 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Thu, 6 Mar 2025 14:09:16 +0100 Subject: [PATCH 21/22] CI/Etherlink: update [test_evm_compatibility] job The new repository contains the updated v14.1 with fillers generated for Cancun. --- .gitlab/ci/pipelines/before_merging.yml | 3 ++- .gitlab/ci/pipelines/merge_train.yml | 3 ++- .gitlab/ci/pipelines/schedule_extended_test.yml | 3 ++- ci/bin/code_verification.ml | 5 +++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.gitlab/ci/pipelines/before_merging.yml b/.gitlab/ci/pipelines/before_merging.yml index b24cbf891888..e2d94a5ed7c6 100644 --- a/.gitlab/ci/pipelines/before_merging.yml +++ b/.gitlab/ci/pipelines/before_merging.yml @@ -2882,7 +2882,8 @@ test_evm_compatibility: - . ./scripts/ci/sccache-start.sh script: - make -f etherlink.mk EVM_EVALUATION_FEATURES=disable-file-logs evm-evaluation-assessor - - git clone --depth 1 --branch v13 https://github.com/ethereum/tests ethereum_tests + - git clone --depth 1 --branch v14.1@etherlink https://github.com/functori/tests + ethereum_tests - ./evm-evaluation-assessor --eth-tests ./ethereum_tests/ --resources ./etherlink/kernel_evm/evm_evaluation/resources/ -c after_script: diff --git a/.gitlab/ci/pipelines/merge_train.yml b/.gitlab/ci/pipelines/merge_train.yml index e671e0763b00..b5229b53d6eb 100644 --- a/.gitlab/ci/pipelines/merge_train.yml +++ b/.gitlab/ci/pipelines/merge_train.yml @@ -2881,7 +2881,8 @@ test_evm_compatibility: - . ./scripts/ci/sccache-start.sh script: - make -f etherlink.mk EVM_EVALUATION_FEATURES=disable-file-logs evm-evaluation-assessor - - git clone --depth 1 --branch v13 https://github.com/ethereum/tests ethereum_tests + - git clone --depth 1 --branch v14.1@etherlink https://github.com/functori/tests + ethereum_tests - ./evm-evaluation-assessor --eth-tests ./ethereum_tests/ --resources ./etherlink/kernel_evm/evm_evaluation/resources/ -c after_script: diff --git a/.gitlab/ci/pipelines/schedule_extended_test.yml b/.gitlab/ci/pipelines/schedule_extended_test.yml index b0e4d1bb3e68..733bbd182dac 100644 --- a/.gitlab/ci/pipelines/schedule_extended_test.yml +++ b/.gitlab/ci/pipelines/schedule_extended_test.yml @@ -2524,7 +2524,8 @@ test_evm_compatibility: - . ./scripts/ci/sccache-start.sh script: - make -f etherlink.mk EVM_EVALUATION_FEATURES=disable-file-logs evm-evaluation-assessor - - git clone --depth 1 --branch v13 https://github.com/ethereum/tests ethereum_tests + - git clone --depth 1 --branch v14.1@etherlink https://github.com/functori/tests + ethereum_tests - ./evm-evaluation-assessor --eth-tests ./ethereum_tests/ --resources ./etherlink/kernel_evm/evm_evaluation/resources/ -c after_script: diff --git a/ci/bin/code_verification.ml b/ci/bin/code_verification.ml index f4b5e69071ed..1d5780a9d1df 100644 --- a/ci/bin/code_verification.ml +++ b/ci/bin/code_verification.ml @@ -3,6 +3,7 @@ (* SPDX-License-Identifier: MIT *) (* Copyright (c) 2024 Nomadic Labs. *) (* Copyright (c) 2024-2025 TriliTech *) +(* Copyright (c) 2025 Functori *) (* *) (*****************************************************************************) @@ -1746,8 +1747,8 @@ let jobs pipeline_type = [ "make -f etherlink.mk EVM_EVALUATION_FEATURES=disable-file-logs \ evm-evaluation-assessor"; - "git clone --depth 1 --branch v13 \ - https://github.com/ethereum/tests ethereum_tests"; + "git clone --depth 1 --branch v14.1@etherlink \ + https://github.com/functori/tests ethereum_tests"; "./evm-evaluation-assessor --eth-tests ./ethereum_tests/ \ --resources ./etherlink/kernel_evm/evm_evaluation/resources/ -c"; ] -- GitLab From 51596f2d7229e290084bb3a5787ce883b58e2298 Mon Sep 17 00:00:00 2001 From: Rodi-Can Bozman Date: Tue, 11 Mar 2025 15:43:03 +0100 Subject: [PATCH 22/22] Backport: add missing members for previous kernels --- .../evm_execution/src/handler.rs | 21 +++++++++++++++++++ .../evm_execution/src/handler.rs | 21 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/etherlink/kernel_bifrost/evm_execution/src/handler.rs b/etherlink/kernel_bifrost/evm_execution/src/handler.rs index 56c6db525de8..eb73ba11c9a5 100644 --- a/etherlink/kernel_bifrost/evm_execution/src/handler.rs +++ b/etherlink/kernel_bifrost/evm_execution/src/handler.rs @@ -2816,6 +2816,27 @@ impl<'a, Host: Runtime> Handler for EvmHandler<'a, Host> { self.record_dynamic_cost(cost, memory_cost) } } + + fn transient_storage(&self, _address: H160, _index: H256) -> H256 { + panic!("Not available on bifrost") + } + + fn blob_hash(&self, _index: H256) -> H256 { + panic!("Not available on bifrost") + } + + fn block_blob_base_fee(&self) -> U256 { + panic!("Not available on bifrost") + } + + fn set_transient_storage( + &mut self, + _address: H160, + _index: H256, + _value: H256, + ) -> Result<(), ExitError> { + panic!("Not available on bifrost") + } } #[cfg(test)] diff --git a/etherlink/kernel_calypso/evm_execution/src/handler.rs b/etherlink/kernel_calypso/evm_execution/src/handler.rs index bd921edbe1af..81fa4be8e4d1 100644 --- a/etherlink/kernel_calypso/evm_execution/src/handler.rs +++ b/etherlink/kernel_calypso/evm_execution/src/handler.rs @@ -2861,6 +2861,27 @@ impl<'a, Host: Runtime> Handler for EvmHandler<'a, Host> { self.record_dynamic_cost(cost, memory_cost) } } + + fn transient_storage(&self, _address: H160, _index: H256) -> H256 { + panic!("Not available on calypso") + } + + fn blob_hash(&self, _index: H256) -> H256 { + panic!("Not available on calypso") + } + + fn block_blob_base_fee(&self) -> U256 { + panic!("Not available on calypso") + } + + fn set_transient_storage( + &mut self, + _address: H160, + _index: H256, + _value: H256, + ) -> Result<(), ExitError> { + panic!("Not available on calypso") + } } #[cfg(test)] -- GitLab