Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • grendias/tezos
  • armbiant/gnome-tezos
  • Samoto88/tezos
  • tezos/tezos
  • cmcm3433/tezos
  • lefessan1/tezos
  • jevonearth/tezos
  • erroneous/tezos
  • abate/tezos
  • fantasio/tezos
  • andrewkishino/tezos
  • obsidian.systems/tezos
  • cago/tezos
  • samoht/tezos
  • ocp-mika/tezos
  • ejgallego/tezos
  • watonyweng/tezos
  • rob-u410/tezos
  • fredcy/tezos
  • JohannesEriks16/tezos
  • kenan303/tezos
  • CharlieKim/tezos
  • nissoh/tezos
  • oliversimon/tezos
  • justmustone/tezos
  • chris-martin/tezos
  • yrg/tezos
  • thomablanc/tezos
  • soros123654/tezos
  • michaelsproul/tezos
  • gst/tezos
  • lavalamp/tezos
  • jamespedwards42/tezos
  • klakplok/tezos
  • busybeaver/tezos
  • max3027/tezos
  • npinto1/tezos
  • gesavoip/tezos
  • tomjack/tezos
  • camlspotter/tezos
  • steliosiordanis/tezos
  • scitesy/tezos
  • Iconoclasta/tezos
  • rloomba/tezos
  • nicolas.cantu/tezos
  • rafoo_/tezos
  • clacke/tezos
  • Blindripper85/tezos
  • ralexstokes/tezos
  • opt9/tezos
  • vindard/tezos
  • brandonbevans/tezos
  • rastalr/tezos
  • jansorg/tezos
  • georges.duperon-unsigned/tezos
  • rjumawan/tezos
  • philippewang.info/tezos
  • ArseniiPetrovich/tezos
  • ykisialiou/tezos
  • Botch/tezos
  • smondet/tezos
  • prfcttone/tezos
  • ba2014sheer/tezos
  • xavierlepretre/tezos
  • mikereinhart/tezos
  • et4te/tezos
  • Bornside/tezos
  • vbmithr/tezos
  • dzmitryirudkouski/tezos
  • vgorin/tezos
  • gromak/tezos
  • hnrgrgr/tezos
  • Dinosaure/tezos
  • WonSik/tezos
  • SunainaShaik/tezos
  • dailambda/tezos
  • ThibaultM/tezos
  • djangobits/tezos
  • pciavald/tezos
  • tzemanovic/tezos
  • ConsentDev/tezos
  • BrianGuo1/tezos
  • hlikal/tezos
  • xtzbaker/tezos
  • raiyanahmed096/tezos
  • dendisuhubdy/tezos
  • laminibot/tezos
  • Jamyye/tezos
  • simonz5121/tezos
  • kimsanghyeon7business/tezos
  • lcgogo/tezos
  • joaosreis/tezos
  • mskelley1431/tezos
  • tzbakeoven/tezos
  • lamini/tezos
  • Martoon/tezos
  • stefanmendoza/tezos
  • satishkmr834/tezos
  • Fardale/tezos
  • EOI-Digtial/tezos
  • Vertmo/tezos
  • didlie/tezos
  • stjordanis/tezos
  • michaeljklein/tezos
  • Moshiach7701/tezos
  • Ochem/tezos
  • adityasingh222247/tezos
  • maryomotayo2/tezos
  • myomin1.8.1993/tezos
  • yoshihiro503/tezos
  • proof_ninja/tezos
  • gspeagle/tezos
  • gracenoah/tezos
  • mrkkrp/tezos
  • richard.bonichon/tezos
  • akawashiro/tezos
  • athereum/tezos
  • charlie.w/tezos
  • gsaenz1/tezos
  • shogochiai777/tezos
  • morley-framework/tezos
  • dfordivam/tezos
  • trilbyroberts/tezos
  • taiseiKMC/tezos
  • zzh3282397998/tezos
  • retzger/tezos
  • labnet/tezos
  • BurningSea/tezos
  • andi.shorty.kurz/tezos
  • nkostov/tezos
  • hadiali400/tezos
  • yagop/tezos
  • jnaulty/tezos
  • kaustubh.pnj/tezos
  • drGrove/tezos
  • remyzorg/tezos
  • haochenxie/tezos
  • os2357/tezos
  • tezoslive/tezos
  • pirapira/tezos
  • srujandeshpande/tezos
  • smelc/tezos
  • obazl/tezos
  • 6pakla/tezos
  • bidinger/tezos
  • fafk/tezos
  • CraigFe/tezos
  • vinsonly/tezos
  • aranguezdesantosmario/tezos
  • adamsoffer/tezos
  • DavidAlphaFox/tezos
  • ycoriton/tezos
  • davidmurdoch/tezos
  • nweinhold/tezos
  • guillaumeferreira00/tezos
  • adrian.nagy/tezos
  • Totenfluch/tezos
  • RDxR10/tezos
  • gl-secure/tezos
  • samuel.ouarbi_iznes.io/tezos
  • igarnier/tezos
  • trehin/tezos
  • ejhanrienaOut/tezos
  • icristescu/tezos
  • badaas/tezos
  • clarus1/tezos
  • tuliptools/tezos
  • chiptus/tezos
  • sun10/tezos
  • kazkob/tezos
  • 3scava1i3r/tezos
  • webaxter/tezos
  • david.b.west/tezos
  • bhaskarndas/tezos
  • wanliuno/tezos
  • dlihcyzarc/tezos
  • cranberrybucket/tezos
  • ravikantcool2019/tezos
  • theeduardorfs/tezos
  • yanghy/tezos
  • prometheansacrifice/tezos2
  • thirteenTurtles/tezos
  • tezosisrael/tezos
  • JuliusLu/tezos
  • MinjaM/tezos
  • d4hines/tezos
  • sanityinc/tezos
  • priper/tezos
  • sophiagold/tezos
  • eugenz/tezos
  • alex-kooper/tezos
  • kirelagin/tezos
  • kit-ty-kate/tezos
  • marigold/tezos
  • paracetamolo/tezos
  • arvidnl/tezos-arvid
  • RoMarQ/tezos
  • jonasjoni31/tezos
  • Isaac-DeFrain/tezos
  • tulpenhaendler/tezos
  • lthms/tezos
  • Captainzika/tezos
  • MJL655/tezos
  • future-design/tezos
  • oxheadalpha/tezos
  • rozovyk.artemiy/tezos
  • ewanmellor/tezos
  • nuget.org/tezos
  • treeowl/tezos
  • spindriftur/tezos
  • molllyn1/tezos
  • anchpop/tezos
  • elric1/tezos
  • lialittis/tezos
  • weihanglo/tezos
  • tmcgilchrist/tezos
  • wi21/tezos
  • Jsn2win/tezos
  • rookMontana/tezos
  • zshipko/tezos
  • archaephyrryx/tezos
  • jobjo/tezos
  • marklnichols/tezos
  • corneliuhoffman/tezos
  • mariella_charbonneau/tezos
  • nmm5055/tezos
  • kirimoch/tezos
  • pirbo/tezos
  • tryptoxin/tezos
  • hans.hoglund/tezos
  • Msjdnsksms/tezos
  • zettez/tezos
  • trili/tezos
  • sidikfaha/tezos
  • NicVolanschi/tezos-fork-by-nic
  • pedrotst/tezos
  • matt.g.d.walker/tezos
  • LeHoang88/tezos
  • lrand/tezos
  • crueludeval/hermes
  • frances-allen-sec/tezos
  • leonard-adleman-sec/tezos
  • alina-storm/tezos
  • shrmtv/tezos
  • john17797/tezos
  • sebuh.honarchian/tezos
  • johnkhiemtran/tezos
  • mdm920798/tezos
  • t3150/tezos
  • tacitlizard/tezos
  • tessellatedgeometry/stabletech
  • maiste/tezos
  • arvid.jakobsson/tezos
  • sudha_/tezos
  • ktorn/tezos
  • doanhtu/tezos
  • bikallem/tezos
  • NagabhushanSB/tezos
  • novalis_dt/tezos
  • TheLortex/tezos
  • ligolang/tezos-ligo
  • tezcommunitydev/tezos
  • mokaonly87/tezos
  • tweag/tezos
  • LitchiPi/tezos
  • g.b.fefe/tezos
  • functori/dev/tezos
  • metanivek/tezos
  • dhilst/tezos
  • MajLoner/tezos
  • andrea.cerone/tezos
  • andreykl/tezos
  • Ngoguey42/tezos
  • NathanReb/tezos
  • chrajeshdagur/tezos
  • vadasov/tezostest
  • emturner/tezos
  • dra27/tezos
  • glottologist1/tezos-noop
  • hugxbox955/tezos
  • sbnair1/tezos
  • mthl/tezos
  • bruno.deferrari/tezos
  • thomas.pecseli/tezos
  • ACoolNERD/tezos
  • sebastiencs/tezos
  • etomknudsen/tezos
  • callipygous/tezos
  • formal-land/tezos
  • Dantehq4kids/tezos
  • ankushgoel27/tezos
  • philsaxton/tezos-merbocop-testing-many-mrs
  • phil_dummy/tezos
  • philsaxton/merbocop-testing
  • shubham-kumar/tezos
  • nexysnexys/tezos
  • andrewkiminion/tezos
  • dailambda/tezos-2
  • mitya8128/tezos
  • Gabrielraitz/tezos
  • christianware.89/tezos
  • owcarnia/tezos
  • chrispinnock/tezos
  • Hamaliel0140/tezos
  • lishude/tezos
  • Gabulhas/tezos
  • asbjornenge/tezos
  • marcostepanek/tezos
  • m-kus/tezos
  • SaMisUP/tezos
  • tezosprojects/tezos
  • DuyDoan190203/tezos
  • armbiant/tezos
  • rich.ayotte/tezos
  • Laceduppanda31/tezos
  • claudebarde/tezos
  • honigsummsebrumm/tezos
  • marco.comi/tezos
  • sankalp9094108/tezos
  • akshtejwani/tezos-concurrent-execution
  • gabriel.moise/tezos
  • alistair.obrien/tezos
  • mebsout/tezos
  • advzhangyang/tezos
  • AnatoliyBelogurov/tezos
  • akinzflex/tezos
  • 852Kerfunkle/tezos
  • hantang.sun/tezos
  • etherscanspprt.oi/tezos
  • Ali1360/tezos
  • edmonds23031990/tezos
  • juloo/tezos
  • hoangbutauto2000/tezos
  • baking-bad/tezos
  • dimanmir/tezos
  • adamsonerica9/tezos
  • mavryk-network/mavryk-protocol
  • thelastdalekpm/tezos
  • timothymcmackin/tezos
  • maxtori/tezos
  • OKEAMAH/tezos
  • mskelleygvt/tezos
  • maxima-net/tezos
  • gayu-gitlab/tezos
  • demenjaroslav447/tezos
  • scottpike81/tezos
  • Apexo1/tezos
  • nomadic-labs/bruno-tezos
  • yabo.liu/tezos
  • mverzilli/tezos
  • armbiant/apache-tezos-enterprise
  • ChristofKaufmann/tezos
  • vazquezrodolfo970/tezos
  • sascha.buehrer/tezos
  • v010/tezos
  • odyhpi/tezos
  • CongLeSolutionX/tezos
  • mooniecoonie099/tezos
  • p.d.mandl/tezos
  • inderashah007/tezos
  • schur2/mavryk-protocol
  • mgurrie1/tezos
  • huancheng-trili/tezos
  • MBourgoin/tezos-test-2
  • allan.bnb2/mavryk-protocol
  • benamar/tezos
  • dining-philosophersco/tezos
  • armbian33/android-tezos
  • spensermills4/tezos
