From 27e14ef990d1a67da2ea80b88d6971e3f9190dd8 Mon Sep 17 00:00:00 2001 From: Nikolay Yakimov Date: Mon, 30 Oct 2023 12:05:29 +0300 Subject: [PATCH 1/4] MIR: add chain_id type and values --- contrib/mir/src/ast.rs | 6 +- contrib/mir/src/gas.rs | 6 ++ contrib/mir/src/lexer.rs | 1 + contrib/mir/src/syntax.lalrpop | 2 + contrib/mir/src/typechecker.rs | 80 ++++++++++++++++++++++- contrib/mir/src/typechecker/type_props.rs | 2 +- 6 files changed, 94 insertions(+), 3 deletions(-) diff --git a/contrib/mir/src/ast.rs b/contrib/mir/src/ast.rs index cacda66d9433..087b20a958ee 100644 --- a/contrib/mir/src/ast.rs +++ b/contrib/mir/src/ast.rs @@ -13,6 +13,7 @@ pub mod parsed; pub mod typechecked; use std::collections::BTreeMap; +pub use tezos_crypto_rs::hash::ChainId; pub use michelson_address::*; pub use michelson_list::MichelsonList; @@ -36,6 +37,7 @@ pub enum Type { Or(Box<(Type, Type)>), Contract(Box), Address, + ChainId, } impl Type { @@ -44,7 +46,7 @@ impl Type { pub fn size_for_gas(&self) -> usize { use Type::*; match self { - Nat | Int | Bool | Mutez | String | Unit | Operation | Address => 1, + Nat | Int | Bool | Mutez | String | Unit | Operation | Address | ChainId => 1, Pair(p) | Or(p) | Map(p) => 1 + p.0.size_for_gas() + p.1.size_for_gas(), Option(x) | List(x) | Contract(x) => 1 + x.size_for_gas(), } @@ -159,6 +161,7 @@ pub enum TypedValue { Map(BTreeMap), Or(Box>), Address(Address), + ChainId(ChainId), } pub fn typed_value_to_value_optimized(tv: TypedValue) -> Value { @@ -193,6 +196,7 @@ pub fn typed_value_to_value_optimized(tv: TypedValue) -> Value { TV::Option(Some(r)) => V::new_option(Some(typed_value_to_value_optimized(*r))), TV::Or(x) => V::new_or(x.map(typed_value_to_value_optimized)), TV::Address(x) => V::Bytes(x.to_bytes_vec()), + TV::ChainId(x) => V::Bytes(x.into()), } } diff --git a/contrib/mir/src/gas.rs b/contrib/mir/src/gas.rs index fce194ba98c2..94184e4495e0 100644 --- a/contrib/mir/src/gas.rs +++ b/contrib/mir/src/gas.rs @@ -107,6 +107,12 @@ pub mod tc_cost { // `max(bls,ed25519,p256,secp256k1)`, which happens to be `bls` pub const KEY_HASH_OPTIMIZED: u32 = 80; + // corresponds to cost_B58CHECK_DECODING_CHAIN_ID in the protocol + pub const CHAIN_ID_READABLE: u32 = 1600; + + // corresponds to cost_DECODING_CHAIN_ID in the protocol + pub const CHAIN_ID_OPTIMIZED: u32 = 50; + fn variadic(depth: u16) -> Result { let depth = Checked::from(depth as u32); (depth * 50).as_gas_cost() diff --git a/contrib/mir/src/lexer.rs b/contrib/mir/src/lexer.rs index 26f7a0ee7f1b..412f07d73461 100644 --- a/contrib/mir/src/lexer.rs +++ b/contrib/mir/src/lexer.rs @@ -96,6 +96,7 @@ defprim! { IF_LEFT, contract, address, + chain_id, } defprim! { diff --git a/contrib/mir/src/syntax.lalrpop b/contrib/mir/src/syntax.lalrpop index 9c7a066f7fad..57b6046106e5 100644 --- a/contrib/mir/src/syntax.lalrpop +++ b/contrib/mir/src/syntax.lalrpop @@ -53,6 +53,7 @@ extern { "or" => Tok::Prim(PT::Prim(Prim::or)), "contract" => Tok::Prim(PT::Prim(Prim::contract)), "address" => Tok::Prim(PT::Prim(Prim::address)), + "chain_id" => Tok::Prim(PT::Prim(Prim::chain_id)), "True" => Tok::Prim(PT::Prim(Prim::True)), "False" => Tok::Prim(PT::Prim(Prim::False)), "Unit" => Tok::Prim(PT::Prim(Prim::Unit)), @@ -111,6 +112,7 @@ atomic_type: Type = { "unit" => Type::Unit, "operation" => Type::Operation, "address" => Type::Address, + "chain_id" => Type::ChainId, } pair_args: Type = { diff --git a/contrib/mir/src/typechecker.rs b/contrib/mir/src/typechecker.rs index afa6858ef98a..eee6c2fbd52a 100644 --- a/contrib/mir/src/typechecker.rs +++ b/contrib/mir/src/typechecker.rs @@ -7,6 +7,7 @@ use std::collections::BTreeMap; use std::num::TryFromIntError; +use tezos_crypto_rs::{base58::FromBase58CheckError, hash::FromBytesError}; pub mod type_props; @@ -53,6 +54,28 @@ pub enum TcError { }, #[error(transparent)] AddressError(#[from] AddressError), + #[error("invalid value for chain_id: {0}")] + ChainIdError(#[from] ChainIdError), +} + +#[derive(Debug, PartialEq, Eq, Clone, thiserror::Error)] +pub enum ChainIdError { + #[error("{0}")] + FromBase58CheckError(String), + #[error("{0}")] + FromBytesError(String), +} + +impl From for ChainIdError { + fn from(value: FromBase58CheckError) -> Self { + Self::FromBase58CheckError(value.to_string()) + } +} + +impl From for ChainIdError { + fn from(value: FromBytesError) -> Self { + Self::FromBytesError(value.to_string()) + } } #[derive(Debug, PartialEq, Eq, Clone, thiserror::Error)] @@ -143,7 +166,7 @@ fn verify_ty(ctx: &mut Ctx, t: &Type) -> Result<(), TcError> { use Type::*; ctx.gas.consume(gas::tc_cost::VERIFY_TYPE_STEP)?; match t { - Nat | Int | Bool | Mutez | String | Operation | Unit | Address => Ok(()), + Nat | Int | Bool | Mutez | String | Operation | Unit | Address | ChainId => Ok(()), Pair(tys) | Or(tys) => { verify_ty(ctx, &tys.0)?; verify_ty(ctx, &tys.1) @@ -655,6 +678,17 @@ fn typecheck_value(ctx: &mut Ctx, t: &Type, v: Value) -> Result { + ctx.gas.consume(gas::tc_cost::CHAIN_ID_READABLE)?; + TV::ChainId( + ChainId::from_base58_check(&str).map_err(|x| TcError::ChainIdError(x.into()))?, + ) + } + (T::ChainId, V::Bytes(bs)) => { + use tezos_crypto_rs::hash::HashTrait; + ctx.gas.consume(gas::tc_cost::CHAIN_ID_OPTIMIZED)?; + TV::ChainId(ChainId::try_from_bytes(&bs).map_err(|x| TcError::ChainIdError(x.into()))?) + } (t, v) => return Err(TcError::InvalidValueForType(v, t.clone())), }) } @@ -2483,4 +2517,48 @@ mod typecheck_tests { Err(TcError::AddressError(AddressError::WrongFormat(_))) ); } + + #[test] + fn test_push_chain_id() { + let bytes = "f3d48554"; + let exp = hex::decode(bytes).unwrap(); + let exp = Ok(Push(TypedValue::ChainId(ChainId(exp)))); + let lit = "NetXynUjJNZm7wi"; + assert_eq!( + &typecheck_instruction( + parse(&format!("PUSH chain_id \"{}\"", lit)).unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + &exp + ); + assert_eq!( + &typecheck_instruction( + parse(&format!("PUSH chain_id 0x{}", bytes)).unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + &exp + ); + assert_eq!( + typecheck_instruction( + parse("PUSH chain_id \"foobar\"").unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + Err(TcError::ChainIdError( + tezos_crypto_rs::base58::FromBase58CheckError::InvalidChecksum.into() + )) + ); + assert_eq!( + typecheck_instruction( + parse("PUSH chain_id 0xbeef").unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + Err(TcError::ChainIdError( + tezos_crypto_rs::hash::FromBytesError::InvalidSize.into() + )) + ); + } } diff --git a/contrib/mir/src/typechecker/type_props.rs b/contrib/mir/src/typechecker/type_props.rs index ff1a0297c954..3004bc9ad82f 100644 --- a/contrib/mir/src/typechecker/type_props.rs +++ b/contrib/mir/src/typechecker/type_props.rs @@ -41,7 +41,7 @@ impl Type { gas.consume(tc_cost::TYPE_PROP_STEP)?; let invalid_type_prop = || Err(TcError::InvalidTypeProperty(prop, self.clone())); match self { - Nat | Int | Bool | Mutez | String | Unit | Address => (), + Nat | Int | Bool | Mutez | String | Unit | Address | ChainId => (), Operation => match prop { TypeProperty::Comparable | TypeProperty::Passable -- GitLab From 3a0e21c64701ef3d201aea3e9cda73da2da71eb7 Mon Sep 17 00:00:00 2001 From: Nikolay Yakimov Date: Mon, 30 Oct 2023 12:32:30 +0300 Subject: [PATCH 2/4] MIR: Add CHAIN_ID instruction --- contrib/mir/src/ast.rs | 1 + contrib/mir/src/context.rs | 18 ++++++++++++++++-- contrib/mir/src/gas.rs | 1 + contrib/mir/src/interpreter.rs | 21 +++++++++++++++++++++ contrib/mir/src/lexer.rs | 1 + contrib/mir/src/syntax.lalrpop | 2 ++ contrib/mir/src/typechecker.rs | 19 ++++++++++++++++++- contrib/mir/src/tzt/context.rs | 1 + 8 files changed, 61 insertions(+), 3 deletions(-) diff --git a/contrib/mir/src/ast.rs b/contrib/mir/src/ast.rs index 087b20a958ee..52159c51db81 100644 --- a/contrib/mir/src/ast.rs +++ b/contrib/mir/src/ast.rs @@ -278,6 +278,7 @@ pub enum Instruction { IfCons(Vec>, Vec>), Iter(T::IterOverload, Vec>), IfLeft(Vec>, Vec>), + ChainId, } pub type ParsedAST = Vec; diff --git a/contrib/mir/src/context.rs b/contrib/mir/src/context.rs index cc2c48adef69..1177d7012e42 100644 --- a/contrib/mir/src/context.rs +++ b/contrib/mir/src/context.rs @@ -1,5 +1,19 @@ -#[derive(Debug, Default)] +use crate::gas::Gas; + +#[derive(Debug)] pub struct Ctx { - pub gas: crate::gas::Gas, + pub gas: Gas, pub amount: i64, + pub chain_id: tezos_crypto_rs::hash::ChainId, +} + +impl Default for Ctx { + fn default() -> Self { + Ctx { + gas: Gas::default(), + amount: 0, + // the default chain id is NetXynUjJNZm7wi, which is also the default chain id of octez-client in mockup mode + chain_id: tezos_crypto_rs::hash::ChainId(vec![0xf3, 0xd4, 0x85, 0x54]), + } + } } diff --git a/contrib/mir/src/gas.rs b/contrib/mir/src/gas.rs index 94184e4495e0..f5fbfbfa95f2 100644 --- a/contrib/mir/src/gas.rs +++ b/contrib/mir/src/gas.rs @@ -177,6 +177,7 @@ pub mod interpret_cost { pub const AMOUNT: u32 = 10; pub const NIL: u32 = 10; pub const CONS: u32 = 15; + pub const CHAIN_ID: u32 = 15; pub const INTERPRET_RET: u32 = 15; // corresponds to KNil in the Tezos protocol pub const LOOP_ENTER: u32 = 10; // corresponds to KLoop_in in the Tezos protocol diff --git a/contrib/mir/src/interpreter.rs b/contrib/mir/src/interpreter.rs index fda4656d1951..64f337c98bf7 100644 --- a/contrib/mir/src/interpreter.rs +++ b/contrib/mir/src/interpreter.rs @@ -356,6 +356,10 @@ fn interpret_one( stack.push(V::Map(map)); } }, + I::ChainId => { + ctx.gas.consume(interpret_cost::CHAIN_ID)?; + stack.push(V::ChainId(ctx.chain_id.clone())); + } I::Seq(nested) => interpret(nested, ctx, stack)?, } Ok(()) @@ -1285,4 +1289,21 @@ mod interpreter_tests { ) .unwrap(); // panics } + + #[test] + fn chain_id_instr() { + let chain_id = super::ChainId::from_base58_check("NetXynUjJNZm7wi").unwrap(); + let ctx = &mut Ctx { + chain_id: chain_id.clone(), + ..Ctx::default() + }; + let start_milligas = ctx.gas.milligas(); + let stk = &mut stk![]; + assert_eq!(interpret(&vec![Instruction::ChainId], ctx, stk), Ok(())); + assert_eq!(stk, &stk![TypedValue::ChainId(chain_id)]); + assert_eq!( + start_milligas - ctx.gas.milligas(), + interpret_cost::CHAIN_ID + interpret_cost::INTERPRET_RET + ); + } } diff --git a/contrib/mir/src/lexer.rs b/contrib/mir/src/lexer.rs index 412f07d73461..3b480adf10f5 100644 --- a/contrib/mir/src/lexer.rs +++ b/contrib/mir/src/lexer.rs @@ -97,6 +97,7 @@ defprim! { contract, address, chain_id, + CHAIN_ID, } defprim! { diff --git a/contrib/mir/src/syntax.lalrpop b/contrib/mir/src/syntax.lalrpop index 57b6046106e5..7616bb43cef3 100644 --- a/contrib/mir/src/syntax.lalrpop +++ b/contrib/mir/src/syntax.lalrpop @@ -90,6 +90,7 @@ extern { "IF_CONS" => Tok::Prim(PT::Prim(Prim::IF_CONS)), "ITER" => Tok::Prim(PT::Prim(Prim::ITER)), "IF_LEFT" => Tok::Prim(PT::Prim(Prim::IF_LEFT)), + "CHAIN_ID" => Tok::Prim(PT::Prim(Prim::CHAIN_ID)), "(" => Tok::LParen, ")" => Tok::RParen, "{" => Tok::LBrace, @@ -198,6 +199,7 @@ atomic_instruction: ParsedInstruction = { "DUP" => Dup(None), "UNPAIR" => Unpair, "CONS" => Cons, + "CHAIN_ID" => Instruction::ChainId, } instruction: ParsedInstruction = { diff --git a/contrib/mir/src/typechecker.rs b/contrib/mir/src/typechecker.rs index eee6c2fbd52a..16a60f707940 100644 --- a/contrib/mir/src/typechecker.rs +++ b/contrib/mir/src/typechecker.rs @@ -585,6 +585,11 @@ fn typecheck_instruction( (I::Update(..), [.., _, _, _]) => no_overload!(UPDATE), (I::Update(..), [] | [_] | [_, _]) => no_overload!(UPDATE, len 3), + (I::ChainId, ..) => { + stack.push(T::ChainId); + I::ChainId + } + (I::Seq(nested), ..) => I::Seq(typecheck(nested, ctx, opt_stack)?), }) } @@ -2522,7 +2527,7 @@ mod typecheck_tests { fn test_push_chain_id() { let bytes = "f3d48554"; let exp = hex::decode(bytes).unwrap(); - let exp = Ok(Push(TypedValue::ChainId(ChainId(exp)))); + let exp = Ok(Push(TypedValue::ChainId(super::ChainId(exp)))); let lit = "NetXynUjJNZm7wi"; assert_eq!( &typecheck_instruction( @@ -2561,4 +2566,16 @@ mod typecheck_tests { )) ); } + + #[test] + fn chain_id_instr() { + assert_eq!( + typecheck_instruction( + parse("CHAIN_ID").unwrap(), + &mut Ctx::default(), + &mut tc_stk![] + ), + Ok(Instruction::ChainId) + ); + } } diff --git a/contrib/mir/src/tzt/context.rs b/contrib/mir/src/tzt/context.rs index 515925c7e78a..4bce4c595c24 100644 --- a/contrib/mir/src/tzt/context.rs +++ b/contrib/mir/src/tzt/context.rs @@ -12,5 +12,6 @@ pub fn construct_context(test: &TztTest) -> Ctx { Ctx { gas: crate::gas::Gas::default(), amount: test.amount.unwrap_or_default(), + chain_id: Ctx::default().chain_id, } } -- GitLab From 583ca99e68c64784a9b140168d982ffd6939e1dc Mon Sep 17 00:00:00 2001 From: Nikolay Yakimov Date: Wed, 1 Nov 2023 21:01:07 +0300 Subject: [PATCH 3/4] MIR: Add chain_id section for tzt --- contrib/mir/src/syntax.lalrpop | 3 ++- contrib/mir/src/tzt.rs | 23 +++++++++++++++++++---- contrib/mir/src/tzt/context.rs | 17 ----------------- contrib/mir/tzt_runner/main.rs | 28 ++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 22 deletions(-) delete mode 100644 contrib/mir/src/tzt/context.rs diff --git a/contrib/mir/src/syntax.lalrpop b/contrib/mir/src/syntax.lalrpop index 7616bb43cef3..1cc84f0f270e 100644 --- a/contrib/mir/src/syntax.lalrpop +++ b/contrib/mir/src/syntax.lalrpop @@ -296,7 +296,8 @@ tztEntity : TztEntity = { "output" "(" "generalOverflow" ")" => Output(TztError(InterpreterError(GeneralOverflow(a1, a2)))), "output" "(" "StaticError" ")" => Output(TztError(TypecheckerError(Some(s)))), "output" "(" "StaticError" "_" ")" => Output(TztError(TypecheckerError(None))), - "amount" => TztEntity::Amount(m) + "amount" => TztEntity::Amount(m), + "chain_id" => TztEntity::ChainId(<>), } pub tztTestEntities : Vec = semicolonSepSeq; diff --git a/contrib/mir/src/tzt.rs b/contrib/mir/src/tzt.rs index b2ec23267b41..9e4311516901 100644 --- a/contrib/mir/src/tzt.rs +++ b/contrib/mir/src/tzt.rs @@ -5,7 +5,6 @@ /* */ /******************************************************************************/ -mod context; mod expectation; use std::fmt; @@ -13,16 +12,16 @@ use std::fmt; use crate::ast::*; use crate::context::*; use crate::interpreter::*; +use crate::irrefutable_match::irrefutable_match; use crate::parser::spanned_lexer; use crate::stack::*; use crate::syntax::tztTestEntitiesParser; use crate::typechecker::*; -use crate::tzt::context::*; use crate::tzt::expectation::*; pub type TestStack = Vec<(Type, TypedValue)>; -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum TztTestError { StackMismatch( (FailingTypeStack, Stack), @@ -68,6 +67,7 @@ pub struct TztTest { pub input: TestStack, pub output: TestExpectation, pub amount: Option, + pub chain_id: Option, } fn typecheck_stack(stk: Vec<(Type, Value)>) -> Result, TcError> { @@ -108,6 +108,7 @@ impl TryFrom> for TztTest { let mut m_input: Option = None; let mut m_output: Option = None; let mut m_amount: Option = None; + let mut m_chain_id: Option = None; for e in tzt { match e { @@ -125,6 +126,7 @@ impl TryFrom> for TztTest { }, )?, Amount(m) => set_tzt_field("amount", &mut m_amount, m)?, + ChainId(id) => set_tzt_field("chain_id", &mut m_chain_id, id)?, } } @@ -133,6 +135,14 @@ impl TryFrom> for TztTest { input: m_input.ok_or("input section not found in test")?, output: m_output.ok_or("output section not found in test")?, amount: m_amount, + chain_id: m_chain_id + .map(|v| { + Ok::<_, TcError>(irrefutable_match!( + v.typecheck(&mut Ctx::default(), &Type::ChainId)?; + TypedValue::ChainId + )) + }) + .transpose()?, }) } } @@ -197,6 +207,7 @@ pub enum TztEntity { Input(Vec<(Type, Value)>), Output(TztOutput), Amount(i64), + ChainId(Value), } /// Possible values for the "output" expectation field in a Tzt test @@ -232,7 +243,11 @@ pub fn run_tzt_test(test: TztTest) -> Result<(), TztTestError> { // Here we compare the outcome of the interpreting with the // expectation from the test, and declare the result of the test // accordingly. - let mut ctx = construct_context(&test); + let mut ctx = Ctx { + gas: crate::gas::Gas::default(), + amount: test.amount.unwrap_or_default(), + chain_id: test.chain_id.unwrap_or(Ctx::default().chain_id), + }; let execution_result = execute_tzt_test_code(test.code, &mut ctx, test.input); check_expectation(&mut ctx, test.output, execution_result) } diff --git a/contrib/mir/src/tzt/context.rs b/contrib/mir/src/tzt/context.rs deleted file mode 100644 index 4bce4c595c24..000000000000 --- a/contrib/mir/src/tzt/context.rs +++ /dev/null @@ -1,17 +0,0 @@ -/******************************************************************************/ -/* */ -/* SPDX-License-Identifier: MIT */ -/* Copyright (c) [2023] Serokell */ -/* */ -/******************************************************************************/ - -use crate::context::*; -use crate::tzt::*; - -pub fn construct_context(test: &TztTest) -> Ctx { - Ctx { - gas: crate::gas::Gas::default(), - amount: test.amount.unwrap_or_default(), - chain_id: Ctx::default().chain_id, - } -} diff --git a/contrib/mir/tzt_runner/main.rs b/contrib/mir/tzt_runner/main.rs index f52921437870..8d795c2eda0a 100644 --- a/contrib/mir/tzt_runner/main.rs +++ b/contrib/mir/tzt_runner/main.rs @@ -136,6 +136,34 @@ mod tztrunner_tests { )); } + #[test] + fn test_runner_chain_id() { + assert_eq!( + run_tzt_test( + parse_tzt_test( + r#"code { CHAIN_ID }; + input {}; + chain_id "NetXdQprcVkpaWU"; + output { Stack_elt chain_id 0x7a06a770 }"#, + ) + .unwrap() + ), + Ok(()) + ); + assert_eq!( + run_tzt_test( + parse_tzt_test( + r#"code { CHAIN_ID }; + input {}; + chain_id 0xbeeff00d; + output { Stack_elt chain_id 0xbeeff00d }"#, + ) + .unwrap() + ), + Ok(()) + ); + } + const TZT_SAMPLE_ADD: &str = "code { ADD } ; input { Stack_elt int 5 ; Stack_elt int 5 } ; output { Stack_elt int 10 }"; -- GitLab From 912bcbdcd453edd80c5abed40dd1e55415c74389 Mon Sep 17 00:00:00 2001 From: Nikolay Yakimov Date: Wed, 8 Nov 2023 13:09:14 +0300 Subject: [PATCH 4/4] MIR: Add comparability for chain_id --- contrib/mir/src/ast/comparable.rs | 26 ++++++++++++++++++++++++++ contrib/mir/src/gas.rs | 2 ++ 2 files changed, 28 insertions(+) diff --git a/contrib/mir/src/ast/comparable.rs b/contrib/mir/src/ast/comparable.rs index 51c974f10c3e..b455fc741d41 100644 --- a/contrib/mir/src/ast/comparable.rs +++ b/contrib/mir/src/ast/comparable.rs @@ -14,6 +14,7 @@ impl PartialOrd for TypedValue { (Option(x), Option(y)) => x.as_deref().partial_cmp(&y.as_deref()), (Or(x), Or(y)) => x.as_ref().partial_cmp(y.as_ref()), (Address(l), Address(r)) => l.partial_cmp(r), + (ChainId(l), ChainId(r)) => l.partial_cmp(r), _ => None, } } @@ -28,6 +29,8 @@ impl Ord for TypedValue { #[cfg(test)] mod tests { + use tezos_crypto_rs::hash::HashTrait; + use super::*; #[test] @@ -132,6 +135,29 @@ mod tests { } } + #[test] + /// checks that an array of chain ids is sorted without a priori assuming + /// that the comparison operator on chain ids is transitive. + fn compare_chain_ids() { + // ordering was verified against octez-client + let ordered_chain_ids = [ + "00000000", "00000001", "00000002", "00000100", "00000200", "01020304", "a0b0c0d0", + "a1b2c3d4", "ffffffff", + ] + .map(|x| { + TypedValue::ChainId( + tezos_crypto_rs::hash::ChainId::try_from_bytes(&hex::decode(x).unwrap()).unwrap(), + ) + }); + + for (i, addr_i) in ordered_chain_ids.iter().enumerate() { + for (j, addr_j) in ordered_chain_ids.iter().enumerate() { + assert_eq!(addr_i.partial_cmp(addr_j), i.partial_cmp(&j)); + assert_eq!(addr_i.cmp(addr_j), i.cmp(&j)); + } + } + } + #[test] #[should_panic(expected = "Comparing incomparable values in TypedValue")] fn compare_different_comparable() { diff --git a/contrib/mir/src/gas.rs b/contrib/mir/src/gas.rs index f5fbfbfa95f2..bbccd5f1f771 100644 --- a/contrib/mir/src/gas.rs +++ b/contrib/mir/src/gas.rs @@ -244,6 +244,7 @@ pub mod interpret_cost { }; let cmp_option = Checked::from(10u32); const ADDRESS_SIZE: usize = 20 + 31; // hash size + max entrypoint size + const CMP_CHAIN_ID: u32 = 30; Ok(match (v1, v2) { (V::Nat(l), V::Nat(r)) => { // NB: eventually when using BigInts, use BigInt::bits() &c @@ -266,6 +267,7 @@ pub mod interpret_cost { } .as_gas_cost()?, (V::Address(..), V::Address(..)) => cmp_bytes(ADDRESS_SIZE, ADDRESS_SIZE)?, + (V::ChainId(..), V::ChainId(..)) => CMP_CHAIN_ID, _ => unreachable!("Comparison of incomparable values"), }) } -- GitLab