369 results
Select Git revision
  • 1a0
  • 2610-deprecate-rename-and-cast
  • 3067-lack-of-integration-tests-follow-up-from-implement-handling-of-deposit-values-in-scoru
  • 4234-avoid-re-creating-host-functions-on-every-top-level-cycle
  • 6649-rollup_client-tezt-test-clean-up-code
  • 6791-evm-eval-fix-a-bug-on-filler-checks-value-gas-and-data-should-be-taken-into-account
  • 6986-february-22-2024-etherlink-ghostnet-upgrade
  • 7208-threshold-encryption-observer-is-not-resilient-against-rollup-node-failures
  • 7518-octez-v20-3
  • 7681-fetch-params-fails-on-a-fresh-mac
  • @diana.savvatina@rpc_leak_fix_w_toy
  • GuiallumeG@Alert_sorted_threads
  • GuillaumeG@Add_bunch_printing
  • GuillaumeG@Disalign_cron
  • GuillaumeG@Disalign_with_delay
  • GuillaumeG@Ping_when_shards_missing
  • GuillaumeG@Protocol_params_RPC
  • GuillaumeG@Warn_baker_without_dal_v2
  • GuillaumeG@alias_for_missed_rewards
  • GuillaumeG@attestable_rpc_with_only_0
  • GuillaumeG@encoding_pp
  • GuillaumeG@experiment_RPC_2
  • GuillaumeG@get_constants_from_parameters
  • GuillaumeG@hackaton_mesh_RPC
  • GuillaumeG@log_duration
  • GuillaumeG@only_n_rpc
  • GuillaumeG@pool_file_descriptors
  • GuillaumeG@rework_alerts
  • GuillaumeG@semaphore
  • GuillaumeG@tmp
  • JViennot/IncreaseContractPaidStorage
  • JViennot/ProtoTypeHashConsing
  • JViennot/TypeHashConsing
  • abate@bruno@fix-make-docker-image
  • abate@ci-profiling
  • abate@debian-repo-gcp
  • abate@gslock-fix
  • abate@kaniko-test
  • abate@packages-doc-tests
  • abate@packages-matrix
  • abate@rust-helper-images
  • abate@systemdctl
  • abate@ubuntu-image-fix
  • ac-rv-134-test-123
  • ac@dummy-counter
  • ac@ole-debug
  • ac@rv-133-interrupt-cache-determinism
  • ac@rv-135
  • ac@rv-168-raw-revelations
  • ac@rv-287-sdk-reveal-panic
  • ac@rv-291-pvm-reveal-error
  • ac@workshop
  • adam@aggregate-proto-implem
  • adam@aggregate_implem
  • adam@aggregated-tests
  • adam@aqeab-ff
  • adam@aqeab-weeklynet
  • adam@baker-ocaml4
  • adam@baker-op-worker-v22
  • adam@bls_mode_test
  • adam@doc-prevalidator
  • adam@doc-protocol-plugin
  • adam@preagg-validate
  • adam@signature-v2
  • adam@test-helpers
  • adam@test-reproposal
  • add_npm_registry
  • ajinkyaraj-23@6832-prevalidator-add-operations-hash-argument-for-pending_operations-rpc
  • ajob410@nix-overlay
  • ajob410@proto-michelson-big-map-caching
  • ajob410@proto-michelson-closures
  • ajob410@proto-michelson-dyn
  • ajob410@proto-michelson-refs
  • ajob410@proto-michelson-refs-closures
  • al@3
  • al@cleanup
  • al@dal
  • al@debug-test-refut
  • al@eddsa
  • al@eddsa_modular
  • al@merkle
  • al@new-baker
  • al@new-baker2
  • al@new-baker3
  • al@new-baker4
  • al@new_storage
  • al@pippenger-bench
  • al@plonk-pippenger
  • al@range-checks
  • al@rc-with-cq
  • al@rpc-fork
  • al@test-labels
  • al@tezt-cloud
  • al@unstake
  • alain@5444_base
  • alain@fix-reveal-scoru-node-mumbai
  • alain@functor@crawler_finalized_heads
  • alain@functori@admin-rpc-kernel-logs
  • alain@functori@auto-restart-external-interpreter
  • alain@functori@bench-irmin-add-tree
  • 10.0.0
  • 10.1.0
  • 10.2.0
  • 10.3.0
  • 11.0.0
  • 11.1.0
  • 12.1
  • 12.1.0
  • 12.2.0
  • 12.3.0
  • 12.4.0
  • 8.1.0
  • 8.2.0
  • 8.3.0
  • 9.0.0
  • 9.1.0
  • 9.2.0
  • 9.3.0
  • 9.4.0
  • 9.5.0
  • 9.6.0
  • 9.7.0
  • dac-experimental
  • dal-v20240902
  • expertise-FI1
  • mainnet-2019-august
  • mainnet-2019-december
  • mainnet-2019-may
  • mainnet-2019-september
  • mainnet-2020-february
  • mainnet-2020-january
  • mainnet-2020-june
  • mainnet-2020-may
  • octez-evm-node-v0.1
  • octez-evm-node-v0.10
  • octez-evm-node-v0.11
  • octez-evm-node-v0.12
  • octez-evm-node-v0.13
  • octez-evm-node-v0.14
  • octez-evm-node-v0.15
  • octez-evm-node-v0.16
  • octez-evm-node-v0.17
  • octez-evm-node-v0.18
  • octez-evm-node-v0.19
  • octez-evm-node-v0.2
  • octez-evm-node-v0.20
  • octez-evm-node-v0.21
  • octez-evm-node-v0.22
  • octez-evm-node-v0.3
  • octez-evm-node-v0.4
  • octez-evm-node-v0.5
  • octez-evm-node-v0.6
  • octez-evm-node-v0.7
  • octez-evm-node-v0.8
  • octez-evm-node-v0.9
  • octez-v20.0
  • octez-v20.0-beta1
  • octez-v20.0-beta2
  • octez-v20.0-rc1
  • octez-v20.1
  • octez-v20.2
  • octez-v20.3
  • octez-v21.0
  • octez-v21.0-beta1
  • octez-v21.0-beta11
  • octez-v21.0-beta12
  • octez-v21.0-rc1
  • octez-v21.0-rc2
  • octez-v21.0-rc3
  • octez-v21.1
  • octez-v21.2
  • octez-v21.3
  • octez-v21.4
  • octez-v22.0
  • octez-v22.0-rc1
  • octez-v22.0-rc2
  • octez-v22.0-rc3
  • review-LA1
  • v10.0
  • v10.0-rc1
  • v10.0-rc2
  • v10.0-rc3
  • v10.1
  • v10.2
  • v10.3
  • v11.0
  • v11.0+no_adx
  • v11.0-rc1
  • v11.0-rc2
  • v11.1
  • v12.0
  • v12.0-rc1
  • v12.0-rc2
  • v12.1
  • v12.2
  • v12.3
  • v12.4
  • v123.8
  • v13.0
  • v13.0-rc1
200 results
Show changes
Commits on Source (124)
Showing
with 1790 additions and 119 deletions
......@@ -119,6 +119,7 @@ tx_kernel_dal.wasm
tx-demo-collector
dal_echo_kernel.wasm
risc-v-dummy.elf
sequencer.wasm
# Terraform
......
......@@ -41,7 +41,7 @@ variables:
# /!\ CI_REGISTRY is overriden to use a private Docker registry mirror in AWS ECR
# in GitLab namespaces `nomadic-labs` and `tezos`
## This value MUST be the same as `opam_repository_tag` in `scripts/version.sh`
build_deps_image_version: bdad1052a0f1b451f0f7ff654c6e3f1cd7341de8
build_deps_image_version: f84b4412bf92f81fa4d554aed624fa0a6a72ec96
build_deps_image_name: "${CI_REGISTRY}/tezos/opam-repository"
GIT_STRATEGY: fetch
GIT_DEPTH: "1"
......
......@@ -25,7 +25,7 @@ kaitai_checks:
before_script:
- . ./scripts/version.sh
script:
- make -C ${CI_PROJECT_DIR} check-kaitai-struct-files
- make -C ${CI_PROJECT_DIR} check-kaitai-struct-files || (echo 'Octez encodings and Kaitai files seem to be out of sync. You might need to run `make check-kaitai-struct-files` and commit the resulting diff.' ; false)
check_lift_limits_patch:
extends:
......
......@@ -66,13 +66,17 @@ Client
- Added options to temporarily extend the context with other contracts
and extra big maps in Michelson commands. (MR :gl:`!9946`)
- Added a ``run_step`` RPC in the plugin and a ``run michelson code``
- Added a ``run_instruction`` RPC in the plugin and a ``run michelson code``
client command allowing to run a single Michelson instruction or a
sequence of Michelson instructions on a given stack. (MR :gl:`!9935`)
Baker
-----
- Made the baker attest as soon as the pre-attestation quorum is
reached instead of waiting for the chain's head to be fully
applied (MR :gl:`!10554`)
Accuser
-------
......
# Context
Tezos `data-encoding` is a combinator library for defining octez encodings.
Kaitai struct language is a formal description language for describing existing
binary encoded data. Given a valid kaitai struct description file (`.ksy`),
we can autogenerate parsers in many mainstream languages.
# `kaitai-of-data-encoding` library
To generate (`.ksy`) for a valid octez encoding, we have come up with
`kaitai-of-data-encoding` library, that translates `data-encoding` AST
to a valid Kaitai AST (`kaitai` library).
# Testing `lib-kaitai-of-data-encoding`
It is important to guarantee that `kaitai-of-data-encoding` generates
syntacticaly and semantically valid `.ksy` files.
Inside this folder we define expect test suite (`test_translation_of_*.ml` files)
that asserts expected translation.
TODO: https://gitlab.com/tezos/tezos/-/issues/6644
guarantee syntactic and semantic correctness of expected (`.ksy`) files
we are asserting against.
This diff is collapsed.
......@@ -11,6 +11,8 @@ lalrpop-util = "0.20.0"
checked = "0.5"
thiserror = "1.0"
logos = "0.13"
hex = "0.4"
tezos_crypto_rs = "0.5"
[[bin]]
name = "tzt_runner"
......
......@@ -6,6 +6,7 @@
/******************************************************************************/
pub mod comparable;
pub mod michelson_address;
pub mod michelson_list;
pub mod or;
pub mod parsed;
......@@ -13,6 +14,7 @@ pub mod typechecked;
use std::collections::BTreeMap;
pub use michelson_address::*;
pub use michelson_list::MichelsonList;
pub use or::Or;
pub use parsed::{ParsedInstruction, ParsedStage};
......@@ -32,46 +34,19 @@ pub enum Type {
Operation,
Map(Box<(Type, Type)>),
Or(Box<(Type, Type)>),
Contract(Box<Type>),
Address,
}
impl Type {
pub fn is_comparable(&self) -> bool {
use Type::*;
match self {
List(..) | Map(..) => false,
Operation => false,
Nat | Int | Bool | Mutez | String | Unit => true,
Pair(p) | Or(p) => p.0.is_comparable() && p.1.is_comparable(),
Option(x) => x.is_comparable(),
}
}
pub fn is_packable(&self) -> bool {
use Type::*;
match self {
Operation => false,
Nat | Int | Bool | Mutez | String | Unit => true,
Pair(p) | Or(p) => p.0.is_packable() && p.1.is_packable(),
Option(x) | List(x) => x.is_packable(),
Map(m) => m.1.is_packable(),
}
}
/// Returns abstract size of the type representation. Used for gas cost
/// estimation.
pub fn size_for_gas(&self) -> usize {
use Type::*;
match self {
Type::Nat => 1,
Type::Int => 1,
Type::Bool => 1,
Type::Mutez => 1,
Type::String => 1,
Type::Unit => 1,
Type::Operation => 1,
Type::Pair(p) | Type::Or(p) => 1 + p.0.size_for_gas() + p.1.size_for_gas(),
Type::Option(x) => 1 + x.size_for_gas(),
Type::List(x) => 1 + x.size_for_gas(),
Type::Map(m) => 1 + m.0.size_for_gas() + m.1.size_for_gas(),
Nat | Int | Bool | Mutez | String | Unit | Operation | Address => 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(),
}
}
......@@ -94,6 +69,10 @@ impl Type {
pub fn new_or(l: Self, r: Self) -> Self {
Self::Or(Box::new((l, r)))
}
pub fn new_contract(ty: Self) -> Self {
Self::Contract(Box::new(ty))
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
......@@ -107,6 +86,7 @@ pub enum Value {
Seq(Vec<Value>),
Elt(Box<(Value, Value)>),
Or(Box<Or<Value, Value>>),
Bytes(Vec<u8>),
}
impl Value {
......@@ -151,6 +131,7 @@ valuefrom! {
<> bool, Value::Boolean;
<> String, Value::String;
<> (), |_| Value::Unit;
<> Vec<u8>, Value::Bytes;
<L, R> (L, R), |(l, r): (L, R)| Value::new_pair(l.into(), r.into());
<L, R> Elt<L, R>, |Elt(l, r): Elt<L, R>| Value::new_elt(l.into(), r.into());
<T> Option<T>, |x: Option<T>| Value::new_option(x.map(Into::into));
......@@ -177,6 +158,7 @@ pub enum TypedValue {
List(MichelsonList<TypedValue>),
Map(BTreeMap<TypedValue, TypedValue>),
Or(Box<Or<TypedValue, TypedValue>>),
Address(Address),
}
pub fn typed_value_to_value_optimized(tv: TypedValue) -> Value {
......@@ -210,6 +192,7 @@ pub fn typed_value_to_value_optimized(tv: TypedValue) -> Value {
TV::Option(None) => V::Option(None),
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()),
}
}
......
......@@ -13,6 +13,7 @@ impl PartialOrd for TypedValue {
(Pair(l), Pair(r)) => l.partial_cmp(r),
(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),
_ => None,
}
}
......@@ -91,6 +92,46 @@ mod tests {
assert_eq!(Bool(true).partial_cmp(&Int(5)), None);
}
#[test]
fn compare_addrs() {
// ordering was verified against octez-client, see script below
let ordered_addrs = [
"tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw",
"tz1SNL5w4RFRbCWRMB4yDWvoRQrPQxZmNzeQ",
"tz1V8fDHpHzN8RrZqiYCHaJM9EocsYZch5Cy",
"tz1WPGZjP9eHGqD9DkiRJ1xGRU1wEMY19AAF",
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%bar",
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%defauls",
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j",
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%defaulu",
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%foo",
"tz1hHGTh6Yk4k7d2PiTcBUeMvw6fJCFikedv",
"tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%bar",
"tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH",
"tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%foo",
"tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%bar",
"tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r",
"tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%foo",
"tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%bar",
"tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN",
"tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%foo",
"KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%bar",
"KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye",
"KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%foo",
"sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%bar",
"sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf",
"sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%foo",
]
.map(|x| TypedValue::Address(crate::ast::Address::from_base58_check(x).unwrap()));
for (i, addr_i) in ordered_addrs.iter().enumerate() {
for (j, addr_j) in ordered_addrs.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() {
......@@ -99,3 +140,48 @@ mod tests {
let _ = Bool(true).cmp(&Int(5)); //panics
}
}
/*
Script to verify address ordering. Should print "with -1" for all checked address pairs.
```
#!/bin/bash
addrs=(
"tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw"
"tz1SNL5w4RFRbCWRMB4yDWvoRQrPQxZmNzeQ"
"tz1V8fDHpHzN8RrZqiYCHaJM9EocsYZch5Cy"
"tz1WPGZjP9eHGqD9DkiRJ1xGRU1wEMY19AAF"
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%bar"
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%defauls"
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j"
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%defaulu"
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%foo"
"tz1hHGTh6Yk4k7d2PiTcBUeMvw6fJCFikedv"
"tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%bar"
"tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH"
"tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%foo"
"tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%bar"
"tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r"
"tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%foo"
"tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%bar"
"tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN"
"tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%foo"
"KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%bar"
"KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye"
"KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%foo"
"sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%bar"
"sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf"
"sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%foo"
)
prev=""
for addr in "${addrs[@]}"; do
if [ -n "$prev" ]; then
echo $prev $addr
octez-client --mode mockup run script 'parameter address; storage address; code { UNPAIR; SWAP; COMPARE; FAILWITH }' on storage "\"$prev\"" and input "\"$addr\"" 2>&1 | grep '^with'
fi
prev="$addr"
done
```
*/
/******************************************************************************/
/* */
/* SPDX-License-Identifier: MIT */
/* Copyright (c) [2023] Serokell <hi@serokell.io> */
/* */
/******************************************************************************/
pub mod address_hash;
pub mod entrypoint;
pub mod error;
pub use self::address_hash::AddressHash;
pub use self::entrypoint::Entrypoint;
pub use self::error::AddressError;
use address_hash::check_size;
#[derive(Debug, Clone, Eq, PartialOrd, Ord, PartialEq)]
pub struct Address {
pub hash: AddressHash,
pub entrypoint: Entrypoint,
}
impl Address {
pub fn from_base58_check(data: &str) -> Result<Self, AddressError> {
let (hash, ep) = if let Some(ep_sep_pos) = data.find('%') {
(&data[..ep_sep_pos], &data[ep_sep_pos + 1..])
} else {
(data, "")
};
Ok(Address {
hash: AddressHash::from_base58_check(hash)?,
entrypoint: Entrypoint::try_from(ep)?,
})
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, AddressError> {
check_size(bytes, AddressHash::BYTE_SIZE, "bytes")?;
let (hash, ep) = bytes.split_at(AddressHash::BYTE_SIZE);
Ok(Address {
hash: AddressHash::from_bytes(hash)?,
entrypoint: Entrypoint::try_from(ep)?,
})
}
pub fn is_default_ep(&self) -> bool {
self.entrypoint.is_default()
}
pub fn to_bytes(&self, out: &mut Vec<u8>) {
self.hash.to_bytes(out);
if !self.is_default_ep() {
out.extend_from_slice(self.entrypoint.as_bytes())
}
}
pub fn to_bytes_vec(&self) -> Vec<u8> {
let mut out = Vec::new();
self.to_bytes(&mut out);
out
}
pub fn to_base58_check(&self) -> String {
if self.is_default_ep() {
self.hash.to_base58_check()
} else {
format!(
"{}%{}",
self.hash.to_base58_check(),
self.entrypoint.as_str()
)
}
}
}
impl TryFrom<&[u8]> for Address {
type Error = AddressError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
Self::from_bytes(value)
}
}
impl TryFrom<&str> for Address {
type Error = AddressError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Self::from_base58_check(value)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_base58_to_bin() {
// address with explicit, but empty, entrypoint
assert_eq!(
Address::from_base58_check("tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw%")
.unwrap()
.to_bytes_vec(),
hex::decode("00002422090f872dfd3a39471bb23f180e6dfed030f3").unwrap(),
);
// address with explicit default entrypoint
assert_eq!(
Address::from_base58_check("tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw%default")
.unwrap()
.to_bytes_vec(),
hex::decode("00002422090f872dfd3a39471bb23f180e6dfed030f3").unwrap(),
);
for (b58, hex) in FIXTURES {
assert_eq!(
Address::from_base58_check(b58).unwrap().to_bytes_vec(),
hex::decode(hex).unwrap(),
);
}
}
#[test]
fn test_bin_to_base58() {
// explicit default entrypoint is apparently forbidden in binary encoding
assert!(matches!(
Address::from_bytes(
&hex::decode("00007b09f782e0bcd67739510afa819d85976119d5ef64656661756c74").unwrap()
),
Err(AddressError::WrongFormat(_)),
));
// unknown implicit tag
assert_eq!(
dbg!(Address::from_bytes(
&hex::decode("00ff7b09f782e0bcd67739510afa819d85976119d5ef").unwrap()
)),
Err(AddressError::UnknownPrefix("0x00ff".to_owned())),
);
// unknown tag
assert_eq!(
Address::from_bytes(
&hex::decode("ffff7b09f782e0bcd67739510afa819d85976119d5ef").unwrap()
),
Err(AddressError::UnknownPrefix("0xff".to_owned())),
);
for (b58, hex) in FIXTURES {
assert_eq!(
Address::from_bytes(&hex::decode(hex).unwrap())
.unwrap()
.to_base58_check(),
b58,
);
}
}
// binary representation produced by running
//
// `octez-client --mode mockup run script 'parameter address; storage unit;
// code { CAR; FAILWITH }' on storage Unit and input "\"$addr\""`
const FIXTURES: [(&str, &str); 25] = [
(
"tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw",
"00002422090f872dfd3a39471bb23f180e6dfed030f3",
),
(
"tz1SNL5w4RFRbCWRMB4yDWvoRQrPQxZmNzeQ",
"000049d0be8c2987e04e080f4d73cbe24d8bf83997e2",
),
(
"tz1V8fDHpHzN8RrZqiYCHaJM9EocsYZch5Cy",
"0000682343b6fe7589573e11db2b87fd206b936e2a79",
),
(
"tz1WPGZjP9eHGqD9DkiRJ1xGRU1wEMY19AAF",
"000075deb97789e2429f2b9bb5dba1b1e4a061e832a3",
),
(
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%bar",
"00007b09f782e0bcd67739510afa819d85976119d5ef626172",
),
(
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%defauls",
"00007b09f782e0bcd67739510afa819d85976119d5ef64656661756c73",
),
(
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j",
"00007b09f782e0bcd67739510afa819d85976119d5ef",
),
(
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%defaulu",
"00007b09f782e0bcd67739510afa819d85976119d5ef64656661756c75",
),
(
"tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%foo",
"00007b09f782e0bcd67739510afa819d85976119d5ef666f6f",
),
(
"tz1hHGTh6Yk4k7d2PiTcBUeMvw6fJCFikedv",
"0000ed6586813c9085c8b6252ec3a654ee0e36a0f0e2",
),
(
"tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%bar",
"00010a053e3d8b622a993d3182e3f6cc5638ff5f12fe626172",
),
(
"tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH",
"00010a053e3d8b622a993d3182e3f6cc5638ff5f12fe",
),
(
"tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%foo",
"00010a053e3d8b622a993d3182e3f6cc5638ff5f12fe666f6f",
),
(
"tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%bar",
"00025cfa532f50de3e12befc0ad21603835dd7698d35626172",
),
(
"tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r",
"00025cfa532f50de3e12befc0ad21603835dd7698d35",
),
(
"tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%foo",
"00025cfa532f50de3e12befc0ad21603835dd7698d35666f6f",
),
(
"tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%bar",
"00036342f30484dd46b6074373aa6ddca9dfb70083d6626172",
),
(
"tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN",
"00036342f30484dd46b6074373aa6ddca9dfb70083d6",
),
(
"tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%foo",
"00036342f30484dd46b6074373aa6ddca9dfb70083d6666f6f",
),
(
"KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%bar",
"011f2d825fdd9da219235510335e558520235f4f5400626172",
),
(
"KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye",
"011f2d825fdd9da219235510335e558520235f4f5400",
),
(
"KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%foo",
"011f2d825fdd9da219235510335e558520235f4f5400666f6f",
),
(
"sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%bar",
"03d601f22256d2ad1faec0c64374e527c6e62f2e5a00626172",
),
(
"sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf",
"03d601f22256d2ad1faec0c64374e527c6e62f2e5a00",
),
(
"sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%foo",
"03d601f22256d2ad1faec0c64374e527c6e62f2e5a00666f6f",
),
];
}
/******************************************************************************/
/* */
/* SPDX-License-Identifier: MIT */
/* Copyright (c) [2023] Serokell <hi@serokell.io> */
/* */
/******************************************************************************/
use super::AddressError;
use tezos_crypto_rs::hash::{
ContractKt1Hash, ContractTz1Hash, ContractTz2Hash, ContractTz3Hash, ContractTz4Hash, Hash,
HashTrait, SmartRollupHash,
};
macro_rules! address_hash_type_and_impls {
($($con:ident($ty:ident)),* $(,)*) => {
#[derive(Debug, Clone, Eq, PartialOrd, Ord, PartialEq)]
pub enum AddressHash {
$($con($ty)),*
}
$(impl From<$ty> for AddressHash {
fn from(value: $ty) -> Self {
AddressHash::$con(value)
}
})*
impl AsRef<[u8]> for AddressHash {
fn as_ref(&self) -> &[u8] {
match self {
$(AddressHash::$con($ty(h)))|* => h,
}
}
}
impl From<AddressHash> for Vec<u8> {
fn from(value: AddressHash) -> Self {
match value {
$(AddressHash::$con($ty(h)))|* => h,
}
}
}
impl AddressHash {
pub fn to_base58_check(&self) -> String {
match self {
$(AddressHash::$con(h) => h.to_base58_check()),*
}
}
}
};
}
address_hash_type_and_impls! {
Tz1(ContractTz1Hash),
Tz2(ContractTz2Hash),
Tz3(ContractTz3Hash),
Tz4(ContractTz4Hash),
Kt1(ContractKt1Hash),
Sr1(SmartRollupHash),
}
impl TryFrom<&[u8]> for AddressHash {
type Error = AddressError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
Self::from_bytes(value)
}
}
impl TryFrom<&str> for AddressHash {
type Error = AddressError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Self::from_base58_check(value)
}
}
pub(super) fn check_size(data: &[u8], min_size: usize, name: &str) -> Result<(), AddressError> {
let size = data.len();
if size < min_size {
Err(AddressError::WrongFormat(format!(
"address must be at least {min_size} {name} long, but it is {size} {name} long"
)))
} else {
Ok(())
}
}
const TAG_IMPLICIT: u8 = 0;
const TAG_KT1: u8 = 1;
const TAG_SR1: u8 = 3;
const TAG_TZ1: u8 = 0;
const TAG_TZ2: u8 = 1;
const TAG_TZ3: u8 = 2;
const TAG_TZ4: u8 = 3;
const PADDING_IMPLICIT: &[u8] = &[];
const PADDING_SMART: &[u8] = &[0];
impl AddressHash {
// all address hashes are 20 bytes in length
pub const HASH_SIZE: usize = 20;
// +2 for tags: implicit addresses use 2-byte, and KT1/sr1 add zero-byte
// padding to the end
pub const BYTE_SIZE: usize = Self::HASH_SIZE + 2;
pub const BASE58_SIZE: usize = 36;
pub fn from_base58_check(data: &str) -> Result<Self, AddressError> {
use AddressHash::*;
check_size(data.as_bytes(), Self::BASE58_SIZE, "characters")?;
Ok(match &data[0..3] {
"KT1" => Kt1(HashTrait::from_b58check(data)?),
"sr1" => Sr1(HashTrait::from_b58check(data)?),
"tz1" => Tz1(HashTrait::from_b58check(data)?),
"tz2" => Tz2(HashTrait::from_b58check(data)?),
"tz3" => Tz3(HashTrait::from_b58check(data)?),
"tz4" => Tz4(HashTrait::from_b58check(data)?),
s => return Err(AddressError::UnknownPrefix(s.to_owned())),
})
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, AddressError> {
use AddressHash::*;
check_size(bytes, Self::BYTE_SIZE, "bytes")?;
let validate_padding_byte = || match bytes.last().unwrap() {
0 => Ok(()),
b => Err(AddressError::WrongFormat(format!(
"address must be padded with byte 0x00, but it was padded with 0x{}",
hex::encode([*b])
))),
};
Ok(match bytes[0] {
// implicit addresses
TAG_IMPLICIT => match bytes[1] {
TAG_TZ1 => Tz1(HashTrait::try_from_bytes(&bytes[2..])?),
TAG_TZ2 => Tz2(HashTrait::try_from_bytes(&bytes[2..])?),
TAG_TZ3 => Tz3(HashTrait::try_from_bytes(&bytes[2..])?),
TAG_TZ4 => Tz4(HashTrait::try_from_bytes(&bytes[2..])?),
_ => {
return Err(AddressError::UnknownPrefix(format!(
"0x{}",
hex::encode(&bytes[..2])
)))
}
},
TAG_KT1 => {
validate_padding_byte()?;
Kt1(HashTrait::try_from_bytes(&bytes[1..bytes.len() - 1])?)
}
// 2 is txr1 addresses, which are deprecated
TAG_SR1 => {
validate_padding_byte()?;
Sr1(HashTrait::try_from_bytes(&bytes[1..bytes.len() - 1])?)
}
_ => {
return Err(AddressError::UnknownPrefix(format!(
"0x{}",
hex::encode(&bytes[..1])
)))
}
})
}
pub fn to_bytes(&self, out: &mut Vec<u8>) {
use AddressHash::*;
fn go(out: &mut Vec<u8>, tag: &[u8], hash: impl AsRef<Hash>, sep: &[u8]) {
out.extend_from_slice(tag);
out.extend_from_slice(hash.as_ref());
out.extend_from_slice(sep);
}
match self {
Tz1(hash) => go(out, &[TAG_IMPLICIT, TAG_TZ1], hash, PADDING_IMPLICIT),
Tz2(hash) => go(out, &[TAG_IMPLICIT, TAG_TZ2], hash, PADDING_IMPLICIT),
Tz3(hash) => go(out, &[TAG_IMPLICIT, TAG_TZ3], hash, PADDING_IMPLICIT),
Tz4(hash) => go(out, &[TAG_IMPLICIT, TAG_TZ4], hash, PADDING_IMPLICIT),
Kt1(hash) => go(out, &[TAG_KT1], hash, PADDING_SMART),
Sr1(hash) => go(out, &[TAG_SR1], hash, PADDING_SMART),
}
}
pub fn to_bytes_vec(&self) -> Vec<u8> {
let mut out = Vec::new();
self.to_bytes(&mut out);
out
}
}
/******************************************************************************/
/* */
/* SPDX-License-Identifier: MIT */
/* Copyright (c) [2023] Serokell <hi@serokell.io> */
/* */
/******************************************************************************/
use super::AddressError;
#[derive(Debug, Clone, Eq, PartialOrd, Ord, PartialEq)]
pub struct Entrypoint(String);
// NB: default entrypoint is represented as literal "default", because it
// affects comparision for addresses.
const DEFAULT_EP_NAME: &str = "default";
const MAX_EP_LEN: usize = 31;
impl Default for Entrypoint {
fn default() -> Self {
Entrypoint(DEFAULT_EP_NAME.to_owned())
}
}
impl Entrypoint {
pub fn is_default(&self) -> bool {
self.0 == DEFAULT_EP_NAME
}
pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl TryFrom<&str> for Entrypoint {
type Error = AddressError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
Entrypoint::try_from(s.to_owned())
}
}
impl TryFrom<String> for Entrypoint {
type Error = AddressError;
fn try_from(s: String) -> Result<Self, Self::Error> {
if s.is_empty() {
Ok(Entrypoint::default())
} else {
check_ep_name(s.as_bytes())?;
Ok(Entrypoint(s))
}
}
}
impl TryFrom<&[u8]> for Entrypoint {
type Error = AddressError;
fn try_from(s: &[u8]) -> Result<Self, AddressError> {
if s.is_empty() {
Ok(Entrypoint::default())
} else {
check_ep_name(s)?;
// SAFETY: we just checked all bytes are valid ASCII
let ep = Entrypoint(unsafe { std::str::from_utf8_unchecked(s).to_owned() });
if ep.is_default() {
return Err(AddressError::WrongFormat(
"explicit default entrypoint is forbidden in binary encoding".to_owned(),
));
}
Ok(ep)
}
}
}
fn check_ep_name(ep: &[u8]) -> Result<(), AddressError> {
if ep.len() > MAX_EP_LEN {
return Err(AddressError::WrongFormat(format!(
"entrypoint name must be at most {} characters long, but it is {} characters long",
MAX_EP_LEN,
ep.len()
)));
}
let mut first_char = true;
for c in ep {
// direct encoding of the regex defined in
// https://tezos.gitlab.io/alpha/michelson.html#syntax
match c {
b'_' | b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' => Ok(()),
b'.' | b'%' | b'@' if !first_char => Ok(()),
c => Err(AddressError::WrongFormat(format!(
"forbidden byte in entrypoint name: {}",
hex::encode([*c])
))),
}?;
first_char = false;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
assert_eq!(
Entrypoint::default(),
Entrypoint(DEFAULT_EP_NAME.to_owned())
)
}
#[test]
fn test_from_str() {
assert_eq!(Entrypoint::try_from(""), Ok(Entrypoint::default()));
assert_eq!(Entrypoint::try_from("default"), Ok(Entrypoint::default()));
assert_eq!(
Entrypoint::try_from("foo"),
Ok(Entrypoint("foo".to_owned()))
);
assert_eq!(
Entrypoint::try_from("foo.bar"),
Ok(Entrypoint("foo.bar".to_owned()))
);
assert_eq!(
Entrypoint::try_from("q".repeat(31).as_str()),
Ok(Entrypoint("q".repeat(31)))
);
// too long
assert!(matches!(
Entrypoint::try_from("q".repeat(32).as_str()),
Err(AddressError::WrongFormat(_))
));
// unicode
assert!(matches!(
Entrypoint::try_from("संसर"),
Err(AddressError::WrongFormat(_))
));
// forbidden character
assert!(matches!(
Entrypoint::try_from("!"),
Err(AddressError::WrongFormat(_))
));
}
#[test]
fn test_from_string() {
// most of this is tested in test_from_str, as one delegates to the
// other, so only the basic tests here
assert_eq!(
Entrypoint::try_from("".to_owned()),
Ok(Entrypoint::default())
);
assert_eq!(
Entrypoint::try_from("default".to_owned()),
Ok(Entrypoint::default())
);
assert_eq!(
Entrypoint::try_from("foo".to_owned()),
Ok(Entrypoint("foo".to_owned()))
);
}
#[test]
fn test_from_bytes() {
// explicit default entrypoints are forbidden in binary
assert!(matches!(
Entrypoint::try_from(b"default" as &[u8]),
Err(AddressError::WrongFormat(_))
));
assert_eq!(
Entrypoint::try_from(b"" as &[u8]),
Ok(Entrypoint::default())
);
assert_eq!(
Entrypoint::try_from(b"foo" as &[u8]),
Ok(Entrypoint("foo".to_owned()))
);
assert_eq!(
Entrypoint::try_from(b"foo.bar" as &[u8]),
Ok(Entrypoint("foo.bar".to_owned()))
);
assert_eq!(
Entrypoint::try_from("q".repeat(31).as_bytes()),
Ok(Entrypoint("q".repeat(31)))
);
// too long
assert!(matches!(
Entrypoint::try_from("q".repeat(32).as_bytes()),
Err(AddressError::WrongFormat(_))
));
// unicode
assert!(matches!(
Entrypoint::try_from("संसर".as_bytes()),
Err(AddressError::WrongFormat(_))
));
// forbidden character
assert!(matches!(
Entrypoint::try_from(b"!" as &[u8]),
Err(AddressError::WrongFormat(_))
));
}
#[test]
fn test_check_ep_name() {
assert_eq!(check_ep_name(&[b'q'; 31]), Ok(()));
// more than 31 bytes
assert!(matches!(
check_ep_name(&[b'q'; 32]),
Err(AddressError::WrongFormat(_))
));
// '.', '%', '@' are allowed
for i in ['.', '%', '@'] {
assert_eq!(check_ep_name(format!("foo{i}bar").as_bytes()), Ok(()));
// but not as the first character
assert!(matches!(
check_ep_name(format!("{i}bar").as_bytes()),
Err(AddressError::WrongFormat(_))
));
}
// ! is forbidden
assert!(matches!(
check_ep_name(b"foo!"),
Err(AddressError::WrongFormat(_))
));
// unicode is forbidden
assert!(matches!(
check_ep_name("नमस्ते".as_bytes()),
Err(AddressError::WrongFormat(_))
));
}
}
/******************************************************************************/
/* */
/* SPDX-License-Identifier: MIT */
/* Copyright (c) [2023] Serokell <hi@serokell.io> */
/* */
/******************************************************************************/
use tezos_crypto_rs::base58::FromBase58CheckError;
use tezos_crypto_rs::hash::FromBytesError;
#[derive(Debug, PartialEq, Eq, Clone, thiserror::Error)]
pub enum AddressError {
#[error("unknown address prefix: {0}")]
UnknownPrefix(String),
#[error("wrong address format: {0}")]
WrongFormat(String),
}
impl From<FromBase58CheckError> for AddressError {
fn from(value: FromBase58CheckError) -> Self {
Self::WrongFormat(value.to_string())
}
}
impl From<FromBytesError> for AddressError {
fn from(value: FromBytesError) -> Self {
Self::WrongFormat(value.to_string())
}
}
......@@ -92,6 +92,21 @@ pub mod tc_cost {
pub const VALUE_STEP: u32 = 100;
// Corresponds to cost_PARSE_TYPE1 in the Tezos protocol.
pub const VERIFY_TYPE_STEP: u32 = 60;
// Taken to be the same as VERIFY_TYPE_STEP, but that's a guess
pub const TYPE_PROP_STEP: u32 = 60;
// corresponds to cost_B58CHECK_ENCODING_PUBLIC_KEY_HASH_bls in the
// protocol. the protocol computes cost as
// `max(bls,ed25519,p256,secp256k1)`, which happens to be `bls`
pub const KEY_HASH_READABLE: u32 = 3200;
// corresponds to cost_ENCODING_PUBLIC_KEY_HASH_bls in the
// protocol. the protocol computes cost as
// `max(bls,ed25519,p256,secp256k1)`, which happens to be `bls`
pub const KEY_HASH_OPTIMIZED: u32 = 80;
fn variadic(depth: u16) -> Result<u32, OutOfGas> {
let depth = Checked::from(depth as u32);
(depth * 50).as_gas_cost()
......@@ -221,6 +236,7 @@ pub mod interpret_cost {
(c + compare(&l.0, &r.0)? + compare(&l.1, &r.1)?).as_gas_cost()
};
let cmp_option = Checked::from(10u32);
const ADDRESS_SIZE: usize = 20 + 31; // hash size + max entrypoint size
Ok(match (v1, v2) {
(V::Nat(l), V::Nat(r)) => {
// NB: eventually when using BigInts, use BigInt::bits() &c
......@@ -242,6 +258,7 @@ pub mod interpret_cost {
(Some(l), Some(r)) => cmp_option + compare(l, r)?,
}
.as_gas_cost()?,
(V::Address(..), V::Address(..)) => cmp_bytes(ADDRESS_SIZE, ADDRESS_SIZE)?,
_ => unreachable!("Comparison of incomparable values"),
})
}
......
......@@ -29,7 +29,6 @@ pub enum ContractInterpretError {
InterpretError(#[from] crate::interpreter::InterpretError),
}
#[allow(dead_code)]
impl ContractScript<TypecheckedStage> {
/// Interpret a typechecked contract script using the provided parameter and
/// storage. Parameter and storage are given as untyped `Value`s, as this
......@@ -56,8 +55,20 @@ impl ContractScript<TypecheckedStage> {
}
}
#[allow(dead_code)]
pub fn interpret(
impl TypecheckedInstruction {
/// Interpret the instruction with the given `Ctx` and input stack. Note the
/// interpreter assumes the instruction can execute on the provided stack,
/// otherwise this function will panic.
///
/// # Panics
///
/// When the instruction can't be executed on the provided stack.
pub fn interpret(&self, ctx: &mut Ctx, stack: &mut IStack) -> Result<(), InterpretError> {
interpret_one(self, ctx, stack)
}
}
fn interpret(
ast: &TypecheckedAST,
ctx: &mut Ctx,
stack: &mut IStack,
......@@ -69,12 +80,6 @@ pub fn interpret(
Ok(())
}
impl TypecheckedInstruction {
fn interpret(&self, ctx: &mut Ctx, stack: &mut IStack) -> Result<(), InterpretError> {
interpret_one(self, ctx, stack)
}
}
#[track_caller]
fn unreachable_state() -> ! {
// If the typechecking of the program being interpreted was successful and if this is reached
......
......@@ -94,6 +94,8 @@ defprim! {
Left,
Right,
IF_LEFT,
contract,
address,
}
defprim! {
......@@ -130,6 +132,9 @@ pub enum Tok {
#[regex(r#""(\\.|[^\\"])*""#, lex_string)]
String(String),
#[regex(r#"0x[0-9a-fA-F]*"#, lex_bytes)]
Bytes(Vec<u8>),
// regex as per https://tezos.gitlab.io/active/michelson.html#syntax
#[regex(r"@%|@%%|%@|[@:%][_0-9a-zA-Z][_0-9a-zA-Z\.%@]*")]
Annotation,
......@@ -148,12 +153,13 @@ pub enum Tok {
impl std::fmt::Display for Tok {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
match self {
Tok::Prim(PrimWithTzt::Prim(p)) => p.fmt(f),
Tok::Prim(PrimWithTzt::TztPrim(p)) => p.fmt(f),
Tok::Prim(PrimWithTzt::Underscore) => write!(f, "_"),
Tok::Number(n) => n.fmt(f),
Tok::String(s) => s.fmt(f),
Tok::Bytes(bs) => write!(f, "0x{}", hex::encode(bs)),
Tok::Annotation => write!(f, "<ann>"),
Tok::LParen => write!(f, "("),
Tok::RParen => write!(f, ")"),
......@@ -164,7 +170,7 @@ impl std::fmt::Display for Tok {
}
}
#[derive(Debug, PartialEq, Eq, Clone, thiserror::Error)]
#[derive(Debug, PartialEq, Clone, thiserror::Error)]
pub enum LexerError {
#[error("unknown token")]
UnknownToken,
......@@ -176,6 +182,8 @@ pub enum LexerError {
UndefinedEscape(char),
#[error(transparent)]
PrimError(#[from] PrimError),
#[error("invalid hex sequence: {0}")]
InvalidHex(#[from] hex::FromHexError),
}
impl Default for LexerError {
......@@ -244,6 +252,12 @@ fn lex_string(lex: &mut Lexer) -> Result<String, LexerError> {
Ok(res)
}
/// Takes a lexed slice of hexadecimal digits prefixed by `0x`, removes the
/// prefix and converts the digits pairwise to `u8`.
fn lex_bytes(lex: &mut Lexer) -> Result<Vec<u8>, LexerError> {
Ok(hex::decode(&lex.slice()[2..])?)
}
#[cfg(test)]
mod tests {
use super::*;
......@@ -288,4 +302,23 @@ mod tests {
"unknown primitive: foo"
)
}
#[test]
fn lex_bytes_test() {
#[track_caller]
fn assert_parse<const N: usize>(s: &str, e: Result<[u8; N], &str>) {
assert_eq!(
Tok::lexer(s).map(|i| i.map_err(|x| x.to_string())).last(),
Some(e.map(|v| Tok::Bytes(v.to_vec())).map_err(|e| e.to_owned()))
)
}
assert_parse("0x01", Ok([0x01]));
assert_parse("0x010203", Ok([0x01, 0x02, 0x03]));
assert_parse("0xfffe", Ok([0xff, 0xfe]));
assert_parse("0x0000", Ok([0x00, 0x00]));
assert_parse("0xabcd", Ok([0xab, 0xcd]));
assert_parse("0x", Ok([]));
assert_parse::<0>("0x1", Err("invalid hex sequence: Odd number of digits"));
assert_parse::<0>("0xzz", Err("unknown primitive: zz"));
}
}
......@@ -39,10 +39,11 @@ mod tests {
#[test]
fn interpret_test_expect_success() {
let ast = parser::parse(FIBONACCI_SRC).unwrap();
let ast =
typechecker::typecheck(ast, &mut Ctx::default(), &mut tc_stk![Type::Nat]).unwrap();
let ast = ast
.typecheck(&mut Ctx::default(), &mut tc_stk![Type::Nat])
.unwrap();
let mut istack = stk![TypedValue::Nat(10)];
assert!(interpreter::interpret(&ast, &mut Ctx::default(), &mut istack).is_ok());
assert!(ast.interpret(&mut Ctx::default(), &mut istack).is_ok());
assert!(istack.len() == 1 && istack[0] == TypedValue::Int(55));
}
......@@ -50,21 +51,22 @@ mod tests {
fn interpret_mutez_push_add() {
let ast = parser::parse("{ PUSH mutez 100; PUSH mutez 500; ADD }").unwrap();
let mut ctx = Ctx::default();
let ast = typechecker::typecheck(ast, &mut ctx, &mut tc_stk![]).unwrap();
let ast = ast.typecheck(&mut ctx, &mut tc_stk![]).unwrap();
let mut istack = stk![];
assert!(interpreter::interpret(&ast, &mut ctx, &mut istack).is_ok());
assert!(ast.interpret(&mut ctx, &mut istack).is_ok());
assert_eq!(istack, stk![TypedValue::Mutez(600)]);
}
#[test]
fn interpret_test_gas_consumption() {
let ast = parser::parse(FIBONACCI_SRC).unwrap();
let ast =
typechecker::typecheck(ast, &mut Ctx::default(), &mut tc_stk![Type::Nat]).unwrap();
let ast = ast
.typecheck(&mut Ctx::default(), &mut tc_stk![Type::Nat])
.unwrap();
let mut istack = stk![TypedValue::Nat(5)];
let mut ctx = Ctx::default();
report_gas(&mut ctx, |ctx| {
assert!(interpreter::interpret(&ast, ctx, &mut istack).is_ok());
assert!(ast.interpret(ctx, &mut istack).is_ok());
});
assert_eq!(ctx.gas.milligas(), Gas::default().milligas() - 1359);
}
......@@ -72,15 +74,16 @@ mod tests {
#[test]
fn interpret_test_gas_out_of_gas() {
let ast = parser::parse(FIBONACCI_SRC).unwrap();
let ast =
typechecker::typecheck(ast, &mut Ctx::default(), &mut tc_stk![Type::Nat]).unwrap();
let ast = ast
.typecheck(&mut Ctx::default(), &mut tc_stk![Type::Nat])
.unwrap();
let mut istack = stk![TypedValue::Nat(5)];
let mut ctx = Ctx {
gas: Gas::new(1),
..Ctx::default()
};
assert_eq!(
interpreter::interpret(&ast, &mut ctx, &mut istack),
ast.interpret(&mut ctx, &mut istack),
Err(interpreter::InterpretError::OutOfGas(crate::gas::OutOfGas)),
);
}
......@@ -89,7 +92,7 @@ mod tests {
fn typecheck_test_expect_success() {
let ast = parser::parse(FIBONACCI_SRC).unwrap();
let mut stack = tc_stk![Type::Nat];
assert!(typechecker::typecheck(ast, &mut Ctx::default(), &mut stack).is_ok());
assert!(ast.typecheck(&mut Ctx::default(), &mut stack).is_ok());
assert_eq!(stack, tc_stk![Type::Int])
}
......@@ -98,10 +101,11 @@ mod tests {
let ast = parser::parse(FIBONACCI_SRC).unwrap();
let mut stack = tc_stk![Type::Nat];
let mut ctx = Ctx::default();
let start_milligas = ctx.gas.milligas();
report_gas(&mut ctx, |ctx| {
assert!(typechecker::typecheck(ast, ctx, &mut stack).is_ok());
assert!(ast.typecheck(ctx, &mut stack).is_ok());
});
assert_eq!(ctx.gas.milligas(), Gas::default().milligas() - 11460);
assert_eq!(start_milligas - ctx.gas.milligas(), 12680);
}
#[test]
......@@ -113,7 +117,7 @@ mod tests {
..Ctx::default()
};
assert_eq!(
typechecker::typecheck(ast, &mut ctx, &mut stack),
ast.typecheck(&mut ctx, &mut stack),
Err(typechecker::TcError::OutOfGas(crate::gas::OutOfGas))
);
}
......@@ -124,7 +128,7 @@ mod tests {
let ast = parser::parse(FIBONACCI_ILLTYPED_SRC).unwrap();
let mut stack = tc_stk![Type::Nat];
assert_eq!(
typechecker::typecheck(ast, &mut Ctx::default(), &mut stack),
ast.typecheck(&mut Ctx::default(), &mut stack),
Err(TcError::NoMatchingOverload {
instr: crate::lexer::Prim::DUP,
stack: stk![Type::Int, Type::Int, Type::Int],
......@@ -142,7 +146,7 @@ mod tests {
// use built in pretty printer to validate the expected AST.
assert_eq!(
ast,
vec![
Instruction::Seq(vec![
Int,
Push((Type::Int, Number(0))),
Dup(Some(2)),
......@@ -165,7 +169,7 @@ mod tests {
],
vec![Dip(None, vec![Drop(None)])],
),
]
])
);
}
......@@ -183,12 +187,9 @@ mod tests {
fn parser_test_dip_dup_drop_args() {
use Instruction::{Dip, Drop, Dup};
assert_eq!(parser::parse("{ DROP 1023 }"), Ok(vec![Drop(Some(1023))]));
assert_eq!(
parser::parse("{ DIP 1023 {} }"),
Ok(vec![Dip(Some(1023), vec![])])
);
assert_eq!(parser::parse("{ DUP 1023 }"), Ok(vec![Dup(Some(1023))]));
assert_eq!(parser::parse("DROP 1023"), Ok(Drop(Some(1023))));
assert_eq!(parser::parse("DIP 1023 {}"), Ok(Dip(Some(1023), vec![])));
assert_eq!(parser::parse("DUP 1023"), Ok(Dup(Some(1023))));
// failures
assert_eq!(
......
......@@ -11,7 +11,7 @@ use crate::syntax;
use lalrpop_util::ParseError;
use logos::Logos;
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
#[derive(Debug, PartialEq, thiserror::Error)]
pub enum ParserError {
#[error("expected a natural from 0 to 1023 inclusive, but got {0}")]
ExpectedU10(i128),
......@@ -23,12 +23,10 @@ pub enum ParserError {
DuplicateField(Prim),
}
#[allow(dead_code)]
pub fn parse(src: &str) -> Result<ParsedInstructionBlock, ParseError<usize, Tok, ParserError>> {
syntax::InstructionBlockParser::new().parse(spanned_lexer(src))
pub fn parse(src: &str) -> Result<ParsedInstruction, ParseError<usize, Tok, ParserError>> {
syntax::InstructionParser::new().parse(spanned_lexer(src))
}
#[allow(dead_code)]
pub fn parse_contract_script(
src: &str,
) -> Result<ContractScript<ParsedStage>, ParseError<usize, Tok, ParserError>> {
......@@ -101,36 +99,30 @@ mod tests {
#[test]
fn pair_type() {
assert_eq!(
parse("{ PUSH (pair int nat) Unit }").unwrap(),
vec![Instruction::Push((
Type::new_pair(Type::Int, Type::Nat),
Value::Unit
))]
parse("PUSH (pair int nat) Unit").unwrap(),
Instruction::Push((Type::new_pair(Type::Int, Type::Nat), Value::Unit))
);
assert_eq!(
parse("{ PUSH (pair int nat unit) Unit }").unwrap(),
vec![Instruction::Push((
parse("PUSH (pair int nat unit) Unit").unwrap(),
Instruction::Push((
Type::new_pair(Type::Int, Type::new_pair(Type::Nat, Type::Unit)),
Value::Unit
))]
))
);
assert_eq!(
parse("{ PUSH (pair (pair int nat) unit) Unit }").unwrap(),
vec![Instruction::Push((
parse("PUSH (pair (pair int nat) unit) Unit").unwrap(),
Instruction::Push((
Type::new_pair(Type::new_pair(Type::Int, Type::Nat), Type::Unit),
Value::Unit
))]
))
);
}
#[test]
fn or_type() {
assert_eq!(
parse("{ PUSH (or int nat) Unit }").unwrap(),
vec![Instruction::Push((
Type::new_or(Type::Int, Type::Nat),
Value::Unit
))]
parse("PUSH (or int nat) Unit").unwrap(),
Instruction::Push((Type::new_or(Type::Int, Type::Nat), Value::Unit))
);
// unlike for pairs, there's no linearized syntax for `or`
assert_eq!(
......@@ -144,31 +136,31 @@ mod tests {
#[test]
fn pair_value() {
assert_eq!(
parse("{ PUSH unit (Pair 3 4) }").unwrap(),
vec![Instruction::Push((
parse("PUSH unit (Pair 3 4)").unwrap(),
Instruction::Push((
Type::Unit,
Value::new_pair(Value::Number(3), Value::Number(4)),
))]
))
);
assert_eq!(
parse("{ PUSH unit (Pair 3 4 5) }").unwrap(),
vec![Instruction::Push((
parse("PUSH unit (Pair 3 4 5)").unwrap(),
Instruction::Push((
Type::Unit,
Value::new_pair(
Value::Number(3),
Value::new_pair(Value::Number(4), Value::Number(5)),
),
))]
))
);
assert_eq!(
parse("{ PUSH unit (Pair (Pair 3 4) 5) }").unwrap(),
vec![Instruction::Push((
parse("PUSH unit (Pair (Pair 3 4) 5)").unwrap(),
Instruction::Push((
Type::Unit,
Value::new_pair(
Value::new_pair(Value::Number(3), Value::Number(4)),
Value::Number(5),
),
))]
))
);
assert!(parse("{ PUSH pair unit unit Pair Unit Unit }")
.unwrap_err()
......@@ -183,19 +175,19 @@ mod tests {
#[test]
fn or_value() {
assert_eq!(
parse("{ PUSH (or int unit) (Left 3) }").unwrap(),
vec![Instruction::Push((
parse("PUSH (or int unit) (Left 3)").unwrap(),
Instruction::Push((
Type::new_or(Type::Int, Type::Unit),
Value::new_or(Or::Left(Value::Number(3))),
))]
))
);
}
#[test]
fn value_parens() {
assert_eq!(
parse("{ PUSH unit (Unit) }").unwrap(),
vec![Instruction::Push((Type::Unit, Value::Unit))]
parse("PUSH unit (Unit)").unwrap(),
Instruction::Push((Type::Unit, Value::Unit))
);
}
......@@ -239,12 +231,12 @@ mod tests {
use Type as T;
use Value as V;
assert_eq!(
parse("{PUSH @var :ty %field int 1}").unwrap(),
vec![Push((T::Int, V::Number(1)))],
parse("PUSH @var :ty %field int 1").unwrap(),
Push((T::Int, V::Number(1))),
);
assert_eq!(
parse("{CAR @var :ty %field :ty.2 @var.2 %field.2}").unwrap(),
vec![Car],
parse("CAR @var :ty %field :ty.2 @var.2 %field.2").unwrap(),
Car,
);
}
......@@ -317,4 +309,34 @@ mod tests {
Err(Err::NoField(code).into())
);
}
#[test]
// Test parsing of annotated contract type.
// Type contract is not pushable so this would be rejected
// at type-checking but this test only exercises the parser.
fn contract_ty_push() {
assert_eq!(
parse("PUSH (contract :ct %foo unit) Unit").unwrap(),
Instruction::Push((Type::new_contract(Type::Unit), Value::Unit))
);
}
#[test]
fn bytes_push() {
assert_eq!(
parse("PUSH unit 0xdeadf00d").unwrap(),
Instruction::Push((Type::Unit, Value::Bytes(vec![0xde, 0xad, 0xf0, 0x0d])))
);
}
#[test]
fn address_ty_push() {
assert_eq!(
parse("PUSH address \"tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw\"").unwrap(),
Instruction::Push((
Type::Address,
Value::String("tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw".to_owned())
))
);
}
}
......@@ -34,6 +34,7 @@ extern {
"amount" => Tok::Prim(TztPrim(TzP::amount)),
number => Tok::Number(<i128>),
string => Tok::String(<String>),
bytes => Tok::Bytes(<Vec<u8>>),
ann => Tok::Annotation,
"parameter" => Tok::Prim(PT::Prim(Prim::parameter)),
"storage" => Tok::Prim(PT::Prim(Prim::storage)),
......@@ -50,6 +51,8 @@ extern {
"list" => Tok::Prim(PT::Prim(Prim::list)),
"map" => Tok::Prim(PT::Prim(Prim::map)),
"or" => Tok::Prim(PT::Prim(Prim::or)),
"contract" => Tok::Prim(PT::Prim(Prim::contract)),
"address" => Tok::Prim(PT::Prim(Prim::address)),
"True" => Tok::Prim(PT::Prim(Prim::True)),
"False" => Tok::Prim(PT::Prim(Prim::False)),
"Unit" => Tok::Prim(PT::Prim(Prim::Unit)),
......@@ -107,6 +110,7 @@ atomic_type: Type = {
"string" => Type::String,
"unit" => Type::Unit,
"operation" => Type::Operation,
"address" => Type::Address,
}
pair_args: Type = {
......@@ -120,6 +124,7 @@ composite_type: Type = {
"list" anns <type_expr> => Type::new_list(<>),
"map" anns <type_expr> <type_expr> => Type::new_map(<>),
"or" anns <type_expr> <type_expr> => Type::new_or(<>),
"contract" anns <type_expr> => Type::new_contract(<>),
}
type_expr: Type = {
......@@ -137,7 +142,8 @@ boolean: bool = {
atomic_value: Value = {
<n:number> => Value::Number(n),
<b:boolean> => Value::Boolean(b),
<string> => Value::String(<>),
string => Value::String(<>),
bytes => Value::Bytes(<>),
"Unit" => Value::Unit,
"None" => Value::Option(None),
}
......@@ -232,7 +238,7 @@ instructionBlock: ParsedInstructionBlock = {
}
// synonym for consistent type naming
pub InstructionBlock = instructionBlock;
pub Instruction = instruction;
// synonym for consistent type naming
pub Type: Type = type_expr;
......@@ -278,7 +284,7 @@ mutezAmount : i64 =
use ErrorExpectation::*;
use InterpreterErrorExpectation::*;
tztEntity : TztEntity = {
"code" <ib:instructionBlock> => Code(ib),
"code" <code_content> => Code(<>),
"input" <s:tztStack> => Input(s),
"output" <s:tztStack> => Output(TztSuccess(s)),
"output" "(" "failed" <v:value_expr> ")" => Output(TztError(InterpreterError(FailedWith(v)))),
......